编译原理清华第十二章代码生成.ppt
第12章 代码生成,学习目标掌握:基本块代码生成算法,寄存器分配算法理解:待用信息,活跃信息,12.1代码生成概述12.2一个计算机模型12.3一个简单的代码生成器,12.1 代码生成概述,代码生成的任务把中间代码(经过优化或未经过优化)作为输入,将其转换成特定机器的机器语言或汇编语言作为输出,这样的转换程序称为代码生成器(Code Generator)。目标代码生成需要考虑的基本问题:如何使生成的目标代码较短如何充分利用计算机的寄存器,减少目标代码访问存储单元的次数,目标代码生成的一些共同的问题,而不讨论某个特定机器的代码生成问题寄存器分配算法目标代码的执行效率很大程度依赖于寄存器的使用;基本块的代码生成算法寄存器分配算法仅限定在一个基本块的范围内,以四元式的中间代码作为输入,以一个称作M的模型机的汇编语言作为输出。,12.2 一个计算机模型,M模型机具有n个通用寄存器R1,R2,R3,Rn,它们既可以作为累加器,又可以作为变址器。约定:op表示运算,C表示常量;M表示内存单元(用变量名表示该变量所在的单元),Ri表示寄存器;*表示间接寻址,指令系统与寻址方式令X代表Ri或者M,则(X)表示直接取X的内容作为操作对象,(X)表示一层间接,即取X的内容作为地址,特殊指令除了上述的寻址方式和一般的运算指令之外,计算机模型的指令系统中还包括如下特殊指令主要有两大类:内存与寄存器交换类:包括LD与ST;比较与转移类:如CMP与J X,意义,指令,意义,指令,例:条件语句 if AB goto X中间代码:(J,A,B,X)目标代码:CMP A,BJ X,12.3 一个简单的代码生成器,一个基于基本块的代码生成器它的输入是四元式中间代码,输出是M机器的汇编代码着重讨论在基本块内如何充分利用寄存器,12.3.1 寄存器分配原则,在指令的执行代价中,寄存器的代价是最小的,因此总是希望将尽可能多的运算对象放在寄存器中;由于任何一个计算机模型中的寄存器个数都是有限的,因而需要根据一些原则,对寄存器进行分配,基于基本块的寄存器分配的一般原则:当生成某变量的目标代码时,尽量让变量的值或中间结果保留在寄存器中,直到寄存器不够分配为止,这样引用变量值时可减少对内存的存取次数,提高运行速度进入基本块时所有寄存器是空闲的,当到基本块出口时,将变量的有用值存回内存,释放所有寄存器在基本块内,后边不再被引用的变量占用的寄存器应尽早释放,以提高寄存器的利用效率,12.3.2 待用信息链表法,引入原因:为了把在基本块内还要被引用的变量值尽可能保存在寄存器中,不再被引用的变量所占的寄存器尽早释放,在翻译四元式 i:A:=B op C时,必须知道变量A,B,C在基本块内其后的引用情况,即所谓变量的待用信息。,基本定义:定值、引用、活跃在形如 i:A:=B+C 的代码中,出现在“:=”左边和右边的变量,分别被称为对变量的定值和引用,i被称为变量的定值点或引用点。若变量的值在i之后的代码序列中被引用,则称变量在i点是活跃的。待用信息在基本块中,变量A在四元式i中被定值,在i后面的四元式j中引用A值,且从i到j之间没有其他对A的定值点,称j是i中对变量A的待用信息(下次引用信息)。所有这样的待用信息jk(k=1,2,)构成待用信息链。,只在基本块内考虑待用信息,一个变量在基本块的后继中是否被引用,可从活跃变量信息得知(出基本块后,变量是否活跃需要进行全局的数据流分析才能确定),在基本块B2内:R在(3)处定值,在(4)处被引用,所以(4)是(3)中R的待用信息流程B3-B2:X在(5)处被定值,在(3)处被引用,所以X在(5)处是活跃的,基本块内求待用信息的算法假设符号表中含有变量的待用信息和活跃信息栏;四元式表上也有关于结果变量、左右操作数变量的待用和活跃信息栏。把基本块中各变量在符号表的登记项中的待用信息栏置为“非待用”,活跃信息栏按变量在基本块出口是否活跃而置为“活跃”或“非活跃”(假定用户变量都是活跃的,临时变量都是非活跃的)。,从基本块出口的四元式开始由后向前依次处理各个四元式 i:A:=B op C,直到处理完为止:把符号表中结果变量A的待用信息和活跃信息附加到四元式i上。把符号表中变量A的待用信息栏和活跃信息栏分别置为“非待用”和“非活跃”。(由于在i中对A的定值只能在i以后引用,而对i以前的四元式来说A是非活跃和非待用的。)把符号表中变量B和C的待用信息和活跃信息附加到四元式i上。把符号表中变量B和C的待用信息栏置为“i”,活跃信息栏置为“活跃”。注意:i,ii,iii,iv的次序不能颠倒,因为B和C也可能是A,求待用信息的实例,有如下基本块(1)T:=A-B(2)U:=A-C(3)V:=T+U(4)D:=V+U,A,B,C,D是用户变量(在基本块出口活跃)T,U,V是临时变量(在基本块出口不活跃)用“F”表示“非待用”“非活跃”,“L”表示“活跃”则该基本块的待用信息及活跃信息的计算结果如下:,(F,L),D:=V+U,4,(4,L),V:=T+U,3,(3,L),U:=A-C,2,(3,L),T:=A-B,1,右操作数,左操作数,结 果,四元式,序号,附加在四元式上的待用及活跃信息,符号表中的待用及活跃信息,(F,F),(1,L),(1,L),(1),(F,F),(4,L),V,(F,F),(3,L),(4,L),U,(3,L),T,(F,F),D,(2,L),C,B,(2,L),A,(2),(3),(4),初值,变量名,12.3.3 代码生成算法,寄存器描述数组RVALUE为了掌握各寄存器的使用情况,用数组RVALUE记录每个寄存器的当前情况:RVALUERi=A 表示Ri的现行值是变量A的值,或说A独占Ri。RVALUERj=表示Rj是空闲的。RVALUERk=B,C 表示Rk的现行值是变量B和C的值,或说B,C共占Rk。在复写(B:C)时存在多个变量共占一个寄存器。,变量地址描述数组AVALUE生成目标代码要用到变量的地址,它可能是某寄存器Ri,也可能是内存单元(仍用变量名表示)。若变量值同时在寄存器Ri和内存,则取Ri为其地址。AVALUEA=Ri 表示变量A的值在Ri中,不在内存。AVALUEB=Rj,B 表示变量B的值在Rj中,又在内存。AVALUEC=C 表示变量C的值只在内存。,寄存器分配函数GETREG以形如 i:A:B op C 的四元式为输入,返回一个寄存器R,用以存放A的结果值其算法为:如果B独占Ri,且B与A是同一标识符或B值不再引用,则选Ri为R并转(4)如果有空闲Ri,则选Ri为R并转(4)。,释放一个Ri作为R,最好占用Ri的变量值同时在主存中,或在基本块中引用的位置最远。对Ri中不是A(结果变量)的变量M,且其值不在内存,则做如下处理:生成目标代码 ST Ri,M,把变量M的值送入内存修改变量地址描述:如M不是B(左操作数)则AVALUEMM,否则AVALUEMRi,M。修改寄存器描述:删除RVALUERi中的M。给出R,返回通过GETREG(i:A:=B op C)返回的寄存器R用于进行B op C的运算,并把结果(A值)保存在R中。,4.基本块的代码生成算法,开始时所有寄存器都空闲,顺序取出四元式i:A:B op C,按下述算法生成目标代码。到达基本块出口时,若有活跃变量占用寄存器且其值不在内存,则生成存数指令保存其值并释放寄存器。,分配寄存器 R=GETREG(i:A:=B op C)利用地址描述数组AVALUEB和AVALUEC,确定出B和C现行值的存放位置B和C。如果其现行值在寄存器中,则把寄存器取作B和C如果BR则生成目标代码LD R,B;op R,C 否则生成 op R,C,如果B或C为R,则删除AVALUEB或AVALUEC中的R。令AVALUEA=R,RVALUER=A。如果B和C的现行值是“非引用”和“非活跃”,且其值在某个Rk中,则删除RVALUERk中的B或C,删除AVALUEB和AVALUEC中的Rk。,例:假设只有R1和R2两个寄存器利用基本块代码生成算法生成目标代码,ST R1,D,D在R1中,R1含有D,ADD R1,R2,V独占的R1,(4)D:=V+U,V在R1中U在R2中,R1含有VR2含有U,ADD R1,R2,T独占的R1,(3)V:=T+U,T在R1中U在R2中,R1含有TR2含有U,LD R2,ASUB R2,C,空闲的R2,(2)U:=A-C,T在R1中,R1含有T,LD R1,ASUB R1,B,空闲的R1,(1)T:=A-B,AVALUE,RVALUE,目标代码,选取R,四元式,在基本块出口出,D占用R1,且D值不在内存,因此生成 ST R1,D 指令保存D值,然后释放R1。,本章小结以一个假想的机器指令系统为基础,介绍目标代码生成所涉及的共性问题:基本块的代码生成算法寄存器分配算法变量的待用信息和活跃信息,