第8章代码优化_第1页
第8章代码优化_第2页
第8章代码优化_第3页
第8章代码优化_第4页
第8章代码优化_第5页
已阅读5页,还剩52页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、v 解释优化的基本概念以及代码优化器的地位和结构解释优化的基本概念以及代码优化器的地位和结构v 说明编译程序进行代码变换应遵循的原则说明编译程序进行代码变换应遵循的原则v 通过实例说明代码优化通常采用的基本方法通过实例说明代码优化通常采用的基本方法v 介绍基本块的概念及其划分算法介绍基本块的概念及其划分算法v 说明程序流图的构造方法说明程序流图的构造方法v 介绍基本块的介绍基本块的DAG表示方法表示方法v 介绍循环优化一般采用的方法介绍循环优化一般采用的方法8.1 8.1 优化概述优化概述8.2 8.2 局部优化局部优化8.3 8.3 循环优化循环优化8.4 8.4 本章小结本章小结(1)优化

2、的含义对程序进行各种等价变换,使得从变换后的程序出发,能生成更有效的目标代码,称这种变换为。(2)优化分类根据编译阶段的不同划分u 与机器无关的中间代码优化与机器无关的中间代码优化u 依赖于机器的目标代码优化依赖于机器的目标代码优化根据优化对象所涉及的程序范围划分u 局部优化局部优化u 循环优化循环优化u 全局优化全局优化 (3)代码优化器的地位 有很多技术和手段可以用于中间代码这一级上的优化。总体上讲在一个编译程序中优化器的地位和结构如下图:(4)代码优化遵循的原则优化的目的是为了产生更高效的代码。由优化编译程序提供的,对代码的各种变换必须遵循以下三个原则: 经过优化后不应改变程序运行的结果

3、。经过优化后不应改变程序运行的结果。 使优化后所产生的目标代码运行时间较短,占用的存储空间较使优化后所产生的目标代码运行时间较短,占用的存储空间较小。小。 应尽可能以较低的代价取得较好的优化效果。应尽可能以较低的代价取得较好的优化效果。(5)常用的代码优化的方法 删除公共子表达式(删除多余运算)删除公共子表达式(删除多余运算) 复写传播复写传播 删除无用代码(删除无用赋值)删除无用代码(删除无用赋值) 合并已知量合并已知量 代码外提代码外提 强度削弱强度削弱删除归纳变量删除归纳变量循环优化(6)代码优化举例我们通过一个高级语言程序的例子来了解代码优化的全过程。下面是一个用C语言编写的快速排序子

4、程序:void quicksort (int m, int n) int i,j; int v, x;if(n=m) return;/*fragment begins here*/i=m1;j=n;v=an;while(1)do i=i+1; while(aiv);if(i=j) break;x=ai;ai=aj;aj=x;x=ai;ai=an;an=x;/*fragment ends here*/quicksort(m, j);quicksort(i+1,n);通过第6章的中间代码生成方法可以产生这个程序的中间代码。图82给出了程序中两个注解行之间的语句翻译成中间代码序列后所对应的程序流图,

5、对图82程序流图的代码优化叙述如下。删除公共子表达式如果一个表达式E在前面已计算过,并且在这之后E中变量的值没有改变,则称E为。在图82的B5中分别把公共子表达式4*i和4*j的值赋给T7和T10,因此这种重复计算可以消除,即B5中的代码变换成:T6:=4*ix:=aT6T7:=4*iT8:=4*jT9:=aT8aT7:=T9T10:=4*jaT10:=xgoto B2T6:=4*ix:=aT6T7:=T6T8:=4*jT9:=aT8aT7:=T9T10:=T8aT10:=xgoto B2对B5删除了公共子表达式后,仍然要计算4*i和4*j ,我们还可以在更大范围内来考虑删除公共子表达式的问题

6、,即利用B3中的四元式T4:=4*j可以把B5中的代码T8:=4*j替换为T8:=T4。 同样,利用B2中的赋值句T2:=4*i可以把B5中的代码T6:=4*i替换为T6:=T2。 对于B6也可以同样考虑,最后,删除公共子表达式后的程序流图如图83所示。复写传播图83中的B5还可以进一步改进,四元式T6:=T2把T2赋给了T6,而四元式x:=aT6中引用了T6的值,但这中间并没有改变T6的值。因此,可以把x:=aT6变换为x:=aT2。这种变换称为。用复写传播的方法可以把B5变为:T6:=T2x:=aT6T7:=T6T8:=T4T9:=aT8aT7:=T9T10:=T8aT10:=xgoto

