Register allocation in the Go compiler (2024)
8 months ago
- #compiler
- #Go
- #register-allocation
- Go编译器的寄存器分配器(RA)基于SSA(静态单赋值)形式工作,这与编译器中的其他优化阶段类似。
- Go寄存器分配器的关键组件包括:关键边消除、条件码值分配的flagalloc、垃圾回收的活跃值分析、寄存器分配(regalloc)和栈分配(stackalloc)。
- 寄存器分配是最复杂的部分,它按控制流图(CFG)的前序处理基本块(BBs),并跟踪寄存器或内存中的活跃值。
- 当寄存器不足时,RA采用启发式策略(如到下次使用的最长距离)决定溢出哪些值,该距离受基本块布局影响。
- Phi值及其操作数必须占用相同位置(寄存器或栈),这需要特殊处理并可能产生复制操作。
- 栈槽分配通过非重叠SSA值共享槽位来优化栈使用,采用冲突图进行优化。
- RA通过特殊操作(StoreReg/LoadReg/Copy)保持SSA形式,但分配后会产生无效SSA,这会限制后续优化。
- RA算法类似二次机会装箱策略而非线性扫描,重点关注CFG合并点和溢出位置选择。
- 调用ABI假设所有寄存器都会被调用破坏,导致低效代码;使用调用保留寄存器可提升性能。
- Go RA的优势包括代码精简、速度快、栈槽共享高效,缺点在于缺乏全局视角和Phi处理的复杂性。