编程语言详细课程-课件12_第1页
编程语言详细课程-课件12_第2页
编程语言详细课程-课件12_第3页
编程语言详细课程-课件12_第4页
编程语言详细课程-课件12_第5页
已阅读5页,还剩113页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第八章代码生成本章内容一个简单的代码生成算法涉及存储管理,指令选择,寄存器分配和计算次序选择等基本问题前端代码优化器中间代码源程序代码生成器中间代码目标程序第八章代码生成本章内容前端代码中间源程序18.1

代码生成器的设计中的问题8.1.1

目标程序可执行目标模块可重定位目标模块允许程序模块分别编译调用其它先前编译好的程序模块汇编语言程序免去编译器重复汇编器的工作从教学角度,增加可读性8.1代码生成器的设计中的问题8.1.1目标程序28.1

代码生成器的设计中的问题8.1.2

指令的选择 目标机器指令系统的性质决定了指令选择的难易程度,指令系统的统一性和完备性是重要的因素 指令的速度和机器特点是另一些重要的因素8.1代码生成器的设计中的问题8.1.2指令的选择38.1

代码生成器的设计中的问题 若不考虑目标程序的效率,指令的选择是直截了当的三地址语句x=y+z(x,y和z都是静态分配)

MOV y, R0 /

把y装入寄存器R0/ ADD z, R0 /z加到R0上/ MOV R0, x /

把R0存入x中/逐个语句地产生代码,常常得到低质量的代码

8.1代码生成器的设计中的问题 若不考虑目标程序的效率,指48.1

代码生成器的设计中的问题语句序列

a=b+c d=a+e的代码如下MOV b, R0ADD c, R0MOV R0, aMOV a, R0ADD e, R0 MOV R0, d 8.1代码生成器的设计中的问题语句序列 a=b+58.1

代码生成器的设计中的问题语句序列

a=b+c d=a+e的代码如下MOV b, R0ADD c, R0MOV R0, aMOV a, R0 --多余的指令ADD e, R0 MOV R0, d 8.1代码生成器的设计中的问题语句序列 a=b+68.1

代码生成器的设计中的问题语句序列

a=b+c d=a+e的代码如下MOV b, R0ADD c, R0MOV R0, aMOV a, R0 --多余的指令ADD e, R0 --若a不再使用,第三条也MOV R0, d --多余8.1代码生成器的设计中的问题语句序列 a=b+78.1

代码生成器的设计中的问题8.1.3寄存器分配 运算对象处于寄存器中的指令通常比运算对象处于内存的指令要短一些,执行也快一些寄存器分配

选择驻留在寄存器中的一组变量寄存器指派

挑选变量要驻留的具体寄存器8.1代码生成器的设计中的问题8.1.3寄存器分配88.1

代码生成器的设计中的问题8.1.4计算次序的选择 某种计算次序可能会比其它次序需要较少的寄存器来保存中间结果8.1代码生成器的设计中的问题8.1.4计算次序的选择98.2

目标机器8.2.1目标机器的指令系统选择可作为几种微机代表的寄存器机器四字节组成一个字,有n个通用寄存器R0,R1,…,Rn-1。二地址指令

op 源,目的 MOV {源传到目的} ADD {源加到目的} SUB {目的减去源}8.2目标机器8.2.1目标机器的指令系统108.2

目标机器地址模式和它们的汇编语言形式及附加代价模式 形式 地址 附加代价绝对地址 M M 1寄存器 R R 0变址 c(R) c+contents(R) 1间接寄存器R contents(R) 0间接变址

c(R) contents(c+contents(R))1直接量 #c c 1

8.2目标机器地址模式和它们的汇编语言形式及118.2

目标机器指令实例

MOV R0, M

MOV 4(R0), M

contents(4+contents(R0)) MOV 4(R0), M

contents(contents(4+contents(R0)))

MOV #1, R08.2目标机器指令实例128.2

目标机器8.2.2指令的代价 指令代价取成1加上它的源和目的地址模式的附加代价 指令 代价

MOVR0,R1 1

MOVR5,M 2

ADD#1, R3 2

SUB4(R0),12(R1) 38.2目标机器8.2.2指令的代价138.2

目标机器a=b+c, a、b和c都静态分配内存单元 MOVb,R0 ADDc,R0 代价=6 MOVR0,a8.2目标机器a=b+c, a、b和148.2