7、B2T6:=T2x:=aT2T7:=T2T8:=T4T9:=aT4aT2:=T9T10:=T4aT4:=xgoto B2作进一步的考察可以发现,在B2中计算了T3:= aT2,因此在B5中可以删除公共子表达式,即把x:=aT2替换为x:=T3,并继续通过复写传播,把B5中的aT4:=x替换为aT4 :=T3。 同样,把B5中的T9:=aT4替换为T9:=T5,aT2:=T9替换为 aT2:=T5。 这样B5就变为:T6:=T2x:=T3T7:=T2T8:=T4T9:=T5aT2:=T5T10:=T4aT4:=T3goto B2T6:=T2x:=aT2T7:=T2T8:=T4T9:=aT4aT2

8、:=T9T10:=T4aT4:=xgoto B2复写传播的目的是:使得对某些变量的赋值变为无用。删除无用赋值对于进行了复写传播后的B5,其中的变量x及临时变量T6、T7、T8、T9、T10在整个程序中不再使用,故可以删除对这些变量赋值的代码。删除无用赋值后B5变为: aT2:= T5 aT4:= T3 goto B2对B6进行相同的复写传播和删除无用赋值后变为: aT2:= v aT1:= T3复写传播和删除无用赋值后的程序流图如图8-4所示。代码外提对于循环中的有些代码,如果它产生的结果在循环中是不变的,就可以把它提到循环外来,以避免每循环一次都要对这条代码进行运算。这种变换称之为。如: w

9、hile(i=limit-2) . 可变换为: t:=limit-2 while(i=t). 考察图84,没有发现可外提到循环之外的不变运算。 强度削弱观察图84的内循环B3,每循环一次,j的值减1;而T4的值始终与j保持着T4=4*j的线性关系,即每循环一次,T4值随之减少4。因此,我们可以把循环中计算T4值的乘法运算变为在循环前进行一次乘法运算而在循环中进行减法运算。同样,对循环B2中的T2=4*i也可以进行强度削弱。经过强度削弱后的程序流图如图8-5所示。 删除归纳变量由图84可知,B2中每循环一次,i值加1,T2与i之间保持着T2=4*i的线性关系;而B3中每循环一次,j值减1,T4与

10、j之间保持着T4=4*j的线性关系。这种变量我们称之为。 在对T2=4*i和T4=4*j进行了强度削弱后,i和j仅出现在条件句if ij goto B6中,其余地方不再被引用。因此,我们可以变换归纳变量而把此条件句变换为:if T2T4 goto B6。经过这种变换,我们又可以将无用赋值i=i+1和j=j1删去。删除归纳变量后的程序流图如图86所示。 通过上述各种优化,最终得到图86的优化结果。比较图82和图86可知:B2和B3中的四元式从4条减为2条,而且一条是由乘法变为加法;B5中的四元式由9条变为3条,B6中的四元式由8条变为2条。以上这些优化对循环执行来说,效果是非常明显的。虽然B1的

11、四元式由4条变为6条,但因其仅被执行一次,所以影响甚微。 返回基本块及流图基本块及流图 1基本块的基本块的DAG表示及其应用表示及其应用 2(1)基本块所谓,是指程序中一顺序执行的语句序列,其中只有一个入口和一个出口,入口就是其中的第一个语句,出口就是其中的最后一个语句。对一个基本块来说,执行时只能从其入口进入,从其出口退出。例如下面的三地址语句序列就形成了一个基本块: T1:=a*a T2:=a*b T3:=2*T2 T4:=T1+T2 T5:=b*b T6:=T4+T5(2)定值和引用如果一条三地址语句为x:=y+z,则称对x并y和z。(3)活跃的在一个基本块中的一个名字,所谓在程序中的某

12、个给定点是,是指如果在程序中(包括在本基本块或在其它基本块中)它的值在该点以后被引用。(4)局部优化局限于基本块范围内的优化称为,或称为。(5)划分基本块的算法求出四元式程序中各个基本块的入口语句,它们是 程序的第一个语句;或者程序的第一个语句;或者 能由条件转移语句或无条件转移语句转移到的语句;或者能由条件转移语句或无条件转移语句转移到的语句;或者 紧跟在条件转移语句后面的语句。紧跟在条件转移语句后面的语句。对以上求出的每一入口语句,构造其所属的基本块,它是由该入口语句到另一入口语句(不包括该入口语句),或到一转移语句(包括该转移语句),或到一停语句(包括该停语句)之间的语句序列组成的。凡未

