线性扫描寄存器分配:SSA 形式与寄存器约束下的高效实现
1. 引言
寄存器分配是为程序中的变量和临时变量分配寄存器的任务,对编译代码的效率至关重要。传统的寄存器分配标准算法基于图着色,它构建干扰图,图中节点代表程序中的值,若两个值同时存活则在它们之间连边,然后对图进行着色,使相邻节点颜色不同,颜色可视为寄存器,从而实现寄存器分配。
然而,在某些情况下,图着色算法速度过慢,例如在即时(JIT)编译器中,它需要在加载甚至运行时将中间程序表示转换为机器代码。JIT 编译器需在极短时间内完成任务并生成高质量代码,这促使了线性扫描寄存器分配技术的出现。线性扫描在一次线性遍历程序中所有值的存活区间时为值分配寄存器,若两个值的存活区间重叠,则它们不能存于同一寄存器。尽管图着色的寄存器分配效果略好,但线性扫描速度快数倍,因此在 JIT 编译器中颇具吸引力。
本文实现线性扫描寄存器分配技术有两大贡献:一是基于静态单赋值形式(SSA 形式)的程序进行分配,这简化了数据流分析并倾向于产生更短的存活区间,但需对原线性扫描算法进行修改;二是展示如何将线性扫描应用于像 Intel x86 这样的寄存器受限架构,以往相关算法多针对 RISC 架构,而 Intel x86 这类 CISC 机器因双地址指令及某些操作对特定寄存器的要求,需对基本算法进行修改。
2. 线性扫描寄存器分配
线性扫描由 Poletto 等人提出,作为图着色分配的替代方法。它计算程序中值的存活区间并顺序扫描以找出重叠部分,非重叠区间可分配到同一寄存器。由于值的存活区间可能存在该值不存活的空洞,Traub 等人提出了改进版算法(二次机会装箱),虽更复杂,但能更好地利用寄存器,还会分割存活区间使值