第七章 目标代码的生成

合集下载

程序设计语言编译原理第三版第7章

程序设计语言编译原理第三版第7章

N→ Є
D →id: T { enter(top(tblptr), , T.type, top(offset)); top(offset):= top(offset) +T.width } 24
§7.2
说明语句
2.含嵌套说明的翻译模式:
(1)语义规则中的操作: Mktable (previous): 创建一张新符号表,并返回指向新表的一个指针; Enter (table, name, type, offset):
(2)置相对地址为当前offset之值, (3)使offset加上该名字所表示的数据对象的域宽。
20
§7.2 说明语句
3. 相应的翻译模式:
PD { offset:=0 } { enter (, T.type,offset);
DD;D
Did:T
offset:=offset+t.width } Tinteger
(0) (1) (2) (3) (4) (5)
(2) (3) (4)
16
§7.1 中间语言
4.间接三元式:便于代码优化处理
方法:间接码表+三元式表
按运算的先后顺序列出有关三元式在三元表中的位置 例: 语句X:=(A+B)*C;Y:=D↑(A+B)的间接三元式表示如下所示: 间接代码 三元式表 (1) (2) (3) (1) (4) (5)
30
已归约串
PLACE
输入串
语义动作
# #X # X:= # X:= # X:= # X:= # X:=
X:= -B*(C+D)# X := -B*(C+D)# X_ -B*(C+D)# X__ B*(C+D)# -B X__B *(C+D)# -E X__B *(C+D)# { E.place:=p=<B>} E1 X_T1 *(C+D)# {E1.place:=newtemp=T1; 生成四元式(1) } … … … … # X:=E*(C X_T1__C +D)# # X:=E*(E1 X_T1__C +D)# { E1.place:=p=<C> } … … … …

第七章 目标代码的生成

第七章 目标代码的生成

第二段代码较优(少用了寄存器)
基于树重写的代码生成

a [ i ] := b 的一个可能的中间表示树
基于树重写的代生成
树重写(Tree Rewriting)规则形如
其中 • replacement 代表树的单个节点 replacement template {cost} = {action}
这一点较难做到,因为执行效率往往与该语句的上下 文以及目标机体系结构(如流水线)有关
指令选择举例
为TAC 语句选择指令模板
假设一个目标机指令系统(一个简单汇编语言)
例 TAC 语句 a:=b+c 可转换为如下代码序列
MOV ADD MOV b, R0 c, R0 R 0, a
/* b 装入寄存器 R0 */ /* c 加到 R0 */ /* 存 R0 到 a */
两遍的通用寄存器分配算法
• 第一遍先假定可用的通用寄存器是无限数量的,完 成指令选择 例如:前面介绍的简单代码生成算法中的 getreg 函数返回一个伪寄存器(不管物理寄存器的个数) • 第二遍将物理寄存器分配到伪寄存器。 物理寄存器数量不足时,会将一些伪寄存器泄露到 (spilled into)内存,图着色算法的核心任务是使 得泄露的伪寄存器数目最少。
T4

T3

T1:=a+b T2:=c+d T3:=e-T2 T4:=T1-T3
T1
+ +
T2
T2:=c+d T3:=e-T2 T1:=a+b T4:=T1-T3
e0 a0 b0 c0 d0
由上述算法从 DAG 生成代码
将上述简单的代码生成算法应用于如下两个基本块

优化和目标代码生成(PPT课件)

优化和目标代码生成(PPT课件)

• 代码优化在整个编译过程的位置
源程序 编译前端 中间代码 中间代码生成 中间代码 目标代码生成 目标程序 中间代码 中间代码优化 目标代码优化
程序员和编译器可能改上程序的位置
源程序 编译前端 中间代码 目标代码生成 目标程序
程序员可以改进 算法,改变循环
编译器可以改进过程调 用、循环和地址计算
编译器可以利用寄存器, 选择指令和窥孔优转换
3
7.1.1 数据类型
类型的合法性检查是判断数据类型是否与上下文的要求一致 数据类型是对该类型数据(变量或常量)的取值是否合法以 及对该类型数据的运算是否合法的一种说明。
4
7.1.2 数据结构
一个程序设计语言如允许使用的数组、记录、字符串、 表、栈等形式的数据结构,在编译程序中应为它们提供相 应的翻译。 为了能对数据结构中的元素进行引用,必须完成从逻辑结 构到能够访问这些数据元素的物理结构的映射。应考虑: 1映射算法相对简单,根据逻辑结构容易计算出物理地址 2从逻辑结构投影到物理结构时,不至于超界或存储溢出 3使用的数据结构承担这种程序设计语言的主要功能 4在这些数据结构定义相关的运算
25
• 指令选择
– 一个编译程序可以看成是一个转换系统,它把源程序转换成 等价的目标代码,也就是说,对源语言种各种语言结构,依 据语义确定相应的目标代码结构,即确定源语言于目标语言 之间的对应关系,确保正确实现语义。显然,能否建立这样 的关系直接影响到编译程序的质量。 – 目标机器指令系统的性质决定了指令选择的难以程度,指令 系统的一致性和完备性直接影响到这种对应关系的建立。如 果目标机器能一致地支持各种数据类型和寻址方式,不需特 别处理例外,这种对应关系的建立就容易得多。 – 指令执行速度和机器特点对产生目标代码的质量也十分重要。 显然,如果指令集合丰富的目标机器对于某种操作可提供集 中处理的时候,应该选择效率高、执行速度快的一种。

AutoLISP Visual LISP教程《第七章》

AutoLISP Visual LISP教程《第七章》

对已编译函数直接引用,而不是引用函数名. ① 对已编译函数直接引用,而不是引用函数名.该功能可提高代码的运行速 度并防止在运行时对函数的重定义. 度并防止在运行时对函数的重定义. 去掉函数名使得已编译代码更安全, ② 去掉函数名使得已编译代码更安全,减少程序的长度和缩短程序的加载时 间. 去掉所有局部变量名并对其直接链接引用,同样使得已编译代码更安全, ③ 去掉所有局部变量名并对其直接链接引用,同样使得已编译代码更安全, 并减小程序的大小和加载程序所用的时间. 并减小程序的大小和加载程序所用的时间.
2. 确定要编译的 确定要编译的LSP源文件 源文件
如果源文件在AutoCAD 支持的搜索路径下 , 可以不包括路径名 . 选择 如果源文件在 AutoCAD 菜 单 Tools→Options , 然 后 打 开 Files 选 项 卡 并 选 取 Support File → Search Path,可设置文件搜索路径. ,可设置文件搜索路径. 例如,已设置文件搜索路径为"d:\user",就可以用表达式(vlisp-compile 例如, 已设置文件搜索路径为 , 就可以用表达式( 'st "sample.lsp")编译驱动器 的"\user1"目录下的文件 编译驱动器D的 目录下的文件"sample.lsp". . 编译驱动器 目录下的文件 如果"d:\user"不是文件搜索路径,那么,在指定源文件时必须包括完整的 如果 不是文件搜索路径,那么, 不是文件搜索路径 路径名,如: 路径名, (vlisp-compile 'st "d:\\user\\example.lsp") 或 (vlisp-compile 'st "d:/user/ example.lsp")

编译原理第三版课后习题答案

编译原理第三版课后习题答案

编译原理第三版课后习题答案编译原理是计算机科学中的一门重要课程,它研究的是如何将高级程序语言转换为机器语言的过程。

而《编译原理》第三版是目前被广泛采用的教材之一。

在学习过程中,课后习题是巩固知识、提高能力的重要环节。

本文将为读者提供《编译原理》第三版课后习题的答案,希望能够帮助读者更好地理解和掌握这门课程。

第一章:引论习题1.1:编译器和解释器有什么区别?答案:编译器将整个源程序转换为目标代码,然后一次性执行目标代码;而解释器则逐行解释源程序,并即时执行。

习题1.2:编译器的主要任务是什么?答案:编译器的主要任务是将高级程序语言转换为目标代码,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等过程。

第二章:词法分析习题2.1:什么是词法分析?答案:词法分析是将源程序中的字符序列划分为有意义的词素(token)序列的过程。

习题2.2:请给出识别下列词素的正则表达式:(1)整数:[0-9]+(2)浮点数:[0-9]+\.[0-9]+(3)标识符:[a-zA-Z_][a-zA-Z_0-9]*第三章:语法分析习题3.1:什么是语法分析?答案:语法分析是将词法分析得到的词素序列转换为语法树的过程。

习题3.2:请给出下列文法的FIRST集和FOLLOW集:S -> aAbA -> cA | ε答案:FIRST(S) = {a}FIRST(A) = {c, ε}FOLLOW(S) = {$}FOLLOW(A) = {b}第四章:语义分析习题4.1:什么是语义分析?答案:语义分析是对源程序进行静态和动态语义检查的过程。

习题4.2:请给出下列文法的语义动作:S -> if E then S1 else S2答案:1. 计算E的值2. 如果E的值为真,则执行S1;否则执行S2。

第五章:中间代码生成习题5.1:什么是中间代码?答案:中间代码是一种介于源代码和目标代码之间的表示形式,它将源代码转换为一种更容易进行优化和转换的形式。

编译原理第七章中间代码生成汇编

编译原理第七章中间代码生成汇编
assign a + a assign + * uminus c b uminus
*
b
*
b
uminus
c
a= b*-c + b*-c
c abc uminus * bc numinus *+ assign
抽象语法树
• 构造赋值语句语法树的语法制导定义: 产生式
S→id = E E→E1 + E2 E→E1 * E2 E→- E1 E→(E1)
• param x1 • param x2 • …… • param x2 • call p, n n表示实参个数。return y中y为过程返回的一个值
– 形如x = y[i]及x[i] = y的索引赋值。
– 形如x = &y, x = *y和*x = y的地址和指针赋值。象形式。 • 这些语句可以以带有操作符和操作数域的记录 来实现。四元式、三元式及间接三元式是三种 这样的表示。
x = y op z
其中,x、y和z是名字,常量或编译器生成的临时变量 op代表任何操作符(定点运算符、浮点运算符、逻辑运算 符等)
• 像x+y*z这样的表达式要翻译为:
T1 = y * z
T2 = x + T1 其中T1 ,T2为编译时产生的临时变量。
三地址语句的类型
• 三地址语句类似于汇编语言代码。语句可以有 符号标号,而且存在各种控制流语句。
– 临时变量也要填入符号表中。
三元式
• 为了避免把临时变量填入符号表,可以通过计 算临时值语句的位置来引用该临时变量。 • 这样三地址代码的记录只需要三个域op, arg1 和arg。
• 对于单目运算符op, arg1和arg2只需用其一。

第七章 语义分析和中间代码产生(第九周)

第七章 语义分析和中间代码产生(第九周)

源语言 程序
Compiler Front End
中间语 言程序
Compiler Back End
目标语 言程序
内容线索

中间语言 说明语句


赋值语句的翻译
布尔表达式的翻译


控制语句的翻译
过程调用的处理
中间语言

常用的中间语言
后缀式,逆波兰表示 图表示

DAG 抽象语法树
三地址代码
7. 2 中间语言
1. 后缀式
后缀式表示法又称逆波兰表示法,是一种表示表达式的 方法,它把运算量(操作数)写在前面,算符写在后面 例:中缀表示: a+b,a+b*c,m=1,(a+b)*c, (a+b)*(c-d) 后缀表示: ab+, abc*+, m1=,ab+c*, ab+cd-* 特点: 运算分量的个数与先后次序不变; 运算符的个数不变, 但其出现顺序即为执行顺序 无括号;
一个表达式E的后缀式可如下定义:



(1)如果E是一个变量或常数,则E的后缀式是E 自身; (2)如果E是E1opE2形式的表达式,op是二元操 作符,则E的后缀式为E1’E2’op, E1’和E2‘分 别为E1和E2的后缀式; (3)如果E是(E1)形式的表达式,则E1的后缀式 就是E的后缀式

3*5+4
+
if_then_else
*
B S1 S2 3 5
4
建立表达式的抽象语法树

mknode (op,left,right) 建立一个运算符号结点, 标号是op,两个域left和right分别指向左子树和 右子树。 mkleaf (id,entry) 建立一个标识符结点,标号为 id,一个域entry指向标识符在符号表中的入口。

7 北航本科编译原理课件 张莉

7 北航本科编译原理课件 张莉

第七章 源程序的中间形式•• •• ••波兰表示 波兰表示 N-元表示 N-元表示 抽象机代码 抽象机代码北京航空航天大学计算机学院17.1 波兰表示一般编译程序都生成中间代码,然后再生成目 标代码,主要优点是可移植(与具体目标程序无关), 且易于目标代码优化。

有多种中间代码形式: 波兰表示 N-元组表示 抽象机代码 波兰表示 算术表达式: 转换成波兰表示: 波兰表示: F*3.1416*R*(H+R) F3.1416*R*HR+*赋值语句: A := F * 3.1416 * R * ( H + R ) AF3.1416 * R * HR + * :=2北京航空航天大学计算机学院#a+b#ab++ 操作符栈 # #优先级最低算法: 设一个操作符栈;当读到操作数时,立即输出该操作数, 当扫描到操作符时,与栈顶操作符比较优先级,若栈顶操作 符优先级高于栈外,则输出该栈顶操作符,反之,则栈外操 作符入栈。

北京航空航天大学计算机学院 3if 语句的波兰表示label1if 语句:if <expr> then <stmt1> else <stmt2>label2波兰表示为 :<expr><label1>BZ<stmt1><label2>BR<stmt2> BZ: 二目操作符 若<expr>的计算结果为0 (false), 则产生一个到<label1>的转移 BR: 一目操作符 产生一个到< label2>的转移北京航空航天大学计算机学院4波兰表示为 :<expr><label1>BZ<stmt1><label2>BR<stmt2> 由if语句的波兰表示可生成如下的目标程序框架: <expr> BZ label1 <stmt1> BR label2 label1:<stmt2> label2: 其他语言结构也很容易将其翻译成波兰表示, 使用波兰表示优化不是十分方便。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
选择好计算的次序,充分利用目标机的特点
指令选择
任务
为每条中间语言语句选择恰当的目标机指令或指令序列
原则
• 首先要保证语义的一致性;若目标机指令系统比较完 备,为中间语言语句找到语义一致的指令序列模板是 很直接的(不必考虑执行效率的情形下) • 其次要权衡所生成代码的效率(考虑时间/空间代价)
• 在基本块范围内考虑如何充分利用寄存器的问题 原则: 尽可能地让变量的值保留在寄存器中
尽可能引用变量在寄存器中的值
• 借助于在基本块范围内建立变量的待用信息链和 活跃信息链
一个简单的代码生成算法
待用信息
• 在一个基本块中,四元式i对变量A定值,如果i后面 的四元式j要引用A,且从i到j的四元式没有其它对A的 定值点,则称j是四元式i中对变量A的待用信息,同时 也称A是活跃的。 • 如果A被多处引用,则构成了A的待用信息链和活跃 信息链。 • 为了取得每个变量在基本块内的待用信息和活跃信 息,可从基本块的出口由后向前扫描,对每个变量建 立相应的待用信息链与活跃信息链。
目标代码生成要考虑的主要问题 一个简单的代码生成算法
由上述算法从 DAG 生成代码
基于树重写的代码生成 简单的图着色物理寄存器分配算法
代码生成要考虑的主要问题
指令选择
目标机指令集的性质和中间代码的形式决定 指令选择的难易
寄存器分配
充分、高效地使用寄存器
指令调度
• 对相干图进行着色(coloring)
使用k(物理寄存器数量)种颜色对相干图进行着色, 使任何相邻的结点具有不同的颜色(即两个相干的 伪寄存器不会分配到同一个物理寄存器)。
简单的图着色物理寄存器分配算法
一种启发式图着色算法
“一个图是否能用 k 种颜色着色”是 NP-完全问题 以下是一个简单的启发式 k-着色算法: • 假设图 G 中某个结点 n 的度数小于 k,从G 中删除 n 及其邻边得到图 G’,对 G 的k-着色问题可转化为 先对G’ k-着色,然后给结点 n 分配一个其相邻结点 在 G’ 的k-着色中没有使用过的颜色。 重复这个过程从图中删除度数小于 k 的结点,如果 可以到达一个空图,说明对原图可以成功实现 k-着 色;否则,原图不能成功实现 k-着色,可从 G 中选 择某个结点作为泄露候选,将其删除,算法可继续。
表中“待用信息链”与“活跃信息链”的每列从左至右为每 从后向前扫描一个四元式时相应变量的信息变化情况,空白 处为没变化。 待用信息和活跃信息在四元式上的标记如下所示: (1) T(3)L:=A(2)L-BFL (2) U(3)L:=AFL-CFL (3) V(4)L:=TFF+U(4)L (4) DFL:=VFF+UFF
这一点较难做到,因为执行效率往往与该语句的上下 文以及目标机体系结构(如流水线)有关
指令选择举例
为TAC 语句选择指令模板
假设一个目标机指令系统(一个简单汇编语言)
例 TAC 语句 a:=b+c 可转换为如下代码序列
MOV ADD MOV b, R0 c, R0 R 0, a
/* b 装入寄存器 R0 */ /* c 加到 R0 */ /* 存 R0 到 a */

计算待用信息的算法
(1)对各基本块的符号表中的“待用信息”栏 和“活跃信息”栏臵初值,即把“待用信息” 栏臵“非待用”,对“活跃信息”栏按在基本 块出口处是否为活跃而臵成“活跃”或“非活 跃”。这里假定变量都是活跃的,临时变量都 是非活跃的。
(2)从基本块出口到基本块入口由后向前依次 处理每个四元式。对每个四元式i: A:=B op C, 依次执行下述步骤:
a)
把符号表中变量A的待用信息和活跃信息附加到四 元式i上。 b) 把符号表中变量A的待用信息栏和活跃信息栏分别 臵为“非待用”和“非活跃”。(由于在i中对A的 定值只能在i以后的四元式才能引用,因而对i以前 的四元式来说A是不活跃也不可能是待用的) c) 把符号表中变量B和C的待用信息和活跃信息附加到 四元式i上。 d) 把符号表中变量B和C的待用信息栏臵为“i”,活跃 信息栏臵为“活跃”。
t:=a-b u:=a-c v:=t+u d:=v+u
MOV a,R0 SUB b,R0 u: = a-c MOV a,R1 SUB c,R1 v: = t+u ADD R1,R0 d: = v+u ADD R1,R0 MOV R0,d
由上述算法从 DAG 生成代码
从某个基本块的 DAG 表示得到的两段 TAC 代码
如 B` 或 C` 为R,则删除 AVALUE[B] 或 AVALUE[C] 中的 R
一个简单的代码生成算法
基本块的代码生成算法 (续前页)
·令 AVALUE[A]={R},并令 RVALUE[R]={A},以表示变量 A 的现行
值只在 R 中并且 R 中的值只代表 A 的现行值 。
·如 B 或 C 的现行值在基本块中不再被引用,它们也不是基本块出
一个简单的代码生成算法
寄存器描述数组和变量地址描述数组
• RVALUE[R] 描述寄存器 R 当前对应哪个变量 • AVALUE[A] 表示变量 A 的值存放在哪个寄存器中
一个简单的代码生成算法
基本块内 TAC 语句序列的简单代码生成
(假设只有形如 A:=B op C 的TAC 语句序列)
口之后的活跃变量(由语句 i 上的附加信息知道),并且其现行值在某 个寄存器 Rk 中,则删除 RVALUE[Rk] 中的 B 或C 以及 AVALUE[B] 或 AVALUE[C] 中的 Rk ,使该寄存器不再为 B 或 C 所占用。
step2: 处理完基本块中所有TAC 语句之后,对现行值在 某寄存器 R 中的每个变量 M,若它在出口之后是活跃 的,则生成 MOV 生成
一个简单代码生成器
目标代码生成在编译程序中的逻辑位臵
词法分析 字符流 单词流 语法分析树 中间表示 优化的中间表示 目标代码 优化的目标代码 语法分析 从中间表示 获取的流图 改进的流图 语义分析和中间代码生成 机器无关的代码优化 目标代码生成 针对机器的代码优化 指令调度 寄存器分配 窥孔优化
器分配算法将它们对应到真实寄存器或内存地址)。
其实也可以不是返回伪寄存器,而是在寄存器不够时返回一个内 存地址。
一个简单的代码生成算法举例
对于右图的基本块 (假定只有d在基本块的 出口是活跃的),利用上述算法可生成如下 代码序列:
语句 t: = a-b 生成的代码 寄存器描述 空寄存器 R0 包含 t R0 包含 t R1 包含 u R0 包含 v R1 包含 u R0 包含 d 地址描述 t 在 R0 中 t 在 R0 中 u 在 R1 中 u 在 R1 中 v 在 R0 中 d 在 R0 中 d 在 R0 中和存储器中
两遍的通用寄存器分配算法
• 第一遍先假定可用的通用寄存器是无限数量的,完 成指令选择 例如:前面介绍的简单代码生成算法中的 getreg 函数返回一个伪寄存器(不管物理寄存器的个数) • 第二遍将物理寄存器分配到伪寄存器。 物理寄存器数量不足时,会将一些伪寄存器泄露到 (spilled into)内存,图着色算法的核心任务是使 得泄露的伪寄存器数目最少。
T1:=a+b T2:=c+d T3:=e-T2 T4:=T1-T3 MOV a,R0 ADD b,R0 MOV c,R1 ADD d,R1 MOV e,R2 SUB R1,R2 SUB R2,R0 MOV R0,T4 T2:=c+d T3:=e-T2 T1:=a+b T4:=T1-T3 MOV c,R0 ADD d,R0 MOV e,R1 SUB R0,R1 MOV a,R0 ADD b,R0 SUB R1,R0 MOV R0,T4
• template 代表一棵树
• cost 是用来计算相应于该template代价的代码片段 • action 是使用该规则进行树重写时执行的代码片段
基于树重写的代码生成
例 若干VAX指令对应的树重写规则
基于树重写的代码生成
例 若干VAX指令对应的树重写规则
基于树重写的代码生成
函数 getreg(以 i: A:=B op C 为参数, 返回一个伪寄存器)
步骤:
• 若 RVALUE[R]={B} ,且在语句 i 之后 B 在基本块中不再被引用,同 时也不是基本块出口之后的活跃变量(由 i 上的附加信息可知道), 则返回 R; • 否则,返回一个新的伪寄存器R’
注:这里的 getreg 返回伪寄存器(可以利用随后介绍的图着色寄存
从中间表示树生成代码
思路
• 根据树重写规则对中间表示树的子树逐步进行归 约,直至单个节点为止,该过程的所有子树集合构 成中间表示树的一种覆盖(cover)。 • 某个覆盖的代价是相应树重写规则的附加代价之和
• 找到一种代价最小的覆盖。 • 根据最小代价的覆盖进行代码生成。
简单的图着色物理寄存器分配算法
简单的图着色物理寄存器分配算法 基于寄存器相干图(register-interference graph) 的图着色寄存器分配算法
• 构造寄存器相干图 结点:每一个伪寄存器为一个结点。 边:如果程序中存在某点,一个结点在该点被定义, 而另一个结点在该点是活跃的,则在这两个结 点间连一条边。
第二段代码较优(少用了寄存器)
基于树重写的代码生成

a [ i ] := b 的一个可能的中间表示树
基于树重写的代码生成
树重写(Tree Rewriting)规则形如
其中 • replacement 代表树的单个节点 replacement template {cost} = {action}
step1:对每个TAC 语句i: A:=B op C,依次执行下述步骤:
相关文档
最新文档