简单代码生成算法是针对一个基本块而言的。假设基本块中均为形如X:=Y op Z的中间代码,对于其他形式的中间代码的翻译可参考下述算法进行。在生成过程中,寄存器的分配非常关键,构建一个函数GETREG来完成这个任务,其参数就是第i条中间代码i:X:=Y op Z。该函数将返回一个寄存器,用来存放X的现行值。
算法9.2 利用GETREG分配寄存器
1)如果Y的当前值在某寄存器Ri中,且RVALUE[Ri]={Y},同时,满足如下两种情况之一的:
(1)如果Y与X是同一标识符,或者
(2)在中间代码i的附加信息中,Y的待用信息和活跃信息分别为“非待用”和“非活跃”,意味着Y的现行值在执行中间代码i:X:=Y op Z之后不会再引用。则选取Ri为所需的寄存器R,并返回。
2)如果有空闲的寄存器,则从中选取一个Ri为所需的寄存器R,并返回。
3)从已分配的寄存器中选取一个Ri为所需的寄存器R。假设变量A占用Ri,则需满足以下条件之一:
(1)变量A的现行值,存放在内存单元中,这样可以从此单元中读取A。
(2)在基本块中,A不会被引用到或者要在最远的将来才会引用到,这可从有关中间代码i上的待用信息得知。
这样,对寄存器Ri所含的变量和变量在内存中的情况必须做出调整,即对RVALUE[Ri]中的每一个变量M,如果M不是X且AVALUE[M]不包含M,则需完成以下处理:
①生成目标代码MOV M,Ri,即把不是X的变量值由Ri送入内存中;
②如果M不是Y,则令AVALUE[M]={M},否则,令AVALUE[M]={M,Ri};
③删除RVALUE[Ri]中的M。
算法9.2的实现过程可以描述为:
算法9.3 简单代码生成算法。
对基本块中每条中间代码i:X:=Y op Z,完成下述步骤。
1)调用函数GETREG(i:X:=Y op Z),返回一个寄存器R,用来存放X的现行值。
2)根据变量地址描述数组AVALUE[Y]和AVALUE[Z],确定出变量Y和Z现行值的存放位置addr(Y)和addr(Z)。如果其现行值在寄存器中,则把寄存器取作addr(Y)和addr(Z)。(www.xing528.com)
3)(1)如果addr(Y)≠R,则生成目标代码:
MOV R,addr(Y)
op R,addr(Z)
(2)如果addr(Y)=R,则生成目标代码:
op R,addr(Z)
(3)如果addr(Y)或addr(Z)为R,则删除AVALUE[Y]或AVALUE[Z]中的R。
4)令AVALUE[X]={R},RVALUE[R]={X},以表示变量X的现行值仅放在R中,R中的值仅代表X的现行值。
5)如果Y和Z的现行值在基本块中不再被引用,也不是基本块出口之后的活跃变量(通过中间代码i上的附加信息可知),并且其现行值在某寄存器Rk中,则删除RVALUE[Rk]中的Y或Z以及AVALUE[Y]中的Rk,使该寄存器不再被Y或Z所占用。
算法9.3的实现过程可以描述为:
对于其他形式的中间代码,可以参照算法9.3来生成目标代码。表9-6给出了典型中间代码所对应的目标代码序列。
表9-6 典型中间代码对应的目标代码
例9.3 对例9.2,假设只有R0和R1是可用寄存器,W在基本块外是活跃的,用简单代码生成算法生成的目标代码和相应的RVALUE与AVALUE如表9-7所示。
表9-7 目标代码及相关信息
由于变量A、B、C的值一直保存在存储器中,因此,在地址描述数组中没有显示它们。并且,还假定临时变量T、U、V均不在存储器中。
基本块中所有中间代码处理完之后,对于当前值仅保存在某寄存器中的每个活跃变量,需要将其存放到内存单元中。此时,利用RVALUE可以决定在寄存器中存放了哪些变量的现行值,再利用AVALUE来决定其中哪些变量的现行值尚不在内存单元中,最后,利用活跃变量信息来决定哪些变量是活跃的。就例9.3来说,从RVALUE得知W的值在寄存器中,从AVALUE得知W不在内存单元,且已知W是活跃变量,因此,需要生成目标代码MOV W,R0。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。