目标机器a=b+c, a、b和c都静态分配内存单元 MOVb,R0 ADDc,R0 代价=6 MOVR0,a MOVb,a ADDc,a 代价=68.2目标机器a=b+c, a、b和158.2

目标机器a=b+c, a、b和c都静态分配内存单元若R0,R1和R2分别含a,b和c的地址,则 MOVR1,R0 ADDR2,R0 代价=28.2目标机器a=b+c, a、b和168.2

目标机器a=b+c, a、b和c都静态分配内存单元若R0,R1和R2分别含a,b和c的地址,则 MOVR1,R0 ADDR2,R0 代价=2若R1和R2分别含b和c的值,并且b的值在这个赋值后不再需要,则 ADDR2,R1 MOVR1,a 代价=38.2目标机器a=b+c, a、b和178.3

基本块和流图怎样为三地址语句序列生成目标代码? |(1) prod=0 prod=0; |(2) i=1 i=1; |(3) t1=4i do{ |(4) t2=a[t1] prod=prod+a[i]b[i];|(5) t3=4i i=i+1; |(6) t4=b[t3] }while(i<=20); |(7) t5=t2t4

|(8) t6=prod+t5 |(9) prod=t6 |(10) t7=i+1 |(11) i=t7

|(12) ifi<=20goto(3)8.3基本块和流图怎样为三地址语句序列生成目标代码?188.3

基本块和流图8.3.1基本块基本块:连续的语句序列,控制流从它的开始进入,并从它的末尾离开再用有向边表示基本块之间的控制流信息,就能得到程序的流图8.3基本块和流图8.3.1基本块198.3

基本块和流图三地址语句序列的划分基本块首先确定所有的入口语句序列的第一个语句是入口语句能由条件转移语句或无条件转移语句转到的语句是入口语句紧跟在条件转移语句或无条件转移语句后面的语句是入口语句每个入口语句到下一个入口语句之前的语句序列构成一个基本块

8.3基本块和流图三地址语句序列的划分基本块208.3

基本块和流图(1) prod=0(2) i=1(3) t1=4i(4) t2=a[t1](5) t3=4i(6) t4=b[t3](7) t5=t2t4

(8) t6=prod+t5(9) prod=t6(10) t7=i+1(11) i=t7(12) ifi<=20goto(3)(1)prod=0(2)i=1(3)t1=4i(4)t2=a[t1](5)t3=4i(6)t4=b[t3](7)t5=t2t4(8)t6=prod+t5(9)prod=t6(10)t7=i+1(11)i=t7(12)ifi<=20goto(3)B1B28.3基本块和流图(1) prod=0(1)prod218.3

基本块和流图8.3.2基本块的优化三地址语句x=y+z引用y和z并对x定值一个名字的值在基本块的某一点以后还要引用的话,则说这个名字在该点是活跃的基本块的等价两个基本块计算一组同样的表达式这些表达式的值分别代表同样的活跃名字的值有很多等价变换可用于基本块局部变换全局变换8.3基本块和流图8.3.2基本块的优化228.3

基本块和流图删除局部公共子表达式 a=b+c a=b+c b=ad b=ad c=b+c c=b+c d=ad d=b删除死代码定值x=y+z以后不再引用,则称x为死变量8.3基本块和流图删除局部公共子表达式238.3

基本块和流图交换相邻的独立语句 t1=b

+c t2=x

+y t2=x

+y t1=b

+c当且仅当t1和t2不相同,x和y都不是t1,

并且b和c都不是t2

代数变换 x=x+0 可以删除

x=x1 可以删除

x=y2 改成x=yy8.3基本块和流图交换相邻的独立语句248.3

基本块和流图8.3.3流图 把控制流信息加到基本块集合,形成一个有向图来表示程序

首结点、前驱、后继8.3基本块和流图8.3.3流图258.3

基本块和流图什么是循环?所有结点是强连通的唯一的循环入口外循环和内循环prod=0i=1t1=4it2=a[t1]t3=4it4=b[t3]t5=t2t4t6=prod+t5prod=t6t7=i+1i=t7ifi<=20gotoB2B1B28.3基本块和流图什么是循环?prod=0t1=4268.3

