消除不可达代码

另一个窥孔优化的机会是消除不可达的指令。一个紧跟在无条件跳转之后的不带标号的指令可以被删除。通过重复这个运算,就可以删除一个指令序列。比如,为了调试的目的,一个大型程序中可能含有一些只有当变量debug等于1时才运行的代码片断。在中间表示形式中,这个代码看起来可能就像

if debug == 1 goto L1
goto L2

L1: print debugging information
L2:

一个显而易见的窥孔优化方法是消除级联跳转指令。因此,不管debug的值是什么,上面的代码序列可以被替换为:

表达式的优化代码的生成

当一个基本块仅包含单一的表达式求值时,或者我们认为以逐次处理各个表达式的方式为基本块生成代码就已经足够了,那么我们就可以最佳地选择寄存器。在下面的算法中,我们引人对一个表达式树(即一个表达式的语法树)的结点添加数字标号的方案。在使用固定个数的寄存器来对一个表达式求值的情况下,该方案允许我们为表达式生成最优的代码。

Ershov 数

一开始,我们给一个表达式树的每个结点各赋予一个数值。该数表示如果我们不把任何临时值存放问内存的话,计算该表达式需要多少个寄存器。这些数有时被称为Ershou数(Ershov nurnher)。这是根据A.Ershov命名的,他为只有一个算术寄存器的机器使用了类似的方案。对我们的机器模型而言,计算Ershov数的规则如下:

从带标号的表达式树生成代码

假设在我们的机器模型中,所有的运算分量都必须在寄存器中,且寄存器可以同时用于存放某个运算的运算分量和结果。可以证明,如果在计算表达式的过程中不允许把中间结果保存回内存,那么一个结点的标号就等于计算该结点对应的表达式时需要的最少的寄存器个数。因为在这个机器模型中,我们必须把每个运算分量加载到寄存器中,且必须计算每个内部结点所对应的中间结果,所以,造成生成代码不是最优代码的唯一可能是我们使用了不必要的将临时结果存回内存的指令。对这个断言的证明包含在下面的算法中。这个算法生成的代码不包含将临时结果存回内存的指令,而这个代码所使用的寄存器数目就是根结点的标号。

代码调度约束

这些调度约束保证了优化后的程序和原程序生成同样的结果。但是,因为代码调度改变了运算执行的顺序,所以优化后的程序执行时某一点上的内存状态可能和顺序执行时任一点上的内存状态都不匹配。如果一个程序的执行因异常或用户设定的断点而中断时,就会产生问题。因此经过优化的程序比较难以调试。请注意,这个问题不是代码调度专有的,所有的优化技术都会出现这个问题,包括部分冗余消除和寄存器分配。
代码调度是程序优化的一种形式,它应用于由代码生成器生成的机器代码。代码调度要遵守下面三种约束:

1)控制依赖约束。所有在原程序中执行的运算都必须在优化后的程序中执行。

寄存器使用和并行性之间的折衷与代码调度阶段之间的顺序

我们将假设源程序的机器无关中间表示形式使用了无限多个伪寄存器(pseudoregister)。 这些伪寄存器代表了可以分配到寄存器的变量。这些变量包括源程序中不能通过任何其他名字访问的标量,也包括由编译器生成的用于存放表达式的部分结果的临时变量。和内存位置不同,寄存器的命名是唯一的。因此可以很容易地为寄存器访问生成精确的数据依赖约束。

在中间表示形式中使用的无限多个伪寄存器最终必须被映射到在目标机器上可用的少量物理寄存器。把几个伪寄存器映射为同一个物理寄存器有一个副作用。这种映射会生成人为的存储依赖,这限制了指令级的并行性。反过来,并行执行指令产生了更多的存储需求,以便存放同时计算出来的值。因此,尽量降低寄存器使用数量的目标和最大化指令级并行性的目标直接冲突。

«12»
最近发表
控制面板
您好,欢迎到访网站!
  [查看权限]
网站分类
搜索
Tags列表
网站收藏
图标汇集
  • 订阅本站的 RSS 2.0 新闻聚合
友情链接

热门搜索: 外链域名 高外链域名 高收录域名

Copyright www.thyst.cn. Some Rights Reserved.