13、被纳入某一基本块中的语句,都是程序中控制流无法到达的语句。从而也是不会被执行到的语句,可把它们从程序中删除。【例 8.1】将以下求最大公因子的程序划分为基本块。read Xread YR:=X mod Yif R=0 goto X:=YY:=Rgoto write Yhalt解:解:(1)找入口语句 (2) 构造基本块 B1: B2: B3: B4:(6)基本块内可实现的变换合并已知量合并已知量临时变量改名临时变量改名交换语句的位置交换语句的位置 代数变换代数变换 (8)流图一个(简称)就是具有唯一首结点的有向图。所谓,就是从它开始到控制流程图中任何一个结点都有一条通路的结点。我们可以把控制流

14、程图表示成一个三元组G=(N,E,n0);其中,N代表图中所有结点集,E代表图中所有有向边集,n0代表首结点。 一个程序可用一个流图来表示。流图的有限结点集N就是程序的基本块集,流图中的结点就是程序的基本块,流图的首结点就是包含程序第一个语句的基本块。流图的有向边集E是这样构成的:假设流图中结点i和结点j分别对应于程序的基本块i和基本块j,则当下述条件有一个成立时,从结点i有一条有向边引到结点j:(8)流图 基本块j在程序中的位置紧跟在基本块i之后,并且基本块i的出口语句不是无条件转移语句goto(s)或停语句。 基本块i的出口语句是goto(s)或if goto(s),并且(s)是基本块j的

15、入口语句。基本块基本块i.非非goto或或halt基本块基本块j基本块基本块i.if. goto(S)基本块基本块j(S).【例 8.2】将以下程序划分为基本块,并作出其程序流图。read Xread YR:=X mod Yif R=0 goto X:=YY:=Rgoto write Yhaltread Xread YR:=X mod Yif R=0 goto X:=YY:=Rgoto write YhaltB1B2B4B3(1)基本块的DAG表示基本特征 (Directed Acyclic Graph)是一种有向图,常常用来对基本块进行优化。一个基本块的DAG是一种其结点带有下述标记或附加信

16、息的DAG:图的叶结点(无后继的结点)以一标识符(变量名)或常数作为标记,表示该结点代表该变量或常数的值。如果叶结点用来表示一变量A的地址,则用addr(A)作为该结点的标记。通常把叶结点上作为标记的标识符加上下标0,以表示它是该变量的初值。图的内部结点(有后继的结点)以一运算符作为标记,表示该结点代表应用该运算符对其直接后继结点所代表的值进行运算的结果。图中各个结点上可能附加一个或多个标识符,表示这些变量具有该结点所代表的值。(2)基本块的DAG表示 四元式与DAG结点 一个基本块由一个四元式序列组成,且每一个四元式都可以用相应的DAG结点表示。注:在以下各图中u 各结点圆圈中的各结点圆圈中

17、的ni是构造是构造DAG过程中各结点的编号。过程中各结点的编号。u 各结点下面的符号各结点下面的符号(运算符、标识符或常数运算符、标识符或常数)是各结点的标记。是各结点的标记。u 各结点右边的标识符是结点上的附加标识符。各结点右边的标识符是结点上的附加标识符。u 除了对应转移语句的结点右边可附加一语句位置来指示转移目标外,其除了对应转移语句的结点右边可附加一语句位置来指示转移目标外,其余各类结点的右边只允许附加标识符。余各类结点的右边只允许附加标识符。u 除对应于数组元素赋值的结点除对应于数组元素赋值的结点(标记为标记为 =)有三个后继外,其余结点最多有三个后继外,其余结点最多只有两个后继。只

18、有两个后继。、0型四元式:后继结点个数为0。n1ABn1(S)n1opBn2Aa) A:=Bb) goto (S)A:=op B、1型四元式:有一个后继结点。、2型四元式:有两个后继结点。n1opBn3An2Cn1=Bn3An2Cn1ropBn3(S)n2Ca) A:= B op Cb) A:= BCc) if B rop C goto (S)、3型四元式:有三个后继结点。DC :=Bn1=Dn4Bn2Cn3(3)仅含0,1,2 型中间代码的基本块DAG构造算法 我们规定:用大写字母(如A、B等)表示四元式中的变量名(或常数);用函数Node(A)表示A在DAG中的相应结点,其值可为n或者无定

