【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
上一篇文章谈到了汇编代码的生成,但是留了一个小尾巴,那就是汇编的优化。在实际操作中,优化主要分成两个部分。一个是中间代码的优化,比如a=4*5,一般生成中间代码的时候,编译器就帮你算成了a=20;另外一种就是汇编代码的优化,比如a=b/2,这个时候虽然是除法运算,但是编译器可能就用a=b>>1代替了a=b/2,因为对于cpu硬件来说,移位运算要比除法快得多。
今天讨论的汇编优化,其实也是众多优化方法中的一种,那就是store-load优化。假设有两条相连的指令,第一条是store [mem],ax,第二条是load ax,[mem],这个时候大家可以试想一下,如果store和load命令的register一样,mem变量一样,是不是这两条指令可以同时删除呢?当然,现实情况中一般用窥孔来查询,也就是说如果在一定范围内寻找到这样的指令,那么就做删除处理。不然,全局来查找,花费的时间也太多了。
首先,优化代码的操作可以放在生成汇编代码的函数里面,
public static String translate_code(String input)
{
String[] sub;
String str = "";
if(input == "")
{
return "";
}
sub = input.split("\n");
for(int i = 0; i < sub.length; i++)
{
str += translate_single_code(sub[i]);
}
str = optimise_assemble_code(str);
return str;
}
可以看到,相比较之前的translate_code函数,这里仅仅是多了一个optimise_assemble_code函数。同时,我们也注意到,优化会汇编代码的工作是等所有汇编代码都已经生成好之后,再开始的。
接下来,就需要进一步分析optimise_assemble_code,
public static String optimise_assemble_code(String input)
{
String [] sub;
String str = "";
if( input == "")
{
return "";
}
sub = input.split("\n");
for(int i = 0; i < sub.length; i += 1)
{
int j;
String [] word_i;
String [] word_j;
j = i + 1;
if(j < sub.length)
{
word_i = sub[i].split(" ");
word_j = sub[j].split(" ");
if(false == word_i[0].equals("store"))
{
str += sub[i] + "\n";
continue;
}
if( false == word_j[0].equals("load"))
{
str += sub[i] + "\n";
continue;
}
// check register and local mem
if(word_i[1].split(",")[0].equals(word_j[1].split(",")[1]) && word_i[1].split(",")[1].equals(word_j[1].split(",")[0]))
{
i += 1;
}
else
{
str += sub[i] + "\n";
}
}
else
{
str += sub[i] + "\n";
}
}
return str;
}
这段代码稍长,我们可以慢慢分析。首先判断input是否为空,如果为空,则退出。接下来就是利用\n将字符串切分成一行一行的汇编代码。切分好之后,就是一个循环操作。在循环体里面,依次分析相连的两条指令,即如果第一条指令不是store,拷贝并继续;如果第二条指令不是load指令,拷贝并继续;如果两者register和mem完全相同,跳过,反之则拷贝继续。另外就是,在循环体中,如果发现当前已经是最后一条指令,则无条件拷贝退出。
有了上面的操作,我们可以比较一下,同样的输入,优化前和优化后有什么区别。首先是优化前的输出打印,
C:\Users\feixiaoxing\Desktop\DIYCompiler\day10>java Parse 4/2/1
tmp2
tmp1
4
2
1
mov ax,4
mov bx,2
div ax, bx
store [tmp1],ax
load ax,[tmp1]
mov bx,1
div ax, bx
store [tmp2],ax
接下来是优化后的输出打印,还是4/2/1,
C:\Users\feixiaoxing\Desktop\DIYCompiler\day11>java Parse 4/2/1
tmp2
tmp1
4
2
1
mov ax,4
mov bx,2
div ax, bx
mov bx,1
div ax, bx
store [tmp2],ax
大家可以观察到,原来中间的store和load操作都被删除了。这其实就是一个冗余操作。此外,因为优化的过程中节省的操作都是内存的访问和读取,我们都知道cpu访问register的速度要比访问mem空间快的多,这也就是,优化后的代码相比较之前生成的汇编代码,要快得多,代码空间也能节省一部分。
最后,为了方便大家学习,贴出完整代码,当然也可以去上面的github链接下载。
options {
STATIC = false;
}
PARSER_BEGIN(Parse)
import java.io.*;
class node
{
public node left;
public node right;
public String node_type;
public String node_name;
public int depth;
node() {this.left = this.right = null;}
public void set_left_node(node left) { this.left = left;}
public node get_left_node() { return this.left;}
public void set_right_node(node right) { this.right = right;}
public node get_right_node() {return this.right;}
public void set_node_type(String node_type) {this.node_type = node_type;}
public String get_node_type() {return this.node_type;}
public void set_node_name(String node_name) {this.node_name = node_name;}
public String get_node_name() {return this.node_name;}
public void set_depth(int depth) {this.depth = depth;}
public int get_depth() {return this.depth;}
public int calculate_depth() { // node depth should be calculated before print it, so just calculate root node
int left_depth = 0;
int right_depth = 0;
int final_depth = 0;
if(get_left_node() == null && get_right_node() == null) {
set_depth(1);
return 1;
}
if(null != get_left_node()) {
left_depth = get_left_node().calculate_depth();
}
if(null != get_right_node()){
right_depth = get_right_node().calculate_depth();
}
final_depth = (left_depth > right_depth) ? (left_depth+1) :(right_depth +1);
set_depth(final_depth);
return final_depth;
}
public void print_node(int start_depth, int start_point) // add print node function
{
int i = 0;
for(i =0; i < (start_point - start_depth*5); i++){
System.out.print(" ");
}
if(get_node_type() != "value_node")
{
System.out.println(get_node_name());
}
else
{
System.out.println(((value_node)this).get_value());
}
if(get_left_node() != null) get_left_node().print_node(start_depth -1, start_point);
if(get_right_node() != null) get_right_node().print_node(start_depth -1, start_point);
}
}
class value_node extends node
{
public int value;
value_node() { set_node_type("value_node");}
public int get_value() { return this.value;}
public void set_value(int value) {this.value = value;}
}
class div_node extends node
{
div_node() { set_node_type("/");}
public int get_value() {
int left = 0, right = 0;
// get left node
if(get_left_node().get_node_type() == "/")
{
left = ((div_node)get_left_node()).get_value();
}
else
{
left = ((value_node)get_left_node()).get_value();
}
// get right node
if(get_right_node() == null)
{
return left;
}
else
{
right = ((value_node)get_right_node()).get_value();
return left/right;
}
}
// add semantic check
public int check_value() {
if(get_right_node() != null)
{
if( 0 == ((value_node)get_right_node()).get_value())
{
System.out.println("Div by Zero");
return -1;
}
}
if(get_left_node().get_node_type() == "/")
{
return ((div_node)(get_left_node())).check_value();
}
return 1;
}
// generate inter-mediate code
public String generate_intermediate_code()
{
int value;
String str = "";
if(get_left_node().get_node_type() == "/")
{
str = ((div_node)get_left_node()).generate_intermediate_code();
}
if(null == get_right_node())
{
return "";
}
set_node_name("tmp" + Integer.toString(Parse.allocate_index()));
if(get_left_node().get_node_type() == "/")
{
str += "div " + get_node_name() + " " + get_left_node().get_node_name() + " / " + Integer.toString(((value_node)get_right_node()).get_value()) + "\n";
}
else
{
str += "div " + get_node_name() + " " + Integer.toString(((value_node)get_left_node()).get_value()) + " / " + Integer.toString(((value_node)get_right_node()).get_value()) + "\n";
}
return str;
}
}
public class Parse {
public static int index = 0;
public static void main(String[] args) {
for (String arg : args) {
try {
div_node div = evaluate(arg);
String str = div.generate_intermediate_code();
System.out.println("");
div.calculate_depth();
div.print_node(div.get_depth(), div.get_depth()*5);
System.out.println("");
System.out.println(translate_code(str));
//System.out.println(div.check_value());
} catch (ParseException ex) {
System.err.println(ex.getMessage());
}
}
}
public static div_node evaluate(String src) throws ParseException {
Reader reader = new StringReader(src);
return new Parse(reader).expr();
}
// important index
public static int allocate_index()
{
index += 1;
return index;
}
// tranlsater inter-mediate code, with input is inter-mediate code, and output is assmeble code
public static String translate_single_code(String input)
{
String assemble = "";
String[] sub = input.split(" ");
if(sub[2].charAt(0) >= '0' && sub[2].charAt(0) <= '9')
{
assemble += "mov ax," + sub[2] + "\n";
}
else
{
assemble += "load ax,[" + sub[2] + "]\n";
}
assemble += "mov bx," + sub[4] + "\n";
assemble += "div ax, bx\n";
assemble += "store [" + sub[1] + "],ax\n";
return assemble;
}
public static String optimise_assemble_code(String input)
{
String [] sub;
String str = "";
if( input == "")
{
return "";
}
sub = input.split("\n");
for(int i = 0; i < sub.length; i += 1)
{
int j;
String [] word_i;
String [] word_j;
j = i + 1;
if(j < sub.length)
{
word_i = sub[i].split(" ");
word_j = sub[j].split(" ");
if(false == word_i[0].equals("store"))
{
str += sub[i] + "\n";
continue;
}
if( false == word_j[0].equals("load"))
{
str += sub[i] + "\n";
continue;
}
// check register and local mem
if(word_i[1].split(",")[0].equals(word_j[1].split(",")[1]) && word_i[1].split(",")[1].equals(word_j[1].split(",")[0]))
{
i += 1;
}
else
{
str += sub[i] + "\n";
}
}
else
{
str += sub[i] + "\n";
}
}
return str;
}
public static String translate_code(String input)
{
String[] sub;
String str = "";
if(input == "")
{
return "";
}
sub = input.split("\n");
for(int i = 0; i < sub.length; i++)
{
str += translate_single_code(sub[i]);
}
str = optimise_assemble_code(str);
return str;
}
}
PARSER_END(Parse)
SKIP: { <[" ", "\t", "\r", "\n"]> }
TOKEN: {
<INTEGER: (["0"-"9"])+>
}
div_node expr() throws NumberFormatException :
{
Token a ;
Token b ;
div_node div;
}
{
a = <INTEGER>
{
value_node node_a = new value_node();
node_a.set_value(Integer.parseInt( a.image ));
div = new div_node();
div.set_left_node(node_a);
}
(
"/" b = <INTEGER>
{
value_node node_b = new value_node();
node_b.set_value(Integer.parseInt( b.image ));
// important code about node adding
if(div.get_right_node() == null)
{
div.set_right_node(node_b);
}
else
{
div_node prev = div;
div = new div_node();
div.set_left_node(prev);
div.set_right_node(node_b);
}
}
)*
<EOF>
{ return div ; }
}