« 上一篇下一篇 »

寄存器和地址描述符

我们代码生成算法依次考虑了各个三地址指令,并决定需要哪些加载指令来把必需的运算分量加载寄存器。在生成加载指令之后,它开始生成运算代码。然后,如果有必要把结果存放人一个内存位置,它还会生成相应的保存指令。

为了做出这些必要的决定,我们需要一个数据结构来说明哪些程序变量的值当前被存放在哪个或哪些寄存器里面。我们还需要知道当前存放在一个给定变量的内存位置上的值是否就是这个变量的正确值。因为变量的新值可能已经在寄存器中计算出来但还没有存放到内存中。这个数据结构具有下列描述符:

1)每个可用的寄存器都有一个寄存器描述符(register descriptor)。它用来跟踪有哪些变量的当前值存放在此寄存器内。因为我们仅仅考虑那些用于存放一个基本块内的局部值的寄存器, 我们可以假设在开始时所有的寄存器描述符都是空的。随着代码生成过程的进行,每个寄存器将存放零个或多个变量名字的值。

2)每一个程序变量都有一个地址描述符(address descriptor) 0它用来跟踪记录在哪个或哪些位 置上可以找到该变量的当前值。这个位置可以是一个寄存器、一个内存地址、一个栈中的位置,也可以是由这些位置组成的一个集合。这个信息可以存放在这个变量名字对应的符号表条目中。

代码生成算法

这个算法的一个重要部分是函数getReg(I)。这个函数为每个与三地址指令I有关的内存位置选择寄存器。函数getReg可以访问这个基本块的所有变量对应的寄存器和地址描述符。这个函数还可能需要获取一些有用的数据流信息,比如哪些变量在基本块出口处活跃。我们将首先给出基本算法,然后再讨论函数。我们不知道总共有多少个寄存器可用于存放基本块的局部数据,因此假设有足够的寄存器使得在把值存放回内存,释放了所有的可用寄存器之后,空闲的寄存器足以完成任何三地址运算。

在一个形如x=y+z的三地址指令中,我们将把+当作一般的运算符,而ADD当作等价的机器指令。因此,我们没有利用+的交换性。这样,当我们实现这个运算时,y的值必须在ADD指令中给出的第二个寄存器中,而绝不会是第三个寄存器。可以按照下面的方法来改进算法:只要+是一个满足交换律的运算符,算法同时为x=y+z和x =z+y生成代码;随后再选择一个比较好的代码序列。

运算的机器指令

对每个形如+-的三地址指令,完成下列步骤:

1)使用getReg(x=y+z)来为x选择寄存器。我们把这些寄存器称为RxRy和Rz。

2)如果(根据Ry的寄存器描述符)y不在Ry中,那么生成一个指令“LD Ry, y'”其中是y'存放y的内存位置之一(y'可以根据y的地址描述符得到)。

3)类似地,如果z不在Rz内,生成一个指令“LD Rz z'”,其中z'是存放z的位置之一。

4)生成指令“ADDRx,Ry,Rz”。

« 上一篇下一篇 »