19、义,并用n表示DAG中的一个结点值。开始,DAG为空。对基本块中每一条中间代码式,依次执行以下步骤。、如果NODE(B)无定义,则构造一标记为B的叶结点并定义NODE ( B)为这个结点。若当前四元式是0型, 则记Node(B)的值为n, 转。若当前四元式是1型, 则转。若当前四元式是2型, 则:i.若Node(C)无定义,则构造一标记为C的叶结点, 并定义Node(C)为该结点;ii.转。 若Node(B)是以常数标记的叶结点,则转,否则转。若Node(B)和Node(C)都是以常数标记的叶结点,则转,否则转。执行op B(即合并已知量),令得到的新常 数为P。n 若若Node(B)是处理当

20、前四元式时新建立的结点,则删除它;是处理当前四元式时新建立的结点,则删除它;n 若若Node(P)无定义,则构造一个用无定义,则构造一个用P做标记的叶结点做标记的叶结点n,并置,并置Node(P)= n;转;转。 执行B op C(即合并已知量),令得到的新常数为P。n 若若Node(B)或或Node(C)是处理当前四元式时新建立的结点则删除它;是处理当前四元式时新建立的结点则删除它;n 若若Node(P)无定义,则构造一用无定义,则构造一用P标记的叶结点标记的叶结点n,并置,并置Node(P)= n;转转。 检查DAG中是否有标记为op且以Node(B)为唯一后继的结点。n 若有则把已有的结

21、点作为它的结点,并设该结点为若有则把已有的结点作为它的结点,并设该结点为n;n 若没有,则构造一个新结点;转若没有,则构造一个新结点;转。检查DAG中是否有标记为op且其左后继为Node(B)、右后继为Node(C)的结点(即查找公共子表达式)。n 若有,则把已有的结点作为它的结点,并设该结点为若有,则把已有的结点作为它的结点,并设该结点为n;n 若没有,则构造一个新结点;转若没有,则构造一个新结点;转。若Node(A)无定义,则把A附加在结点n上,并令Node(A)= n;否则,先从Node(A)的附加标识符集中将A删去(若Node(A)是叶结点,则不能将A删去),然后再把A附加到新结点 n

