文章目录
一、优化主要为两类:
- 中间代码的优化(不依赖硬件)
- 目标代码的优化(依赖硬件)
编译前端 ->代码优化器->代码产生
- 优化对代码进行的变换必须遵守以下原则:
- 等价原则: 经优化的代码执行结果不变;
- 有效原则: 优化后确实执行时间短、占用空间少;
- 合算原则: 以较低的代价,换取较好的优化效果。
二、常用优化方式
- 删除公共子表达式(多余运算)
- 复写传播
- 删除无用代码
- 代码外提
- 删除归纳变量
- 合并已知量
三、局部优化
对于给定的一个程序,可以将其划分为一系列的
基本块,分别在块内进行局部优化(基本块内的优化)。
1. 求出程序中可做基本块入口的语句,它们是:
- Ⅰ. 程序的第一条语句;
- Ⅱ. 能由条件转移语句或无条件转移语句转移到的语句;
- Ⅲ. 紧跟在条件转移语句后面的语句。
2. 对以上入口语句,构造其所属的基本块:
此入口语句到下一条入口语句前,或下一条跳转
语句前,或一条停语句前的语句序列组成一个基本块。
3. 删除未被纳入任何基本块的语句。
对基本块内的语句可以进行如下一些优化变换:
- 合并已知量
- 交换语句位置
- 代数变换
以基本块为结点,构造程序的流程图,称为流图。
四、基本块的DAG表示及其应用
1. 基本块的DAG表示
一个基本块的DAG为如下形式的图:
- Ⅰ.叶子结点:以一个标识符或常数或变量的地址作为
标记。标识符可以0为下标,表示初值; - Ⅱ.内部结点:以运算符为标记;
- Ⅲ.各结点可附加多个标识符,表示这些标识符等价,
且具有该结点的值。
2. 构造基本块的DAG的算法:
a. 0型:A=B
- NODE(B)无定义,则构造叶结点n,NODE(B)=n;
- NODE(A)有定义,则删除A在原结点的标记。
令NODE(A)=n。
b. 1型:A= OP B
c.NODE(B)无定义,则构造叶结点n,NODE(B)=n;
d.若B为常数,则计算 OP B => P,若NODE§无定义,
则构造叶结点n,NODE§=n, 执行0型2。
e.若B非常数,查有无 OP B 子树:
- 有:设 NODE(OP)=n, 执行0型2;
- 无:构造n结点OP, 执行0型2 。
2型:A=B OP C 或 A=B[C]
- NODE(B)无定义,则构造叶结点B;
NODE©无定义,则构造叶结点C; - 若B,C均为常数,则计算B OP C=> P, 若NODE§无
定义,则构造叶结点n, NODE§=n, 执行0型2。 - 若B,C不是常数,查有无 B OP C 子树:
有:设 NODE(OP)=n, 执行0型2;
无:构造n结点OP, 执行0型2 。
在构造基本块的DAG时,当参与运算的结点均为常数时,已直接计算结果,生成新常数结点(合并已知)。
3.循环优化
对循环中的代码可以实行代码外提、强度削弱和删除归纳变量等优化。
1.代码外提
循环中的代码要随着循环反复执行,但其中某些运算的结果并不因循环而改变,对于这种不随循环变化的运算,可以将其外提到循环外。这样,程序的运行结果仍保持不变,但程序的运行效率却提高了。我们称这种优化为代码外提。
实行代码外提时,在循环入口结点前面建立一个新结点(基本块),称为循环的前置结点。循环前置结点以循环入口结点为其唯一后继,原来流图中从循环外引到循环入口结点的有向边改成引到循环前置结点
因为在我们所定义的循环结构中,其入口结点是唯一的,所以前置结点也是唯一的。循环中外提的代码将统统外提到前置结点中。