基本块和流图8.3.4下次引用信息 为每个三地址语句x=yopz决定x、y和z的下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x8.3基本块和流图8.3.4下次引用信息278.3

基本块和流图8.3.4下次引用信息 为每个三地址语句x=yopz决定x、y和z的下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x8.3基本块和流图8.3.4下次引用信息288.3

基本块和流图对每个基本块从最后一个语句反向扫描到第一个语句,可以得到下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x8.3基本块和流图对每个基本块从最后一个语句反向扫描到第一298.3

基本块和流图对每个基本块从最后一个语句反向扫描到第一个语句,可以得到下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x利用下次引用信息,可以压缩临时变量需要的空间8.3基本块和流图对每个基本块从最后一个语句反向扫描到第一308.4

一个简单的代码生成器依次考虑基本块的每个语句,为其产生代码假定三地址语句的每种算符都有对应的目标机器算符假定计算结果留在寄存器中尽可能长的时间,

除非:该寄存器要用于其它计算,或者到基本块结束8.4一个简单的代码生成器依次考虑基本块的每个语句,为其产318.4

一个简单的代码生成器在没有收集全局信息前,暂且以基本块为单位来生成代码prod=0i=1t1=4it2=a[t1]t3=4it4=b[t3]t5=t2t4t6=prod+t5prod=t6t7=i+1i=t7ifi<=20gotoB2B1B28.4一个简单的代码生成器在没有收集全局信息prod=328.4

一个简单的代码生成器8.4.1寄存器描述和地址描述例:对a=b+c如果寄存器Ri含b,Rj含c,且b此后不再活跃产生ADDRj,Ri,结果a在Ri中如果Ri含b,但c在内存单元,b仍然不再活跃产生ADDc,Ri,或者MOVc,Rj ADDRj,Ri若c的值以后还要用,第二种代码比较有吸引力8.4一个简单的代码生成器8.4.1寄存器描述和地址描述338.4

一个简单的代码生成器在代码生成过程中,需要跟踪寄存器的内容和名字的地址寄存器描述记住每个寄存器当前存的是什么在任何一点,每个寄存器保存若干个(包括零个)名字的值名字的地址描述记住运行时每个名字的当前值可以在哪个场所找到这个场所可以是寄存器、栈单元、内存地址、甚至是它们的某个集合这些信息可以存于符号表中这两个描述在代码生成过程中是变化的8.4一个简单的代码生成器在代码生成过程中,需要跟踪寄存器348.4

一个简单的代码生成器8.4.2

代码生成算法对每个三地址语句x=yopz调用函数getreg决定放yopz计算结果的场所L查看y的地址描述,确定y值当前的一个场所y.如果y的值还不在L中,产生指令MOVy,L产生指令opz,L,其中z是z的当前场所之一如果y和/或z的当前值不再引用,在块的出口也不活跃,并且还在寄存器中,那么修改寄存器描述8.4一个简单的代码生成器8.4.2代码生成算法358.4

一个简单的代码生成器8.4.3

寄存器选择函数函数getreg返回保存x=yopz的x值的场所L如果名字y在R中,这个R不含其它名字的值,并且在执行x=yopz后y不再有下次引用,那么返回这个R作为L否则,返回一个空闲寄存器,如果有的话否则,如果x在块中有下次引用,或者op是必须用寄存器的算符,那么找一个已被占用的寄存器R(可能产生MOVR,M指令,并修改M的描述)否则,如果x在基本块中不再引用,或者找不到适当的被占用寄存器,选择x的内存单元作为L8.4一个简单的代码生成器8.4.3寄存器选择函数368.4

一个简单的代码生成器赋值语句d=(ab)+(ac)+(ac)编译产生三地址语句序列: t1=ab t2=ac t3=t1+t2 d=t3+t2

8.4一个简单的代码生成器赋值语句d=(ab)378.4

一个简单的代码生成器语

生成的代码

寄存器描述名字地址描述

寄存器空

t1=ab

MOVa,R0SUBb,R0

R0含t1

t1在R0中

t2=acMOVa,R1SUBc,R1R0含t1R1含t2t1在R0中t2在R1中t3=t1+t2

ADDR1,R0

R0含t3

R1含t2

t3在R0中t2在R1中

d=t3+t2

ADDR1,R0

R0含dd在R0中

MOVR0,d

d在R0和内存中

8.4一个简单的代码生成器语句生成的代码寄存器描述388.4

一个简单的代码生成器前三条指令可以修改,使执行代价降低MOVa,R0 MOVa,R0SUBb,R0 MOVR0,R1MOVa,R1 SUBb,R0SUBc,R1 SUBc,R1... ...8.4一个简单的代码生成器前三条指令可以修改,使执行代价降398.4

一个简单的代码生成器8.4.4

为变址和指针语句产生代码 变址与指针运算的三地址语句的处理和二元算符的处理相同8.4一个简单的代码生成器8.4.4为变址和指针语句产生408.4

一个简单的代码生成器8.4.5

条件语句实现条件转移有两种方式根据寄存器的值是否为下面六个条件之一进行分支:负、零、正、非负、非零和非正用条件码来表示计算的结果或装入寄存器的值是负、零还是正8.4一个简单的代码生成器8.4.5条件语句418.4

一个简单的代码生成器根据寄存器的值是否为下面六个条件之一进行分支:负、零、正、非负、非零和非正例如:ifx<ygotoz把x减y的值存入寄存器R如果R的值为负,则跳到z8.4一个简单的代码生成器根据寄存器的值是否为下面六个条件428.4

一个简单的代码生成器用条件码的例子ifx<ygotoz x=y+w的实现: ifx<0gotozCMP x, y 的实现:CJ< z MOV y, R0 ADD w, R0 MOV R0,x CJ< z8.4一个简单的代码生成器用条件码的例子43本章要点代码生成器设计中的主要问题:存储管理、计算次序的选择、寄存器的分配、指令的选择等目标机器几种常用的地址模式和一些常用的指令基本块和程序流图简单的代码生成算法本章要点代码生成器设计中的主要问题:存储管44例题1在SPARC/SUNOS上,经某编译器编译,程序的结果是120。把第4行的abs(1)改成1的话,则程序结果是1intfact(){ staticinti=5; if(i==0){return(1);} else{i=i-1;return((i+abs(1))

fact());}}main(){ printf("factorof5=%d\n",fact());}例题1在SPARC/SUNOS上,经某编译器编译45例题2下面的程序在X86/Linux机器上编译后的运行结果是7,而在SPARC/SUNOS机器上编译后的运行结果是6。试分析运行结果不同的原因。main(){ longi; i=0; printf("%ld\n",(++i)+(++i)+(++i));}例题2下面的程序在X86/Linux机器上编译后46例题2按一般的代码生成,i=i+1的计算结果保留在寄存器中,因此这三个i=i+1的计算次序不会影响最终的结果。结果应该是6。++===ii+1ii+1ii+1例题2按一般的代码生成,i=i+1的计算结47例题2按一般的代码生成,i=i+1的计算结果保留在寄存器中,因此这三个i=i+1的计算次序不会影响最终的结果。结果应该是6。结果是7的话,一定是某个i=i+1的结果未保留在寄存器中。上层计算对它的引用落在计算另一个i=i+1的后面

++===ii+1ii+1ii+1例题2按一般的代码生成,i=i+1的计算结48例题2如果机器有INC指令的话,编译器极可能产生一条INC指令来完成i=i+1X86/Linux机器上果真是这么做的

