声明:本系列文章,是根据中国大学MOOC网 哈工大的编译原理 这门课学习而成的学习笔记。
一、代码生成器的主要任务
指令选择
选择适当的目标机指令来实现中间表示(IR)语句
寄存器分配和指派
把哪个值放在哪个寄存器中
指令排序
按照什么顺序来安排指令的执行
二、一个简单的目标机模型
地址机器模型
- 加载、保存、运算、跳转等操作
- 内存按字节寻址
- n个通用寄存器R0, R1, …, Rn-1
- 假设所有的运算分量都是整数
- 指令之间可能有一个标号
目标机器的主要指令
寻址模式
三、指令选择
运算语句的目标代码
数组寻址语句的目标代码
指针存取语句的目标代码
指针存取语句的目标代码
条件跳转语句的目标代码
过程调用和返回的目标代码
四、寄存器的选择
三地址语句的目标代码生成
寄存器描述符和地址描述符
- 寄存器描述符 ( register descriptor )
记录每个寄存器当前存放的是哪些变量的值 - 地址描述符 ( address descriptor )
记录运行时每个名字的当前值存放在哪个或哪些位置
该位置可能是寄存器、栈单元、内存地址或者是它们的某个集合
这些信息可以存放在该变量名对应的符号表条目中
基本块的收尾处理
- 对于一个在基本块的出口处可能活跃的变量x , 如果它的地址描述符表明它的值没有存放在x的内存位置上, 则生成指令“ST x, R” ( R是在基本块结尾处存放 x值的寄存器 )
管理寄存器和地址描述符
当代码生成算法生成加载、保存和其他指令时,它必须同时更新寄存器和地址描述符
开始时,各个寄存器的值为空,a,b,c,d依次存放在它们各种的内存地址中
对第一条指令生成三地址指令,将a和b分别放入寄存器R1,R2,同时修改a,b的地址描述符,增加对应的位置
执行sub,将运算后的t的值送人R2中,将t的地址描述符添加上R2,此时R2存的是t,在从任何不等于t的地址描述符中删除R2的位置信息,此后同理。
最后,由于a,b,c,d是活跃的,所有最后再使a和d包含自己的内存地址
五、寄存器选择函数getReg的设计
寄存器选择函数getReg
计算R的“费用”
寄存器Rx的选择
六、窥孔优化
- 窥孔(peephole)是程序上的一个小的滑动窗口
- 窥孔优化是指在优化的时候,检查目标指令的一个滑动窗口(即窥孔) ,并且只要有可能就在窥孔内用更快或更短的指令来替换窗口中的指令序列
- 也可以在中间代码生成之后直接应用窥孔优化来提高中间表示形式的质量
具有窥孔优化特点的程序变换的例子
- 冗余指令删除
- 控制流优化
- 代数优化
- 机器特有指令的使用
冗余指令删除
控制流优化
代数优化
- 代数恒等式
消除窥孔中类似于x=x+0或x=x*1的运算指令 - 强度削弱
对于乘数(除数)是2的幂的定点数乘法(除法) ,用移位运算实现代价比较低
除数为常量的浮点数除法可以通过乘数为该常量倒数的乘法来求近似值
特殊指令的使用
- 充分利用目标系统的某些高效的特殊指令来提高代码效率
例如:INC指令可以用来替代加1的操作