8编译原理之讲义代码生成
编译原理目标代码生成
中间代码生成
探讨中间代码的概念、作用和生成方法,包括抽象语法 树、三地址代码等中间表示形式。
代码优化
介绍代码优化的原理和常用技术,如常量折叠、复制传 播、死代码删除等,以提高目标代码的质量。
目标代码生成
详细讲解目标代码生成的过程和方法,包括指令选择、 寄存器分配、汇编语言输出等关键步骤,以及针对不同 目标平台的优化策略。
语义分析
介绍了语义分析的基本任务,如类型 检查、控制流分析、数据流分析等。
中间代码生成
阐述了中间代码的概念、作用及生 成方法,包括抽象语法树、三地址 代码等。
目标代码生成
详细讲解了目标代码生成的过程, 包括指令选择、寄存器分配、优化 等。
对未来编译技术的展望
智能化编译技术
随着人工智能技术的发展,未来编译器可能具备更强的自 主学习能力,能够自动优化代码性能、提高编译效率。
01
指令选择算法
根据目标计算机的指令集和程序语义, 选择最合适的指令来实现程序功能。
02
03
代码优化算法
通过对生成的机器相关代码进行各种 优化(如常量折叠、循环展开等), 提高其执行效率和资源利用率。
06
代码生成器的设计与实现
代码生成器的结构
中间代码生成器
将源程序转换为中间代码形式,便于后续优化和代码生成。
2
编译过程包括词法分析、语法分析、语义分析、 中间代码生成、代码优化和目标代码生成等阶段。
3
编译原理不仅关注如何生成高效的目标代码,还 关注如何提高编译器的可维护性、可移植性和可 扩展性。
目标代码生成的意义
提高程序执行效率
目标代码是计算机直接执行的指令,其执行效率远高于高级语言程序。通过优化目标代码 ,可以提高程序的执行速度。
编译原理课件-中间代码生成
Wensheng Li BUPT @ 2008
賦值語句a:=b*-c+b*-c的圖表示法
語法樹表示: assign
dag圖形表示: assign
a
+
a
+
*
*
b uminus b uminus
c
c
* b uminus
c
Wensheng Li BUPT @ 2008
7/75
二、三地址代碼
三地址代碼
賦值語句a:=b*-c+b*-c的三元式表示
Wensheng Li BUPT @ 2008
op
arg1
arg2
(14) uminus
c
(15)
*
b
(14)
(16) uminus
c
(17)
*
b
(16)
(18)
+
(15)
(17)
(19)
:=
a
(18)
12/75
語句x[i]:=y和x:=y[i]的三元式序列
EE1+E2
{ E.place=newtemp; if (E1.type==integer) && (E2.type==integer) { emit(E.place := E1.place + E2.place); E.type=integer; }; else if (E1.type==real) && (E2.type==real) { emit(E.place := E1.place real+ E2.place); E.type=real; }; else if (E1.type==integer) && (E2.type==real) { u=newtemp; emit(u := inttoreal E1.place); emit(E.place := u real+ E2.place); E.type=real; }; else if (E1.type==real) && (E2.type==integer) { u=newtemp; emit(u := inttoreal E2.pace); emit(E.place := E1.place real+ u); E.type=real; }; else E.type=type_error; }
计算机基础知识点编译原理代码生成
计算机基础知识点编译原理代码生成编译原理是计算机科学中非常重要的一门学科,它研究的是如何将高级语言编写的程序转化为机器可以执行的指令序列。
在编译过程中,代码生成是其中一个关键的步骤。
本文将介绍编译原理中的代码生成基础知识点。
一、代码生成概述代码生成是编译过程中的最后一个阶段,它的任务是将中间表示形式(如抽象语法树或中间代码)转化为目标机器代码,使得程序可以在计算机上运行。
代码生成的目标是产生高效且正确的机器指令序列,以最大程度地利用计算机的硬件资源。
代码生成的过程可以分为以下几个步骤:1. 寄存器分配:将变量和临时值分配到计算机的寄存器中,以便在指令中进行操作。
2. 指令选择:根据中间表示的特点和目标机器的指令集,选择适当的机器指令来实现所需的操作。
3. 指令调度:对指令进行重新排序,以减少指令相关性和提高执行效率。
4. 内存分配:将变量和临时值存储到内存中,以便在需要时可以进行访问。
5. 代码优化:对生成的机器指令进行优化,以减少执行时的开销和资源占用。
二、寄存器分配在代码生成的过程中,寄存器分配是一个非常重要的环节。
寄存器是计算机中的一种高速存储设备,可以用于存储和执行指令操作。
在生成的机器代码中,寄存器通常用于存储临时值和计算结果。
寄存器分配的目标是将变量和临时值存储到寄存器中,并进行相应的寄存器的分配和释放。
常见的寄存器分配算法有线性扫描分配算法、图着色分配算法等。
寄存器分配算法的选择通常取决于目标机器的寄存器数量和寄存器之间的互斥关系。
三、指令选择指令选择是代码生成的关键一环,它的任务是根据中间表示和目标机器的指令集,选择合适的机器指令来实现所需的操作。
指令选择的准则通常是从操作数和操作符的角度考虑,以及考虑目标代码的执行效率和可读性。
指令选择的过程中,需要考虑目标机器的指令格式、寻址方式、寄存器约束等因素。
对于一些特殊的操作,如函数调用、跳转指令等,还需要考虑目标代码的控制流程和程序执行的正确性。
编译原理与自动化代码生成
编译原理与自动化代码生成编译原理是计算机科学中的一个重要领域,它研究如何将高级程序语言翻译为计算机能够执行的低级指令,从而实现程序的执行。
自动化代码生成是编译原理中的一个关键步骤,它通过将程序中的高级语言代码转换为计算机识别的机器码,实现程序功能的自动化生成。
一、编译原理的基本概念与流程编译原理涉及到词法分析、语法分析、语义分析、中间代码生成、代码优化和代码生成等多个环节。
下面将简要介绍编译原理的基本流程。
1. 词法分析词法分析器将源代码分割为一个个词法单元,如关键字、标识符、运算符、常量等,并将这些词法单元以标记的形式传递给语法分析器。
2. 语法分析语法分析器将词法分析器传递的标记组织成语法树,检查程序语法的正确性。
常用的语法分析方法有递归下降分析、LL(1)分析和LR分析等。
3. 语义分析语义分析器主要对程序的语义进行检查,包括类型检查、符号表管理、语法错误修复等。
它会生成中间代码,为代码生成和优化做准备。
4. 中间代码生成中间代码是一种介于源代码和目标代码之间的代码形式,方便进行代码优化和代码生成。
常见的中间代码形式有三地址码、四元式和抽象语法树。
5. 代码优化代码优化是在保持程序功能不变的前提下,通过改进程序结构或重写代码,以提高运行效率。
常见的代码优化技术有常量传播、常量折叠、循环优化等。
6. 代码生成代码生成是将中间代码转换为目标代码的过程。
目标代码可以是可执行代码,也可以是汇编代码,具体取决于编译器的设定。
二、自动化代码生成的意义和方法自动化代码生成旨在提高程序开发的效率和质量,减少开发人员的工作量。
以下是常见的自动化代码生成方法。
1. 模板代码生成模板代码是指在开发过程中频繁出现的、类似的代码片段。
通过定义好模板,利用代码生成工具可以自动根据模板生成对应的代码。
2. 元编程元编程是一种编程范式,它允许程序在运行时生成、修改和执行其他程序。
通过元编程技术,可以实现动态生成代码和扩展程序的功能。
编译原理 之 代码生成【VIP专享】
1. 代码生成程序的输入
• 中间代码. 线性表示法(后缀 式)、三地址(四元式)等.
• 符号表中的信息. 代码生成根据 符号表中的信息来决定中间代码 中的名字所指示的数据对象的运 行时地址.
• 有时需要作类型检查.
2. 指令选择
✓ 指令选择--寻找一个合适的目标机 指令序列以实现给定的中间表示.
ADD Rj,Ri 其开销为1,结果在Ri中. ② b存放在Ri中,而c在一个存储单元里,并假
定b不再活跃。 ADD c,Ri 其开销为2 ③ 或者 MOV c,Rj ADD Rj,Ri 其开销为3
4. 指令调度•Biblioteka 指令调度——确定程序指令的执行顺序
• 对具有流水线限制的体系结构,这个阶段 是必须的。如:RISC体系结构一个通用的 流水线限制为:从内存中取入寄存器中的 值在随后的某几个周期中是不能用的。在 这几个周期期间,调出不依赖于该取入值 的指令来执行是很重要的。
代码生成器
目标程序目标程序
符号表
图12.1 代码生成器在编译系统中的位置
代码生成器的输入 ➢中间代码 ➢符号表中的信息
目标代码一般有三种形式:
1. 能够立即执行的机器语言代码,所 有地址均已定位,通常位于固定的 存储区域中,编译后可直接运行.
2. 待装配的机器语言模块。当需要执 行时,由连接装入程序把它们和某
✓ 如果目标机不能支持指令集的所有 类型,那么对每一种例外要做特别 处理.
✓ 多数CPU的指令集合具有冗余性, 也即,同一计算可用两个或多个不 同的指令序列完成。指令选择器选 择其中之一以产生最好的代码.
例:“加1”的两种代码生成方 式
编译原理代码生成(new)
+ +
:=
:=
i +i +
i 1i 1
:= i+
i1
例题2
按一般的代码生成,i = i +1的计算结果保留在 寄存器中,因此这三个i = i +1的计算次序不会 影响最终的结果。结果应该是6。
结果是7的话,一定是 某个i = i +1的结果未保 留在寄存器中。上层 计算对它的引用落在 计算另一个i = i +1的 后面
的寄存器R(可能产生MOV R,M指令,并修改 M的描述 ) 否则,如果x在基本块中不再引用,或者找不到适当的被占用寄存器,选择x的内存单
元作为L。
11.4 一个简单的代码生成器
赋值语句d := (a b) + (a c) + (a c)
编译产生三地址语句序列: t1 := a b t2 := a c t3 := t1 + t2 d := t3 + t2
代码生成
本章内容 一个简单的代码生成算法 涉及存储管理,指令选择,寄存器分配和计算次序选择等基本问题
源程序
中间 前端 代码
代 码 中间 代码
优 化 代码 生成
器
器
目标 程序
11.1 代码生成器的设计中的问题
11.1.1 目标程序 可执行目标模块 可重定位目标模块
允许程序模块分别编译 调用其它先前编译好的程序模块
+ +
:=
:=
i +i +
i 1i 1
:= i+
i1
例题2
如果机器有INC指令的话,编译器极可能产生一条INC指令来完成i = i +1 X86/Linux机器上果真是这么做的
精品课程编译原理-PPT课件第8章 语法制导与中间代码生成
(3)一致性检查。在很多场合要求对象只能被 定义一次。例如Pascal语言规定同一标识符在一 个分程序中只能被说明一次,同一case语句的标 号不能相同,枚举类型的元素不能重复出现等等。
(4)上下文相关性检查。比如,变量名字必 须先声明后引用;
(5)名字的作用域分析。各变量的作用域可 能是不一样的,要通过分析明确各变量的作用域。
例子: a:=b*c+b*d的相应三元组
①(*, b, c) b*c ②(*, b, d) b*d ③(+, (1),(2)) b*c+b*d ④(:=,(3), a) a:=b*c+b*d
例子:tri(A*B+C) =tri(A*B)||tri(c)||2:(+,①≥,C) =1:(*, A,B) A*B 2:(+,①,C) A*B+C
8.2.2 S-属性文法和自下而上翻译 一般的属性文法的翻译器很难建立,然 而L-属性文法的翻译器很容易建立。
L-属性文法的一个特例叫S-属性文法。 S-属性文法是只含有综合属性的属性文法。
8.2.3 L-属性文法在自下而上分析中实现 L-属性文法允许一次遍历就计算出所以的 属性值。
8.3 中间代码的形式
3*5+6的带注释的分析树
只使用综合属性.
T.val=3 F.val=3
E.val=15 T.val=15
*
L
E.val=21
+
F.val=5
T.val=6 F.val=6 digit.lexval=6
digit.lexval=5
digit.lexval=3
3*5+6的带注释的分析树
继承属性
一个结点的继承属性值是由此结点的父结点和/或兄弟结 点的某些属性来决定的。
编译原理与代码生成
编译原理与代码生成在计算机科学领域中,编译原理是一门研究编程语言如何被转换成可执行代码的学科。
它涉及到编译器的设计和开发,其中一个关键环节就是代码生成。
代码生成是编译过程中的最后一步,它将中间表示形式(如抽象语法树或中间代码)转化为机器代码或目标代码,以便计算机能够直接执行。
代码生成是编译过程中至关重要的一环,其质量直接影响到最终生成的可执行程序的效率和性能。
一个好的代码生成器应该能够生成高效、优化的机器代码,并且具备可移植性。
为了实现这一目标,代码生成器通常需要考虑以下几个方面:1. 寄存器分配:寄存器是现代计算机体系结构中重要的资源之一。
在代码生成阶段,寄存器的分配是一个关键问题。
代码生成器需要决定哪些变量应该存储在寄存器中,哪些应该存储在内存中,并生成相应的指令来进行寄存器的分配和管理。
2. 内存分配:除了寄存器分配外,代码生成器还需要考虑如何进行内存分配。
它需要决定哪些变量应该存储在堆栈上,哪些应该存储在静态数据区,以及如何有效地进行内存的分配和释放。
3. 代码优化:代码生成器还需要考虑一系列的代码优化技术,以提高生成代码的质量和效率。
这些技术包括常见的优化方法,如常量折叠、公共子表达式消除、死代码删除等。
通过应用这些优化技术,代码生成器可以生成更紧凑、更高效的机器代码。
4. 目标代码生成:最后,代码生成器需要将中间表示形式翻译成目标机器能够执行的机器代码。
这一过程中,代码生成器需要根据目标机器的指令集架构和特性来生成相应的机器代码。
同时,为了保证生成的代码的可移植性,代码生成器还需要考虑各种编译器选项和标准。
综上所述,编译原理中的代码生成是编译过程中不可或缺的一部分。
通过合理的寄存器分配、内存分配、代码优化和目标代码生成,代码生成器可以生成高质量、高效率的机器代码。
这对于计算机科学学习者和编译器开发者来说,都是一个重要的课题。
只有深入理解编译原理和代码生成的原理和技术,才能够设计和实现出优秀的编译器和程序。
编译原理之代码生成
03
04
05
1. 语法分析:根据语言 2. 语义分析:对抽象语
的语法规则,将源程序 法树进行语义检查和处
解析成抽象语法树
理,包括类型检查、符
(Abstract Syntax Tree,号表管理等。
AST)。
3. 中间代码生成:根据 抽象语法树和语义分析 结果,生成中间代码。 常见的中间代码形式有 三地址码、静态单赋值 形式(Static Single Assignment,SSA)等。
运行时系统自动管理程序中的内存资源, 通过垃圾回收机制回收不再使用的内存空 间,防止内存泄漏和野指针等问题。
运行时系统对程序性能的影响和优化
性能影响
运行时系统的设计和实现会直接影响程序的性能。例如,垃圾回收算法的选择和实现会 影响内存的回收效率和程序的暂停时间。线程调度策略的选择也会影响程序的并发性能
编译原理是计算机科学的重要分支,对于理解计算机如何执行程序以及如何提高程 序执行效率具有重要意义。
代码生成在编译过程中的作用
代码生成是编译过程的最后阶段, 负责将中间代码或优化后的代码 转换为目标机器上的可执行代码。
代码生成器需要了解目标机器的 指令集、寄存器分配、内存管理 等相关知识,以生成高效且正确
中间代码在编译器中的 作用主要有以下几点
使得编译过程分为相对 独立的前端和后端,降 低了编译器的复杂性。
提供了统一的中间表示, 便于实现不同语言之间 有利于进行各种优化操 的互操作性。 作。
ห้องสมุดไป่ตู้
中间代码生成的算法和步骤
01
02
中间代码生成的主要算 法包括语法分析、语义 分析和中间代码生成三 个步骤。
具体步骤如下
代码生成器的测试和评估方法
编译原理-语义分析和中间代码生成
编译器是一种将高级语言翻译成低级语言的程序。语义分析和中间代码生成 是编译器中非常重要的两个步骤。在本次演讲中,我们将深入探讨它们的内 容和作用。
定义和目的
1 语义分析
对代码的意义和上下文进行全面的分析。
2 目的
识别出语法正确但不符合语言规范的代码,以及提取中间代码。
检查和错误
1
步骤
类型检查、控制流检查、错误信息收集。
2
类型
变量未声明、数组维数不符、类型不匹配、函数参数个,中断代码生成流程。
中间代码生成
概述
表示形式
将源代码翻译为一种可读性和 可执行性都比较好的中间代码。
三元式、四元式、静态单赋值 形式。
算法
递归下降法、语法制导翻译、 继承型翻译。
实例和案例分析
实例
对表达式 "a = b + c * d" 进行语义分析和中 间代码生成。
案例
使用LLVM对C语言代码生成中间代码。
总结
语义分析
中间代码生成
全面分析代码以及上下文,发现不符合语言规 范的代码。
将源代码翻译为可读性和可执行性都比较好的 中间代码。
“Your code isn't wrong, it's just not right yet.” "If you can't run with the big dogs, stay on the porch."
深入学习:掌握编译原理与目标代码生成
深入学习:掌握编译原理与目标代码生成编译原理与目标代码生成是计算机科学与软件工程领域非常重要的一部分。
在这个领域中,我们研究的是将程序代码转换为可执行代码的过程,这涉及到了词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等一系列的技术和算法。
编译器是实现编译过程的工具,它将高级语言源代码转换为机器可执行的目标代码。
而编译过程中的关键环节即为目标代码生成,它是将中间代码转换为特定硬件平台上可执行的机器代码的过程。
编译原理的研究从上世纪50年代开始,经历了多个阶段的发展。
早期的编译器通过逐行读取源代码,然后将其转换为汇编语言或机器码。
随着计算机硬件的发展和编程语言的演化,编译器的设计和实现也发生了重大变化。
编译原理的核心概念之一是语法分析,它将源代码转换为抽象语法树(AST)。
语法分析器通过识别词法单元(如关键字、标识符、操作符等)来构建AST,并使用上下文无关文法来定义语法结构。
常见的语法分析算法有递归下降分析和LR分析。
语义分析是编译过程中的另一个重要环节,它确保程序在语义上是正确的。
语义分析器会检查源代码中的类型错误、作用域错误、类型转换错误等,并为后续的代码生成阶段提供必要的信息和约束条件。
中间代码生成是编译器的一个重要步骤,它将AST转换为一种中间表示形式,例如三地址码或者虚拟机指令。
中间代码是对源代码的一种抽象表示,它简化了后续代码生成和优化的过程,并为优化算法提供了更好的机会。
代码优化是编译过程中的重要环节,它旨在提高目标代码的性能和效率。
代码优化器使用各种技术和算法,例如常量折叠、循环优化、指令调度等,来改进目标代码的执行效率。
最后一个环节是目标代码生成,它将中间代码转化为特定硬件平台的机器代码。
目标代码生成器需要考虑到硬件平台的特点和限制,并根据目标机器的指令集架构来生成高效的机器代码。
目标代码生成是编译器的最终阶段,它决定了程序的最终执行效果。
一个好的目标代码生成器应该可以充分利用硬件资源,减少指令的数目和执行时间,从而提升程序的性能。
编译原理 代码生成
3.
重命名临时变量
t := b + c,t——临时变量 u := b +c,u——新临时变量,对t的引用对u的引用, 基本块结果不变 定义临时变量的语句都定义新的临时变量 基本块等价变换,范式基本块
保结构变换(续)
4.
语句交换
t1 := b + c t2 := x + y 两个语句交换位置不影响运算结果 x、y都不是t1,b、c都不是t2 注意:范式基本块允许所有可能的语句交换
/* */ /* 局部数据 */
300: 304:
9.3.2 栈分配
使用相对活动记录起始的偏移
活动记录的地址——栈寄存器,SP
―第一个过程”
MOV #stackstart, SP 第一个过程的代码 HALT
栈分配——函数调用和返回
例9.3
begin prod := 0 i := 1 do begin prod := prod + a[i] * b[i]; i := i + 1 end while i <= 20 end
例9.3(续)
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12)
t1 := 12 + R3 *t1 := 0 MOV #0, 12(R3)
9.4 基本块和流图
9.4.1 基本块,basic block
连续语句序列,执行过程中没有分支 t1 := a * a t2 := a * b t3 := 2 * t2 t4 := t1 + t3 t5 := b * b t6 := t4 + t5 x := y + z:定义x,使用(引用)y、z
编译原理语义分析与中间代码生成
产生式的语义描述
(1)A→i:=E { p=lookup(); if (p==NULL) error(); else emit(p ’=’ E.place)} (2) E→E(1)+E(2) {E.place=newtemp(); emit(E.place ’=’ E(1).place ’+’ E(2).place)} (3)E→E(1)*E(2) {E.place=newtemp(); emit(E.place ’=’ E(1).place ’*’ E(2).place)} (4) E→-E(1) {E.place=newtemp(); emit(E.place ’=’’uminus’ E(1).place)} (5)E→(E(1)) {E.place ’=’ E(1).place} (6)E→i { p=lookup(); if (p==NULL) error(); else E.place=p}
中间代码
中间代码(Intermediate code ):
源程序的一种内部表示,不依赖目标机的结构,
易于机械生成目标代码的中间表示。
几种中间语言
后缀式(逆波兰表示法) 三地址代码
四元式 三元式 间接三元式 树
后缀式
表达式的一种表示形式
运算符直接跟在运算量后面
又称为逆波兰表示法
有穷的属性集有穷的属性集每个属性与一个文法符号相关联每个属性与一个文法符号相关联这些属性代表与文法符号相关的语义信息这些属性代表与文法符号相关的语义信息如类型地址值代码符号表内容等等如类型地址值代码符号表内容等等属性与变量一样可以进行计算和传递属性与变量一样可以进行计算和传递属性加工的过程即是语义处理的过程属性加工的过程即是语义处理的过程属性加工与语法分析同时进行属性加工与语法分析同时进行属性的表示
编译原理语义分析和中间代码生成
在语义分析阶段,编译器会检查源代 码中是否存在类型错误、未定义的变 量和函数、不符合控制流规则的语句
等。
语义分析的主要任务包括类型检查、 函数和变量的解析、控制流的检查等。
如果发现错误,编译器会报错并停止 编译过程;如果没有发现错误,编译 器将继续生成中间代码。
02 中间代码生成
中间代码生成概述
中间代码是源代码和目标代码之间的代 码形式,用于表示源程序的结构和语义
信息。
中间代码生成是编译过程的一个重要阶 中间代码生成可以提高编译器的灵活性
段,它把源代码转换成一种更接近于机 和可移植性,因为中间代码与具体的机
器语言的代码形式,以便进行后续的优 器语言无关,可以在不同的平台上使用
代码优化
编译器通过优化技术 对源代码进行优化, 以提高生成代码的执 行效率,减少运行时 间。
代码分析
编译原理还可以用于 代码分析,检查代码 的语法、语义和结构, 发现潜在的错误和漏 洞。
程序理解
编译原理可以帮助理 解程序的内部结构和 行为,为程序修改、 重构和优化提供支持。
编译原理的发展趋势
静态分析
在语法分析阶段,编译器根据 语言的语法规则将词素或标记 组合成一个个的语法结构,如 表达式、语句、程序等。
语义分析阶段是在语法分析的 基础上,对这些语法结构进行 语义检查和语义处理。
语义分析的例子
01
02
假设有以下C语言代码 ```c
03
int a = "hello";
04
```
05
在语义分析阶段,编译 器会发现变量a被赋值为 一个字符串字面量,而 字符串字面量是字符数 组类型的值,因此会报 错,因为整型变量不能 赋值为字符数组类型的 值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
• RISC、CISC; • 可重定向代码、汇编语言
代码生成器设计中的问题
指令选择
•代码生成器将中间表示形式映射为目标
机代码
•映射的复杂性由下列因素决定:
• IR的层次
• 高:用代码模板翻译,但代码质量不高,需优 化
• 低:利用低层次细节生成更高效的代码
• 指令集体系结构本身的特性 • 期望的目标代码质量
方便记忆)
常量#constant56
例子
x=y-z
• LD R1, y
//R1=y
• LD R2, z
//R2=x
• SUB R1, R1, R2
//R1=R1-R2
• ST x, R1
//x=R1
b=a[i]
• LR R1, i
//R1=i
• MUL R1, R1, 8
//R1=R1*8
• LD R2, a(R1)
8.1代码生成器设计中的问题
设计目标:
• 生成代码的正确性(最重要) • 易于实现、测试和维护
输入 输出 指令选择 寄存器分配 计算顺序
代码生成器设计中的问题
输入
• 前端生成的源代码的IR(中间表示形式)及符号表信息 • 中间表示形式的选择
• 四元式、三元式、字节代码、堆栈机代码、后缀表示、抽象 语法树、DAG图、…
//R2=contents(a+contents(R1))
• ST b, R2
//b = R2
程序及指令代价
不同的目的有不同的度量
• 最短编译时间、目标程序大小、运行时间、能耗
不可判定一个目标程序是否最优 指令代价=指令固定代价(设为1)+运算分量寻
址模式代价,例:
• LD R0, R1;代价为1 • LD R0, M;代价是2 • LD R1, *100(R2);代价为2
变量x:指向分配x的内存位置 a(r):地址是a的左值加上r中的值(可类比
一维数组方便记忆)
constant(r):寄存器中内容加上前面的 常数即其地址;(可类比一维数组方便记忆)
*r:寄存器r的内容为其地址 *constant(r):r中内容加上常量的和所
指地址中存放的值为其地址(可类比一维数组
8编译原理之代码生成
代码生成器的位置
根据中间表示生成代码 代码生成器之前可能有一个优化组件 代码生成器的三个任务
• 指令选择:选择适当的指令实现IR语句 • 寄存器分配和指派:把哪个值放在哪个寄存器中 • 指令排序:按照什么顺序安排指令执行
主要内容
代码生成器设计中的问题 目标机模型 静态/栈式数据区分配 基本块相关的代码生成 简单的代码生成算法 窥孔优化
常数和内存地址 增加代价1,
寄存器增加代价 为0。
8.3 目标代码中的地址
• Q:如何将IR中的名字转换成目标代码中的地址?
A:程序运行时环境划分为4个区域:代码区Code、静态 区Static、栈区Stack和堆区Heap。
不同区域中的名字采用不同寻址方式。
如何为过程调用和返回生成代码
• 静态分配 • 栈式分配
代码生成器设计中的问题
指令选择
•映射的复杂性由下列因素决定:
• IR的层次 • 指令集体系结构本身的特性
• 指令的统一性、完整性 • 指令速度和机器惯用语(idioms)
• 期望的目标代码质量
代码生成器设计中的问题
指令选择
•映射的复杂性由下列因素决定:
• IR的层次 • 指令集体系结构本身的特性 • 期望的目标代码质量
• ADD SP, SP, #caller.recordSize
//增加栈指针,越过调用者自身的活动记录
• ST 0(SP), #here+16
//保存返回地址
• BR callee.codeArea
//转移到被调用者
返回指令序列
• BR *0(SP) //被调用者最后执行,返回调用者 • SUP SP, SP, #caller.recordSize
...
返回地址
callee中的语句return
• BR *callee.staticArea
*为突出重点,经常将活 动记录中其它的部分忽略。
例子
三地址代码
• action1 • call p • action 2 • halt
//p的代码
• action3 • return
活动记录栈式分配
寄存器SP指向栈顶 第一个过程(main)初始化栈区 过程调用指令序列
//调用者中减低栈指针34
例:快速排序
未完,转下页
例:快速排序
接上页
名字的运行时刻地址
在三地址语句中使用名字(实际上是按符 号表条目提供的信息)来引用变量
三地址语句x=0
• 如果x分配在开始位置为static静态区域,且
符号表中保存的相对地址为12,则可以译为:
• static[12] = 0 • 设静态区从100开始,则也可译为
活动记录静态分配
每个过程静态地分配一个数据区域,开始 位置用staticArea表示
call callee的实现
常量1字长
实际为一个常量1字长
• ST 一个指令1字长
callee.staticArea, #here+20
一个指令1字长
• //保存返回地址
常量1字长
• BR callee.codeArea
• 同一IR程序可用不同代码序列实现,它们的代 价不同
•示例:a=a+1可实现为两
种 •LD R0,a
•INC
•ADD R0,R0,#1
a
•ST a,R0
8.2 目标机模型
本书使用三地址机器模型,指令如下:
• 加载
• LD dst, addr;把地址addr中的内容加载到dst所指寄 存器。addr:内存地址/寄存器
• 保存
• ST x, r;c1, src2;把src1和scr2中的值运算后将 结果存放到dst中。
• 无条件跳转
• BR L;控制流转向标号L的指令
• 条件跳转
• Bcond r, L;对r中的值进行测试,如果为真则转向L。
寻址模式
LD 112 #0
• 如果x分配在栈区,且相对地址为12,则
• LD 12(SP) #0
基本块和流图
中间代码的流图表示法
• 中间代码划分成为基本块(basic block),其
特点是单入口单出口,即:
• 控制流只能从第一个指令进入 • 除了基本块最后一个指令,控制流不会跳转/停机
• 流图中结点是基本块,边指明了哪些基本块