(4)源代码优化程序(source code optimizer)
编译器通常包括许多代码改进或优化步骤。绝大多数最早的优化步骤是在语义分析之后完 成的,而此时代码改进可能只依赖于源代码。这种可能性是通过将这一操作提供为编译过程中的单独阶段指出的。每个编译器不论在已完成的优化种类方面还是在优化阶段的定位中都有很大的差异。 在上例中,我们包括了一个源代码层次的优化机会,也就是:表达式4 + 2可由编译器计算先得到结果6 (这种优化称为常量合并(constant folding ))。当然,还会有更复杂的情况。还是在上例中,通过将根节点右面的子树合并为它的常量值,这个优化就可以直接在(注释)语法树上完成: 尽管许多优化可以直接在树上完成,但是在很多情况下,优化接近于汇编代码线性化形式的树更为简便。这样节点的变形有许多,但是三元式代码(three-address code )(之所以这样称呼是因为它在存储器中包含了3个(或3个以上)位置的地址)却是标准选择。另一个常见的选 择是P -代码(P - code ),它常用于Pascal编译器中。 在前面的例子中,原先的C表达式的三元式代码应是: t = 4 + 2 a [ index] = t (请注意,这里利用了一个额外的临时变量t 存放加法的中间值)。这样,优化程序就将这个代码改进为两步。首先计算加法的结果: t = 6 a [index] = t 接着,将t替换为该值以得到三元语句 a [index] = 6 ,指出源代码优化程序可能通过将其输出称为中间代码(intermediate code )来使用三元式代码。中间代码一直是指一种位于源代码和目标代码(例如三元式代码或类似的线性表示)之间的代码表示形式。但是,我们可以更概括地认为它是编译器使用的源代码的任何一个内部表示。此时,也可将语法树称作中间代码,源代码优化程序则确实能继续在其输出中使用这个表示。有时,这个中间代码也称作中间表示(intermediate representation,IR)。
(5)代码(code generator)
代码得到中间代码(IR),并生成目标机器的代码。正是在编译的这个阶段中,目标机器的特性成为了主要因素。当它存在于目标机器时,使用指令不仅是必须的而且数据的形式表示也起着重要的作用。例如,整型数据类型的变量和浮点数据类型的变量在存储器中所占的字节数或字数也很重要。 在上面的示例中,现在必须决定怎样存储整型数来为数组索引生成代码。例如,下面是所给表达式的一个可能的样本代码序列(在假设的汇编语言中):
M O V R0, index ;;
value of index -> R0 M U L R0, 2 ;;
double value in R0 M O V R1, &a ;;
address of a -> R1 A D D R1, R0 ;;
add R0 to R1 M O V *R1, 6 ;;
constant 6 -> address in R1
在以上代码中,为编址模式使用了一个类似C的协定,因此& a是a的地址(也就是数组的基地址),* R1则意味着间接寄存器地址(因此最后一条指令将值6存放在R1包含的地址中)。 这个代码还假设机器执行字节编址,并且整型数占据存储器的两个字节(所以在第2条指令中用2作为乘数)。
(6)目标代码优化程序(target code optimizer )
在这个阶段中,编译器尝试着改进由代码生成的目标代码。这种改进包括选择编址模式以提高性能、将速度慢的指令更换成速度快的,以及删除多馀的操作。 在上面给出的样本目标代码中,还可以做许多更改:在第2条指令中,利用移位指令替代乘法(通常地,乘法很费时间),还可以使用更有效的编址模式(例如用索引地址来执行数组 存储)。使用了这两种优化后,目标代码就变成:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-27981-4.html
简直各种感动各种正力量好不好