830 likes | 969 Views
编 译 原 理. 指导教师 : 杨建国. 二零一零年三月. 第十三章 编译程序的构造. 第一节 编译程序的书写. 第二节 可重定向编译程序. 第三节 GCC 的剖析. 第四节 GCC 的定制. 第五节 GCC 的优化. 知识结构. 第十三章 编译程序的构造. 13.1 编译程序的书写. 编译程序的构造主要有三条途径: 用某种程序语言书写编译程序 通过 LEX 、 YACC 等工具进行自动构造 通过现有的编译基础设施进行改造和组装. 一 . 编译程序的书写语言与 T 型图 编译程序的 T 型图,如图 13.1 所示:.
E N D
编 译 原 理 指导教师:杨建国 二零一零年三月
第十三章 编译程序的构造 • 第一节 编译程序的书写 • 第二节 可重定向编译程序 • 第三节 GCC的剖析 • 第四节 GCC的定制 • 第五节 GCC的优化
第十三章 编译程序的构造 • 13.1 编译程序的书写 • 编译程序的构造主要有三条途径: • 用某种程序语言书写编译程序 • 通过LEX、YACC等工具进行自动构造 • 通过现有的编译基础设施进行改造和组装
一.编译程序的书写语言与T型图 • 编译程序的T型图,如图13.1所示:
如果一个编译程序的源语言是X,目标语言是Y,书写语如果一个编译程序的源语言是X,目标语言是Y,书写语 言是Z,把该编译程序记作CZXY,那么用T型图表示如图 13.2所示:
二.编译程序的自展技术 • 自展思想:先用目标机的汇编语言或机器语言书写源语言 的一个子集的编译程序,然后再用这个子集作为书写语言, 实现源语言的编译程序。如果把这个过程根据情况分成若 干步,像滚雪球一样直到生成预计源语言的编译程序为止, 把这样的实现方式称为自展技术
例如,在目标机A上要实现L语言的编译程序,可以把L的例如,在目标机A上要实现L语言的编译程序,可以把L的 核心部分划分为L1 • 第一步:先用A机器的汇编语言或机器语言A书写L1的编 译程序,表示为CAL1A,其T型图如图13.3所示:
第二步:再用L1书写L语言的编译程序为CL1LA,其T型图第二步:再用L1书写L语言的编译程序为CL1LA,其T型图 如图13.4所示
A • 第三步:由于最终要求得到CALA,只要把CL1LA经过CAL1A 即可得到CALA。可用图13.5的双层结合T型图表示:
结合T型图的原则是: (1)下面的T型图的左右上角两个语言分别与上面左右两个 T型图的底部语言相同 (2)上面左右两个T型图的左右上角的语言必须分别相同
A • 如果把L分出L1,L2,这个过程用三层结合的T型图表示 如图13.6所示: • CALA CLL1A CL1L2A CL2LA CAL2A CALA
L可以分成核心L1,L2,…,Ln都为L1的逐步扩充,使得L可以分成核心L1,L2,…,Ln都为L1的逐步扩充,使得 L=Ln,其自展的示意图如图13.7所示:
13.2 可重定向编译程序 一.概述 • 可重定向编译程序的研究和开发对于编译程序的构造具有 重大意义: • 第一,它缩短了编译程序的开发周期 • 第二,它提高了编译程序研究的质量,使研究人员能够在 抽象级的平台上开发,把精力专注于研究本身而非基础建设 • 第三,便于更多的队伍从事编译程序研究,且其研究成果 能够被很好地共享,从而可以加快步伐 • 第四,及时针对新机器和新语言开发出配套编译程序,减 少了采用新语言和新机器的障碍,有利于为产品创造更大 的市场
1.交叉编译程序: • 交叉编译:在一个平台上生成另一个平台上的可执行代码 • 平台:体系结构、操作系统 • 需要它的原因: • 目标平台上不允许或不能够安装所需要的编译程序,而又 需要这个编译程序的某些特征 • 目标平台上的资源贫乏,无法运行所需要的编译程序 • 目的平台还没有建立,没有操作系统,根本上谈不上运行 什么编译程序 • 与主机编译相比,交叉编译受到的限制更多:专利、版权 、技术
2.编译基础设施: • 编译基础设施是编译程序的开发环境,它提供一系列开发 编译程序的策略和工具,支持多种源语言、多目标机的编 译技术,以便于人们在具有较高抽象层次的平台上进行编 译程序开发和研究工作 • 编译基础设施为开发各种编译程序成分提供相应的生成工具
3.可重定向编译程序: • 它能根据不同目标机,生成相应的目标代码,而普通编译程 序将源程序翻译成特定目标机的汇编代码或目标代码 (1)可重定向编译程序不是针对特定机器的编译程序用户 而言的可重定向 (2)可重定向编译程序不是编译程序的生成器 (3)有多个针对不同机型的可选后端
二.支持可重定向编译的关键技术 • 可重定向编译程序的目的是为了实现资源共享,方便于特 定目标机的编译程序的剪裁和移植,因此,传统的多目标 编译后端构造,中间表示、代码优化和代码生成等编译技 术,应该为可重定向编译程序的开发提供依据
1.中间表示技术: • 中间表示是在编译程序将高级语言程序翻译为汇编语言或 机器代码的过程中产生的 • 在可重定向编译程序的研究中,应提供一种结构良好的中 间表示,这种中间表示应在适当的抽象层次上,向上能支 持多语言的映射,向下能适应多平台转换且宜于进行各种 优化
2.机器描述技术: • 研究表明,基于体系结构描述语言详细地指定体系结构是 产生高质量机器级工具的关键技术
3.代码生成程序的构造技术: • 一般来说,代码生成程序的构造器的输入是机器描述,输 出是代码生成程序
4.目标机描述与目标代码生成的接口技术: • 目标机描述与目标代码生成的接口,指定了与目标机无关 的前端及与目标机有关的后端之间的相互联系
三.常用的可重定向编译程序 • 目前在全世界范围内得到广泛使用的可重定向编译程序是 GCC(GNU compiler collection) • GCC是FSF启动的GNU工程的一部分,其开发目标在于提 高GNU系统中编译程序的质量 • GCC目前已支持的源语言有:C、C++、Objective_C、 JAVA、Ada,已移植的平台有100多种,涉及30多种 处理器、60多种系统 • GCC属于自由软件: http://gcc.gnu.org/
LCC是由普林斯顿大学的Christopher Fraser和David Hanson开发的可重定向的ANSIC编译程序,可供匿名 使用
两者的主要区别在于: • 在前端和后端的数量上:GCC支持C、C++、Java等7种 源语言和MIPS、ARM等36种体系结构系列。LCC源语言 只支持标准C,后端支持ALPHA、MIPSR3000、 SPARC和x86 • 在机器描述的能力上:GCC所描述的处理器信息较多,强 于LCC • 在产生代码质量上:GCC经过20~30多遍的优化,大量测 试表明代码的稳定性较好。LCC经过少量的优化,代码质 量也比较可靠 • GCC逐渐成为工业上的主流应用,LCC应用较少,且有被 GCC取代的趋势
13.3GCC的剖析 一.GCC的总体结构 • 编译器的工作是将源代码(通常使用高级语言编写)翻译成 目标代码(通常是低级的目标代码或者机器语言),在现代 编译器的实现中,这个工作一般是分两个阶段来实现的: • 第一阶段,编译器的前端接受输入的源代码,经过词法、 语法和语义分析等等得到源程序的某种中间表示方式 • 第二阶段,编译器的后端将前端处理生成的中间表示方式 进行一些优化,并最终生成在目标机器上可运行的代码
GCC 设计中有两个重要的目标: • 在构建支持不同硬件平台的编译器时,它的代码能够最大 程度的被复用,所以GCC 必须要做到一定程度的硬件无 关性 • 要生成高质量的可执行代码,这就需要对代码进行集中的 优化。 • 为了实现这两个目标,GCC 内部使用了一种硬件平台无关 的语言,它能对实际的体系结构做一种抽象,这个中间语 言就是RTL(Register Transfer Language)
GCC编译系统由与源语言相关的前端、与源语言无关的后GCC编译系统由与源语言相关的前端、与源语言无关的后 端和目标机描述三部分组成,如图13.8所示: • 对于其支持的每种源语言,存在一个独立的、与语言相关 的语法分析器 • 利用这些语法分析器,对不同的源语言产生相同的分析结 果-语法树
二.GCC的中间表示 • 高层中间表示为语法树,低层中间表示为RTL • RTL的语法结构类似于LISP语言的表达式,真正用于编译 内部的只有91种操作码,另外的24种操作码则只出现在机 器描述中
RTL的基本元素是rtx表达式,每个表达式的外部语法形RTL的基本元素是rtx表达式,每个表达式的外部语法形 式为: (code: m opn1 opn2 ...) • code为rtx的操作码,该操作码指明rtx的操作类型, 如表示一条rtx指令、进行某种算术运行、引用某个符号 名或寄存器以及表示某种说明等等。除此这外,code还确 定rtx的操作数个数及其种类
m表示机器方式,即数据和运算结果的类型,它反映了数m表示机器方式,即数据和运算结果的类型,它反映了数 据类型与字长两部分信息 • opn为操作数。rtx操作码可以表示5种对象:一般整数、宽 整数、字符串、rtx表达式、由指向rtx的指针组成的向量
下面是一条将寄存器值送入内存的rtx表达式及其相应下面是一条将寄存器值送入内存的rtx表达式及其相应 的树结构: (insn • 11 13 (set (mem:SF (plus:S1 58) (const_int 32))) (reg:SF 71))...
图13.9中的rtx表达式表示了一条将寄存器的值送至内存的图13.9中的rtx表达式表示了一条将寄存器的值送至内存的 指令:
RTL的基本元素rtx在形式上是统一的,但根据它们允许RTL的基本元素rtx在形式上是统一的,但根据它们允许 出现的场合可分为:指令的、具有副作用的、运算的、初 等值的rtx • 表示指令的rtx一共有7条,其中最主要的是INSN、 JUMP_INSN、CALL_INSN、CODE_LABEL和NOTE, 它们分别表示一般指令、转移指令、转子指令、标号定义 和编译指导信息 • GCC中间表示中每条RTL指令实际上都表示着目标机的一 条指令
源程序中一个处理单元(函数或程序段)中所有RTL指令源程序中一个处理单元(函数或程序段)中所有RTL指令 形成了如图13.10所示的一个完整结构:
三.GCC的机器描述 1.宏定义头文件: machine.h • 定义的主要内容: (1)编译驱动程序的宏定义:用于指导编译驱动程序以什 么形式的命令行参数运行诸如预处理、编译、汇编连接等处 理步骤 (2)存储器的编址信息:如存储器的寻址单位、寻址方式 (3)各种类型数据对象的存储约定 (4)寄存器的个数、种类、名称及各种寄存器的用途约定 (5)栈的安排、函数的入口、出口及调用约定
(6)有关汇编语言输出的宏定义:指明汇编语言初始数据(6)有关汇编语言输出的宏定义:指明汇编语言初始数据 段、正文段、一般数据段等的格式要求,定义汇编输出函数 的函数名 (7)目标机操作系统所支持的目标文件格式或调试输出格 式等等
2.机器描述文件: machine.md • 它是一个正文文件 • 其中除了允许以;打头的注释行外,其余均是采用RTL外 部语法形式书写的rtx表达式 • 这些rtx表达式的操作码是专门用于机器描述的9条操作码, 由它们组成的机器描述包含目标机指令集的各种内容,主 要包括以下几个方面:
(1)目标机指令集的有关属性,主要包括: • 指令的分类 • 指令的数据类型 • 指令的长度 • 指令的延迟槽 • 功能部件 (2)指令样板,描述目标机所支持的每一条指令相应的 RTL指令形式和汇编输出格式 (3)指令样板的补充信息,指出可以进行与目标机相关的 优化动作及相应的RTL指令形式
define_insn具有4个或5个操作数,其形式和动作如下:define_insn具有4个或5个操作数,其形式和动作如下: • 操作数0为指令名,用字符串表示 • 操作数1是一个不完全的rtx表达式或向量,称为RTL模板 • 操作数2为一字符串,称为条件 • 操作数3为一字符串,称为输出模板 • 操作数4为一任选的rtx向量,称为指令属性
下面是misp.md中一条指令样板的例子: • (define_insn “adddf3” • (set(match_operand:DF 0 “register_operand” “f”) • (plus:DF(match_operand:DF 2 “register_operand” “f”) • (match_operand:DF 2 “register_operand” “f”)))) • “TARGER_HARD_FLOAT” • “add.d\\t %0,%1,%2” • ((set_attr“type”“tadd”) • (set_attr“mode”“DF”) • (set_attr“length”“1”)
RTL模板中set和plus运算涉及的操作数均为形式如下的特RTL模板中set和plus运算涉及的操作数均为形式如下的特 殊rtx的表达式:(match_operand:m n predicate constaint) • 该表达式专门用于表示操作数 • n指明为第几个操作数 • m为操作数的方式 • predicate指明操作数必须满足的匹配条件 • constaint为对操作数的限制
如图13.11所示,指令样板有两个重要作用:用于构造中间如图13.11所示,指令样板有两个重要作用:用于构造中间 语言RTL中的指令、确定汇编代码的输出格式;它是支持 多平台思想得到实现的核心部分:
四.GCC的代码生成与机器描述的接口 • GCC的机器描述文件都是普通的正文文件,在编译过程 中,如果为构造或匹配RTL在这种文件中搜索,那是极其 缓慢的 • 为此,一方面,在编译内部设计了一套专门的函数和数据 结构作为编译主体与机器描述之间的接口,另一方面,在 编译之外设计了一套独立的、专用的机器描述处理程序, 这套程序将正文形式的机器描述转换成方便接口调用的数 据结构与函数
在GCC中,机器描述处理程序由11个独立的程序组成,每在GCC中,机器描述处理程序由11个独立的程序组成,每 个程序处理机器描述文件的一部分内容,它们各自形成相 应的C源程序,分别作用于RTL生成、机器相关优化和汇 编代码输出等过程。其对应关系如图13.12所示:
对于前面给出的mips.md中的那条双精度浮点加指令样板,对于前面给出的mips.md中的那条双精度浮点加指令样板, 经过gen*处理后产生的内容如图13.13所示:
对于每个标准运算,GCC内部有一张操作表,其形式如图对于每个标准运算,GCC内部有一张操作表,其形式如图 13.14所示: