后端辅助类——CalcSpillWeights
CalcSpillWeights
这个“Pass”实际上是 LLVM 寄存器分配器(GreedyRegisterAllocator)在分配前对每个虚拟寄存器(virtual register)做的辅助信息计算,主要包括两部分:
- 计算 Spill Weight(溢出权重)
- 对每个虚拟寄存器的 LiveInterval 调用
weightCalcHelper()
,遍历所有对该寄存器的读写操作,根据:- 写操作/读操作的数量(
getSpillWeight
) - 是否在循环退出时写入(增加权重乘以 3)
- 区间长度或指令数目进行归一化
- 本地拆分(local split artifact)产生的额外 copy 指令
- 可重计算(rematerializable)定义会将总权重减半
- 寄存器类的缩放因子(
getSpillWeightScaleFactor
)
- 写操作/读操作的数量(
- 特殊情况下,将寄存器标记为“不可溢出”(unspillable),包括:
- 遇到 “unspillable terminator”
- 零长度区间且无活跃掩码、非 statepoint 可变参、无法内联汇编折叠
- 最后把得出的浮点权重通过
LiveInterval::setWeight
写回,供后续 allocator 决策。
- 对每个虚拟寄存器的 LiveInterval 调用
- 生成 Register Allocation Hints(寄存器分配提示)
- 在遍历定义/使用指令时,遇到 copy 指令调用
copyHint()
:- 如果是虚寄存器到物理寄存器的纯 copy,就提取那个物理寄存器作为 hint;
- 否则也可能把另一个虚寄存器当作分配 hint,前提是它的寄存器类兼容。
- 汇总所有 copy 产生的 hint,并按“物理寄存器优先 → 权重 → 非 CSR 优先”等规则排序后,通过
MRI.addRegAllocationHint
添加到MachineRegisterInfo
。
同时,这个模块还提供了几个辅助判断函数:
- 在遍历定义/使用指令时,遇到 copy 指令调用
isRematerializable()
:检查一个虚拟寄存器的所有定义是否都可以“重计算”(无需真正 load),如果是则倾向于 spill。isLiveAtStatepointVarArg()
:判断在 statepoint(GC 安全点)可变参中是否仍然活跃,从而决定是否必须 spill。canMemFoldInlineAsm()
:查看内联汇编中的寄存器操作是否可以直接折叠到内存访问,从而影响 spill 决策。
评论