《Engineering a Complier》学习笔记(七)
代码形式(Code Shape)
编译器生成IR后,必须将每个源语言语句映射为目标机指令构成的操作序列。编译器必须在许多备选方法中做出选择,以实现语言中的每个结构。编译器所做的选择影响最终代码的质量。
1.分配存储结构
- 物理寄存器: 目标ISA中一个命名的寄存器
- 虚拟寄存器: IR使用的一个符号名,以代替物理寄存器名
编译器可能创建额外的静态数据区,以保存常量值、跳转表和调试信息。
逻辑地址空间布局:
地址空间的不同视图:
数据区的布局规则:
如果x声明在过程p局部,且值无需跨多次调用 -> 分配到局部储存
如果值跨越对p的多次调用而保持 -> 分配到局部静态存储区中
如果x全局可见 -> 分配到全局存储区
如果x的分配收全局控制 -> 分配到堆
1. 分配偏移量
编译器必须为每个名字分配数据区内部的一个偏移量
x2. 相对偏移量和高速缓存性能
高速缓存在现代计算机系统中的广泛应用,对变量在内存中的布局有微妙的影响。如果代码中使用两个值位置十分接近,则编译器可能想确保二者同时加载到高速缓存中。
对程序中计算的每个值,编译器都必须确定在何处存储该值,是在内存中还是在寄存器中,不管那种情况,都要给出具体的位置。
存储分配为编译器提供了一个关键的机会,编译器可以借此将信息编码到IR中,供后续各趟处理使用。
2. 算数运算符
以a-b*c为例,树遍历代码生成器:
未完待续