« 上一篇下一篇 »

函数getReg的设计

我们考虑如何针对一个地址指令I实现函数getReg(I)。实现这个函数可以选择很多种方法,当然也存在一些绝对不可以选择的方法。这些错误方法会因丢失一个或多个活跃变量的值而导致生成错误代码。我们用处理一个运算指令的步骤来开始我们的讨论,还是用x=y+z作为一般性的例子。首先,我们必须为y和z分别选择一个寄存器。这两次选择所面临的问题是相同的,因此我们将集中考虑为y选择寄存器Ry的方法。选择规则如下:

1)如果y当前就在一个寄存器中,则选择一个已经包含了y的寄存器作为Ry。不需要生成一个机器指令来把y加载到这个寄存器。

2)如果y不在寄存器中,但是当前存在一个空寄存器,那么选择这个空寄存器作为Ry。

3)比较困难的情况是y不在寄存器中且当前也没有空寄存器。无论如何,我们需要选择一个可行的寄存器,并且必须保证复用这个寄存器是安全的。设是一个候选寄存器,且假设u是R的寄存器描述符表明的已位于R中的变量。我们需要保证要么u的值已经不会被再次使用,要么我们还可以到别的地方获取u的值。可能的情况包括:

①如果u的地址描述符说还保存在之外的其他地方,我们就完成了任务。

②如果u是x,即由指令I计算的变量,且x不同时是指令I的运算分量之一(比如这个例子中的z),那么我们就完成了任务。其原因是在这种情况下,我们知道x的当前值决不会再次被使用,因此我们可以忽略它。

③否则,如果u不会在此之后被使用(即在指令I之后不会再次使用u,且如果u在基本块的出口处活跃,那么u的值必然在基本块中被重新计算),那么我们就完成了任务。

④如果前面的三个条件都不满足,我们就需要生成保存指令ST u, R来把u的值复制到它自己的内存位置上去。这个操作称为溢出操作(spill)。

因为在那个时刻可能存放了多个变量的值,所以我们需要对每个这样的变量u重复上述步骤。最后,R的“得分”是我们需要生成的保存指令的个数。选择一个具有最低得分的寄存器(或之一)。

现在考虑寄存器Rx的选择。其中的难点和可选项几乎和选择Ry时的一样,因此我们只给出其中的区别。

1)因为x的一个新值正在被计算,因此只存放了x的值的寄存器对Rx来说总是可接受。即使x就是y或z之一,这个语句仍然成立,因为我们的机器指令允许一个指令中的两个寄存器相同。

2)如果(像上面对变量u的描述那样)y在指令I之后不再使用,且(在必要时加载y之后)Ry仅仅保存了y的值,那么Ry同时也可以用作Rx。

对z和Rz也有类似选择。需要特别考虑的最后一个问题是当I是复制指令x = y时的情况。我们用上面描述的方法选择Ry,然后是让Rx =Ry。

« 上一篇下一篇 »