22、上,并令Node(A)=n。转处理下一代码。(4)构造DAG实例 【例 8.4】 试构造以下基本块G的DAG:(1) T0=3.14(2) T1:=2*T0(3)T2:=R+r(4) A: =T1*T2(5) B: =A(6) T3:=2*T0(7) T4:=R+r(8) T5:=T3*T4(9T6:=R-r(10) B:=T5*T6n13.14T0n26.28n3Rn4rT1(1) T0:=3.14 (2) T1:= 2*T0(3) T2:=R+r (4) A:= T1* T2(5) B:=A (6) T3:= 2*T0(7) T4:=R+r (8) T5:= T3* T4(9) T6:=R

23、-r (10) B:= T5* T6n5+T2n6*A,B,T3,T4,T5n7-T6n8*B(5)利用DAG进行基本块的优化 利用DAG进行基本块优化的基本思想:首先按基本块内的四元式序列顺序将所有的四元式构造成一个DAG,然后按构造结点的次序将DAG还原成四元式序列。由于在构造DAG的同时已作了局部优化,所以最后所得到的是优化过的四元式序列。例如,上例四元式序列经优化后得G如下:(1) T0:=3.14(2) T1:=6.28(3) T3:=6.28(4) T2:=R+r(5) T4:=T2(6) A:=6.28*T2(7) T5:=A(8) T6:= Rr (9) B:=A*T6n13.

24、14T0n2n3n4rT1n5+T2n6*A,T3,T4,T5n7-T6n8*B6.28R将G和原基本块G相比,我们看到: G中四元式中四元式(2)和和(6)都是已知量和已知量的运算,都是已知量和已知量的运算,G已合并;已合并; G中四元式中四元式(5)是一种无用赋值,是一种无用赋值,G已将它删除;已将它删除; G中四元式中四元式(3)和和(7)的的R+r是公共子表达式是公共子表达式,G只对它们计算了一次,只对它们计算了一次,即删除了多余的即删除了多余的R+r运算。运算。因此,G是对G实现上述三种优化的结果。通过观察上图中的所有叶结点和内部结点以及其上的附加标识符,还可以得出以下结论: 在基本

25、块外被定值并在基本块内被引用的所有标识符就是在基本块外被定值并在基本块内被引用的所有标识符就是DAG中相中相应叶结点上标记的标识符;应叶结点上标记的标识符; 在基本块内被定值且该值能在基本块后面被引用的标识符就是在基本块内被定值且该值能在基本块后面被引用的标识符就是DAG各结点上的附加标识符。各结点上的附加标识符。这些结论可以引导优化工作的进一步深入,尤其是无用赋值的优化,也即: 如果如果DAG中某结点上的标识符在该基本块之后不会被引用,就可以中某结点上的标识符在该基本块之后不会被引用,就可以不生成对该标识符赋值的四元式。不生成对该标识符赋值的四元式。 如果某结点如果某结点ni上没有任何附加标

26、识符,或者上没有任何附加标识符,或者ni上的附加标识符在该基上的附加标识符在该基本块之后不会被引用,而且本块之后不会被引用,而且ni也没有前驱结点,这表明在基本块内和也没有前驱结点,这表明在基本块内和基本块之后都不会引用基本块之后都不会引用ni的值,那么就不生成计算的值,那么就不生成计算ni结点值的四元式。结点值的四元式。如果有两个相邻的四元式如果有两个相邻的四元式A:=C op D和和B:=A,其中第一条代码计算出,其中第一条代码计算出来的来的A值仅在第二个四元式中被引用,则将值仅在第二个四元式中被引用,则将DAG中相应结点重写成四中相应结点重写成四元式时,原来的两个四元式可以优化为元式时,

27、原来的两个四元式可以优化为B:=C op D。假设例8.4中T0、T1、T2、T3、T4、T5和T6在基本块后都不会被引用,则图中的DAG就可重写为如下的四元式序列:(1) S1:=R+r /*S1、S2为存放中间结果的临时变量为存放中间结果的临时变量*/(2) A:=6.28*S1(3) S2:=Rr(4) B:=A*S2以上把DAG重写成四元式序列时,是按照原来构造DAG结点的顺序(即n5、n6、n7、n8)依次进行的。实际上,我们还可以采用其它顺序(如自下而上)重写,只要其中的任何一个内部结点是在其后继结点之后被重写并且转移语句(如果有的话)仍然是基本块的最后一个语句即可。返回 在程序流

28、图中,我们称具有下列性质的结点序列为一个: 它们是它们是强连通强连通的,其中任意两个结点之间必有一条通路,而且该通的,其中任意两个结点之间必有一条通路,而且该通路上各结点都属于该结点序列;如果序列只包含一个结点,则必有路上各结点都属于该结点序列;如果序列只包含一个结点,则必有一条有向边从该结点引到其自身。一条有向边从该结点引到其自身。 它们中间它们中间有一个而且只有一个有一个而且只有一个是入口结点。是入口结点。 所谓,是指序列中具有下述性质的结点:从序列外某结点有一条有向边引到它,或者它就是程序流图的首结点。也就是说,循环就是程序流图中具有唯一入口结点的强连通子图,从循环外要进入循环,必须首先

29、经过循环的入口结点。 考虑右图所示的程序流图:结点序列有一有向边引到自身,且有唯一的入口结点6, 故是循环;结点序列中任两结点间都存在通路,且有唯一入口结点2,故是循环;结点序列强连通且有唯一入口结点4,虽到结点4有向边不止一条,但仍是循环;结点序列和,虽强连通但由于存在两个入口结点2,4,故不是循环; 结点序列和因存在两个入口结点4,7, 故不是循环。 1243576 代码外提代码外提 1强度削弱强度削弱 2删除归纳变量删除归纳变量 3(1)代码外提若循环中某些运算的结果不因循环而改变,则可将其提到循环之外,从而在保持程序运行结果不变的前提下,提高了程序的运行效率,这种优化技术称为。 实行代码外提时,需在循环入口结点前建立一个新结点(基本块),称为循环的。循环前置结点以循环入口结点为其唯一后继,原来流图中从循环外引到循环入口结点的有向边改成引到循环前置结点。 (2)施行代码外提需要满足的条件假定循环L中的不变运算S为A=B op C或A=op B或A=B。要求满足下述条件(A在离开L后仍是活跃的):当把循环中一不变运算外提到循环前置结点时,要求该不变运算所在结当把循环中一不变运算外提到循环前置结点时,要求该不变运算所在结点是循环所有出口结点的必经结点。点是循环所有出口结点的必经结点。 当把循环中一不变运算当把循环中一不变运算A=B op C外提时

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论