++===ii+1ii+1ii+1例题2如果机器有INC指令的话,编译器极可能产生49例题2将表达式改成(++i)+((++i)+(++i)),结果会怎样?++===ii+1ii+1ii+1例题2将表达式改成(++i)+((++i)+(+50例题2将表达式改成(++i)+((++i)+(++i)),结果会怎样?在SPARC/SUNOS机器上的结果仍然是6。在X86/Linux机器上的结果是9。++===ii+1ii+1ii+1例题2将表达式改成(++i)+((++i)+(+51例题3下面C语言程序如下,运行时输出105,为什么?main(){ longi;

i=10; i=(i+5)+(i=i5);

printf("%d\n",i);}例题3下面C语言程序如下,运行时输出105,52例题3下面C语言程序如下,运行时输出105,为什么?main(){ longi;

i=10; i=(i+5)+(i=i5);

printf("%d\n",i);}二元运算

表达式

表达式

需2个R

需3个R

需几个R

例题3下面C语言程序如下,运行时输出105,53例题4

下面是一个C语言程序和在X86/Linux机器上编译(未使用优化)该程序得到的汇编代码见下页(为便于理解,略去了和讨论本问题无关的部分,并改动了一个地方)main(){ longi,j; if(j) i++; else while(i)j++;}例题4 下面是一个C语言程序和在X86/Linu54例题4main() incl-4(%ebp)

{ jmp.L3

longi,j; .L2:.L4:(写在一行以省空间)if(j) cmpl$0,-4(%ebp) i++; jne.L6else jmp.L5 while(i)j++; .L6:} incl-8(%ebp)

pushl%ebp

jmp.L4

movl%esp,%ebp

.L5:.L3:.L1: subl$8,%esp

leave

cmpl$0,-8(%ebp)

ret

je.L2

例题4main() incl-4(%eb55例题4为什么会出现一条指令前有多个标号的情况,如.L2和.L4,还有.L5、.L3和.L1?从控制流语句的中间代码结构加以解释。条件语句和循环语句的中间代码结构如下:

if(E)thenS1elseS2 while(E)doS E的代码 L4: E的代码 假转L2 真转L6 S1的代码 转L5

转L3 L6: S的代码

L2: S2的代码 转L4 L3: L5:当while语句作为条件语句的S2时,会出现所说情况例题4为什么会出现一条指令前有多个标号的情况,如56例题4每个函数都有这样的标号.L1,它的作用是什么,为什么本函数没有引用该标号的地方?例题4每个函数都有这样的标号.L1,它的作用是什57例题4每个函数都有这样的标号.L1,它的作用是什么,为什么本函数没有引用该标号的地方?.L1标号定义的入口是返回调用者时该执行的指令,在函数内部有return语句时就会跳转到.L1。

例题4每个函数都有这样的标号.L1,它的作用是什58习题第一次:8.4(只为8.1(e)生成代码)习题第一次:8.4(只为8.1(e)生成代码59第八章代码生成本章内容一个简单的代码生成算法涉及存储管理,指令选择,寄存器分配和计算次序选择等基本问题前端代码优化器中间代码源程序代码生成器中间代码目标程序第八章代码生成本章内容前端代码中间源程序608.1

代码生成器的设计中的问题8.1.1

目标程序可执行目标模块可重定位目标模块允许程序模块分别编译调用其它先前编译好的程序模块汇编语言程序免去编译器重复汇编器的工作从教学角度,增加可读性8.1代码生成器的设计中的问题8.1.1目标程序618.1

代码生成器的设计中的问题8.1.2

指令的选择 目标机器指令系统的性质决定了指令选择的难易程度,指令系统的统一性和完备性是重要的因素 指令的速度和机器特点是另一些重要的因素8.1代码生成器的设计中的问题8.1.2指令的选择628.1

代码生成器的设计中的问题 若不考虑目标程序的效率,指令的选择是直截了当的三地址语句x=y+z(x,y和z都是静态分配)

MOV y, R0 /

把y装入寄存器R0/ ADD z, R0 /z加到R0上/ MOV R0, x /

把R0存入x中/逐个语句地产生代码,常常得到低质量的代码

8.1代码生成器的设计中的问题 若不考虑目标程序的效率,指638.1

代码生成器的设计中的问题语句序列

a=b+c d=a+e的代码如下MOV b, R0ADD c, R0MOV R0, aMOV a, R0ADD e, R0 MOV R0, d 8.1代码生成器的设计中的问题语句序列 a=b+648.1

代码生成器的设计中的问题语句序列

a=b+c d=a+e的代码如下MOV b, R0ADD c, R0MOV R0, aMOV a, R0 --多余的指令ADD e, R0 MOV R0, d 8.1代码生成器的设计中的问题语句序列 a=b+658.1

代码生成器的设计中的问题语句序列

a=b+c d=a+e的代码如下MOV b, R0ADD c, R0MOV R0, aMOV a, R0 --多余的指令ADD e, R0 --若a不再使用,第三条也MOV R0, d --多余8.1代码生成器的设计中的问题语句序列 a=b+668.1

代码生成器的设计中的问题8.1.3寄存器分配 运算对象处于寄存器中的指令通常比运算对象处于内存的指令要短一些,执行也快一些寄存器分配

选择驻留在寄存器中的一组变量寄存器指派

挑选变量要驻留的具体寄存器8.1代码生成器的设计中的问题8.1.3寄存器分配678.1

代码生成器的设计中的问题8.1.4计算次序的选择 某种计算次序可能会比其它次序需要较少的寄存器来保存中间结果8.1代码生成器的设计中的问题8.1.4计算次序的选择688.2

目标机器8.2.1目标机器的指令系统选择可作为几种微机代表的寄存器机器四字节组成一个字,有n个通用寄存器R0,R1,…,Rn-1。二地址指令

op 源,目的 MOV {源传到目的} ADD {源加到目的} SUB {目的减去源}8.2目标机器8.2.1目标机器的指令系统698.2

目标机器地址模式和它们的汇编语言形式及附加代价模式 形式 地址 附加代价绝对地址 M M 1寄存器 R R 0变址 c(R) c+contents(R) 1间接寄存器R contents(R) 0间接变址

c(R) contents(c+contents(R))1直接量 #c c 1

8.2目标机器地址模式和它们的汇编语言形式及708.2

目标机器指令实例

MOV R0, M

MOV 4(R0), M

contents(4+contents(R0)) MOV 4(R0), M

contents(contents(4+contents(R0)))

MOV #1, R08.2目标机器指令实例718.2

目标机器8.2.2指令的代价 指令代价取成1加上它的源和目的地址模式的附加代价 指令 代价

MOVR0,R1 1

MOVR5,M 2

ADD#1, R3 2

SUB4(R0),12(R1) 38.2目标机器8.2.2指令的代价728.2

目标机器a=b+c, a、b和c都静态分配内存单元 MOVb,R0 ADDc,R0 代价=6 MOVR0,a8.2目标机器a=b+c, a、b和738.2

目标机器a=b+c, a、b和c都静态分配内存单元 MOVb,R0 ADDc,R0 代价=6 MOVR0,a MOVb,a ADDc,a 代价=68.2目标机器a=b+c, a、b和748.2

目标机器a=b+c, a、b和c都静态分配内存单元若R0,R1和R2分别含a,b和c的地址,则 MOVR1,R0 ADDR2,R0 代价=28.2目标机器a=b+c, a、b和758.2

目标机器a=b+c, a、b和c都静态分配内存单元若R0,R1和R2分别含a,b和c的地址,则 MOVR1,R0 ADDR2,R0 代价=2若R1和R2分别含b和c的值,并且b的值在这个赋值后不再需要,则 ADDR2,R1 MOVR1,a 代价=38.2目标机器a=b+c, a、b和768.3

基本块和流图怎样为三地址语句序列生成目标代码? |(1) prod=0 prod=0; |(2) i=1 i=1; |(3) t1=4i do{ |(4) t2=a[t1] prod=prod+a[i]b[i];|(5) t3=4i i=i+1; |(6) t4=b[t3] }while(i<=20); |(7) t5=t2t4

|(8) t6=prod+t5 |(9) prod=t6 |(10) t7=i+1 |(11) i=t7

|(12) ifi<=20goto(3)8.3基本块和流图怎样为三地址语句序列生成目标代码?778.3

基本块和流图8.3.1基本块基本块:连续的语句序列,控制流从它的开始进入,并从它的末尾离开再用有向边表示基本块之间的控制流信息,就能得到程序的流图8.3基本块和流图8.3.1基本块788.3

基本块和流图三地址语句序列的划分基本块首先确定所有的入口语句序列的第一个语句是入口语句能由条件转移语句或无条件转移语句转到的语句是入口语句紧跟在条件转移语句或无条件转移语句后面的语句是入口语句每个入口语句到下一个入口语句之前的语句序列构成一个基本块

8.3基本块和流图三地址语句序列的划分基本块798.3

基本块和流图(1) prod=0(2) i=1(3) t1=4i(4) t2=a[t1](5) t3=4i(6) t4=b[t3](7) t5=t2t4

(8) t6=prod+t5(9) prod=t6(10) t7=i+1(11) i=t7(12) ifi<=20goto(3)(1)prod=0(2)i=1(3)t1=4i(4)t2=a[t1](5)t3=4i(6)t4=b[t3](7)t5=t2t4(8)t6=prod+t5(9)prod=t6(10)t7=i+1(11)i=t7(12)ifi<=20goto(3)B1B28.3基本块和流图(1) prod=0(1)prod808.3

基本块和流图8.3.2基本块的优化三地址语句x=y+z引用y和z并对x定值一个名字的值在基本块的某一点以后还要引用的话,则说这个名字在该点是活跃的基本块的等价两个基本块计算一组同样的表达式这些表达式的值分别代表同样的活跃名字的值有很多等价变换可用于基本块局部变换全局变换8.3基本块和流图8.3.2基本块的优化818.3

基本块和流图删除局部公共子表达式 a=b+c a=b+c b=ad b=ad c=b+c c=b+c d=ad d=b删除死代码定值x=y+z以后不再引用,则称x为死变量8.3基本块和流图删除局部公共子表达式828.3

基本块和流图交换相邻的独立语句 t1=b

+c t2=x

+y t2=x

+y t1=b

+c当且仅当t1和t2不相同,x和y都不是t1,

并且b和c都不是t2

代数变换 x=x+0 可以删除

x=x1 可以删除

x=y2 改成x=yy8.3基本块和流图交换相邻的独立语句838.3

基本块和流图8.3.3流图 把控制流信息加到基本块集合,形成一个有向图来表示程序

首结点、前驱、后继8.3基本块和流图8.3.3流图848.3

基本块和流图什么是循环?所有结点是强连通的唯一的循环入口外循环和内循环prod=0i=1t1=4it2=a[t1]t3=4it4=b[t3]t5=t2t4t6=prod+t5prod=t6t7=i+1i=t7ifi<=20gotoB2B1B28.3基本块和流图什么是循环?prod=0t1=4858.3

基本块和流图8.3.4下次引用信息 为每个三地址语句x=yopz决定x、y和z的下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x8.3基本块和流图8.3.4下次引用信息868.3

基本块和流图8.3.4下次引用信息 为每个三地址语句x=yopz决定x、y和z的下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x8.3基本块和流图8.3.4下次引用信息878.3

基本块和流图对每个基本块从最后一个语句反向扫描到第一个语句,可以得到下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x8.3基本块和流图对每个基本块从最后一个语句反向扫描到第一888.3

基本块和流图对每个基本块从最后一个语句反向扫描到第一个语句,可以得到下次引用信息

i: x=yopz ... 没有对x的赋值

j: …=x…... 没有对x的赋值

k: …=…x利用下次引用信息,可以压缩临时变量需要的空间8.3基本块和流图对每个基本块从最后一个语句反向扫描到第一898.4

一个简单的代码生成器依次考虑基本块的每个语句,为其产生代码假定三地址语句的每种算符都有对应的目标机器算符假定计算结果留在寄存器中尽可能长的时间,

除非:该寄存器要用于其它计算,或者到基本块结束8.4一个简单的代码生成器依次考虑基本块的每个语句,为其产908.4

一个简单的代码生成器在没有收集全局信息前,暂且以基本块为单位来生成代码prod=0i=1t1=4it2=a[t1]t3=4it4=b[t3]t5=t2t4t6=prod+t5prod=t6t7=i+1i=t7ifi<=20gotoB2B1B28.4一个简单的代码生成器在没有收集全局信息prod=918.4

一个简单的代码生成器8.4.1寄存器描述和地址描述例:对a=b+c如果寄存器Ri含b,Rj含c,且b此后不再活跃产生ADDRj,Ri,结果a在Ri中如果Ri含b,但c在内存单元,b仍然不再活跃产生ADDc,Ri,或者MOVc,Rj ADDRj,Ri若c的值以后还要用,第二种代码比较有吸引力8.4一个简单的代码生成器8.4.1寄存器描述和地址描述928.4

一个简单的代码生成器在代码生成过程中,需要跟踪寄存器的内容和名字的地址寄存器描述记住每个寄存器当前存的是什么在任何一点,每个寄存器保存若干个(包括零个)名字的值名字的地址描述记住运行时每个名字的当前值可以在哪个场所找到这个场所可以是寄存器、栈单元、内存地址、甚至是它们的某个集合这些信息可以存于符号表中这两个描述在代码生成过程中是变化的8.4一个简单的代码生成器在代码生成过程中,需要跟踪寄存器938.4

一个简单的代码生成器8.4.2

代码生成算法对每个三地址语句x=yopz调用函数getreg决定放yopz计算结果的场所L查看y的地址描述,确定y值当前的一个场所y.如果y的值还不在L中,产生指令MOVy,L产生指令opz,L,其中z是z的当前场所之一如果y和/或z的当前值不再引用,在块的出口也不活跃,并且还在寄存器中,那么修改寄存器描述8.4一个简单的代码生成器8.4.2代码生成算法948.4

一个简单的代码生成器8.4.3

寄存器选择函数函数getreg返回保存x=yopz的x值的场所L如果名字y在R中,这个R不含其它名字的值,并且在执行x=yopz后y不再有下次引用,那么返回这个R作为L否则,返回一个空闲寄存器,如果有的话否则,如果x在块中有下次引用,或者op是必须用寄存器的算符,那么找一个已被占用的寄存器R(可能产生MOVR,M指令,并修改M的描述)否则,如果x在基本块中不再引用,或者找不到适当的被占用寄存器,选择x的内存单元作为L8.4一个简单的代码生成器8.4.3寄存器选择函数958.4

一个简单的代码生成器赋值语句d=(ab)+(ac)+(ac)编译产生三地址语句序列: t1=ab t2=ac t3=t1+t2 d=t3+t2

8.4一个简单的代码生成器赋值语句d=(ab)968.4

一个简单的代码生成器语

生成的代码

寄存器描述名字地址描述

寄存器空

t1=ab

MOVa,R0SUBb,R0

R0含t1

t1在R0中

t2=acMOVa,R1SUBc,R1R0含t1R1含t2t1在R0中t2在R1中t3=t1+t2

ADDR1,R0

R0含t3

R1含t2

t3在R0中t2在R1中

d=t3+t2

ADDR1,R0

R0含dd在R0中

MOVR0,d

d在R0和内存中

8.4一个简单的代码生成器语句生成的代码寄存器描述978.4

一个简单的代码生成器前三条指令可以修改,使执行代价降低MOVa,R0 MOVa,R0SUBb,R0 MOVR0,R1MOVa,R1 SUBb,R0SUBc,R1 SUBc,R1... ...8.4一个简单的代码生成器前三条指令可以修改,使执行代价降988.4

一个简单的代码生成器8.4.4

为变址和指针语句产生代码 变址与指针运算的三地址语句的处理和二元算符的处理相同8.4一个简单的代码生成器8.4.4为变址和指针语句产生998.4

一个简单的代码生成器8.4.5

条件语句实现条件转移有两种方式根据寄存器的值是否为下面六个条件之一进行分支:负、零、正、非负、非零和非正用条件码来表示计算的结果或装入寄存器的值是负、零还是正8.4一个简单的代码生成器8.4.5条件语句1008.4

一个简单的代码生成器根据寄存器的值是否为下面六个条件之一进行分支:负、零、正、非负、非零和非正例如:ifx<ygotoz把x减y的值存入寄存器R如果R的值为负,则跳到z8.4一个简单的代码生成器根据寄存器的值是否为下面六个条件1018.4

一个简单的代码生成器用条件码的例子ifx<ygotoz x=y+w的实现: ifx<0gotozCMP x, y 的实现:CJ< z MOV y, R0 ADD w, R0 MOV R0,x CJ< z8.4一个简单的代码生成器用条件码的例子102本章要点代码生成器设计中的主要问题:存储管理、计算次序的选择、寄存器的分配、指令的选择等目标机器几种常用的地址模式和一些常用的指令基本块和程序流图简单的代码生成算法本章要点代码生成器设计中的主要问题:存储管103例题1在SPARC/SUNOS上,经某编译器编译,程序的结果是120。把第4行的abs(1)改成1的话,则程序结果是1intfact(){ staticinti=5; if(i==0){return(1);} else{i=i-1;return((i+abs(1))

fact());}}main(){ printf("factorof5=%d\n",fact());}例题1在SPARC/SUNOS上,经某编译器编译104例题2下面的程序在X86/Linux机器上编译后的运行结果是7,而在SPARC/SUNOS机器上编译后的运行结果是6。试分析运行结果不同的原因。main(){ longi; i=0; printf("%ld\n",(++i)+(++i)+(++i));}例题2下面的程序在X86/Linux机器上编译后105例题2按一般的代码生成,i=i+1的计算结果保留在寄存器中,因此这三个i=

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论