CalcSpillWeights

这个“Pass”实际上是 LLVM 寄存器分配器(GreedyRegisterAllocator)在分配前对每个虚拟寄存器(virtual register)做的辅助信息计算,主要包括两部分:

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