« 上一篇下一篇 »

代数恒等式的使用

DAG消除代码操作可以按照如下方式实现。我们一个DAG上删除所有没有附加活跃变量的根结点(即没有父结点的结点)。重复应用这样的处理过程就可以从DAG中消除所有对应于死代码的结点。

代数恒等式表示基本块的另一类重要的优化方法。比如,我们可以使用诸如:

x+0=0+x=x  x-0 =x

x*1=1*x=x  x/1 =x

这样的恒等式来从一个基本块中消除计算步骤。

另一类代数优化是局部强度消减(reduction in strength),就是把一个代价较高的运算替换为 一个代价较低的运算。比如:

代价较高的     代价较低的
             ㎡         =    m*m
             2*x        =    x+x
             x/2        =    x*0.5

第三种相关的优化是常量合并(constant folding)。使用这种方法时,我们在编译时刻对常量表达式求值,并把此常量表达式替换为求出的值。因此,表达式2 *3.14可以被替换为6.28。

在实践中,因为在程序中频繁使用符号常量,所以会出现常量表达式。

DAG的构造过程可以帮助我们使用这些转换,以及其他的通用代数转换规则,比如交换律和结合律等。比如,假设语言的参考手册确定*是可交换的,也就是说,x *y = y*x。在创建一个标记为*且左右子结点分别是M和N的新结点时,我们总是检查这样的结点是否已经存在。然而,因为*是可交换的,所以我们还应该检查是否存在一个标记为*且左右子结点分别是N和M的结点。

<和=这样的关系运算符有时会产生意料之外的公共子表达式。比如,条件表达式x>y也可以通过将参数相减并测试由减法运算设置的条件代码来测试。因此,x-y和x>y:只需要生成一个DAG结点。

结合律也可以用于揭示公共子表达式。比如,如果源程序中包含如下的赋值语句:

编译器的设计者应该仔细阅读语言的参考手册,以决定可以重新排列哪些计算。因为计算机算术(因为上溢或下溢等原因)可能不一定遵守数学上的代数恒等式。比如,Fortran语言标准说,编译器可以通过任意数学上等价的表达式来求值,前提是不能违反原来表达式的括号的一致性。因此,编译器可以用x*(y-z)的方式来计算但是它不能以(a+ b)-c的方式计算a +( 6-c)。因此,如果一个Fortran编译器想按照语言的定义来优化程序,它必须跟踪源语言表达式中哪些地方有括号。

« 上一篇下一篇 »