Hasty Briefsbeta

双语

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处理的复杂性。