溢出发生在寄存器分配(regalloc)pass阶段,由分配器在machineinstr层显式插入spill/reload指令,生成frameindex占位符,后续经stackslotcoloring和prologepiloginserter完成栈槽布局与地址计算。

LLVM 后端不“自动实现”寄存器溢出和重载——它在寄存器分配阶段显式插入 spill 和 reload 指令,由分配器决定何时、何处、如何溢出,并交由后续 pass(如 StackSlotColoring、PrologEpilogInserter)完成栈槽布局与指令替换。
溢出发生在哪个 Pass 阶段?
溢出决策由寄存器分配器(RegAlloc)在 Machinelnstr 层完成,不是 IR 层或 SelectionDAG 层。此时虚拟寄存器(%vreg123)已存在,但尚未绑定物理寄存器(如 %rax 或 %r10)。分配器发现无空闲物理寄存器时,会:
- 选一个高溢出权重(spill weight)的活跃虚拟寄存器
- 为其分配一个栈槽(
FrameIndex,如%stack.42) - 在需要保存的位置插入
STORE指令(如x86_store64) - 在需要读取的位置插入
LOAD指令(如x86_load64) - 将原指令中对该
%vreg的引用全部替换为对应FrameIndex
注意:spill 和 reload 不是函数调用,也不是运行时机制;它们是编译期生成的机器指令,和普通 load/store 无本质区别。
不同分配器对溢出行为的影响
LLVM 提供多个分配器,溢出策略差异显著:
-
-regalloc=basic:按溢出权重排序,贪心分配;溢出后不尝试分裂活跃区间,容易产生冗余 load/store -
-regalloc=fast:块内本地分配,不跨基本块保留寄存器;溢出频繁但速度快,适合调试构建 -
-regalloc=pbqp:基于 PBQP(Partitioned Boolean Quadratic Programming)建模,把溢出代价编码进优化目标;能更精细地权衡 spill/reload 开销与寄存器竞争 -
-regalloc=greedy(默认):结合线性扫描与图着色思想,支持活跃区间分裂(live range splitting),可推迟溢出、减少总 spill 次数
例如,greedy 在遇到长生命周期虚拟寄存器时,可能只 spill 它的某一段使用区间,而非整个生命周期——这依赖于 LiveRangeEdit 和 SplitEditor 等基础设施,不是所有分配器都支持。
栈槽怎么变成真实内存地址?
溢出产生的 FrameIndex 是符号化占位符,不带偏移量。真正计算地址是在 PrologEpilogInserter 和 StackSlotColoring 之后,由 TargetFrameLowering 实现类完成:
-
getFramePointerRegister()和getStackAlignment()决定帧指针/栈指针选择与对齐方式 -
eliminateCallFramePseudoInstr()把伪指令(如CFA_OFFSET)转为真实 add/sub - 最终每个
FrameIndex被映射到相对于rbp或rsp的固定偏移,如-16(%rbp)
如果你用 llc -debug-pass=Structure 观察流水线,会看到 StackSlotColoring 出现在 RegAlloc 之后、PrologEpilogInserter 之前——这个顺序不能颠倒,否则栈槽布局未定,溢出指令无法生成有效地址。
重载(reload)不是独立动作,而是 spill 的镜像
所谓“重载”,只是分配器在某个 use 点前插入一条 LOAD 指令,读取之前 STORE 到栈槽的值。它没有额外语义:
- 不会触发缓存预热,不绕过 MMU,不涉及 TLB 命中逻辑
- 如果该栈槽被分配在 red zone(x86-64 下 128 字节),甚至可能完全避免栈指针调整
- 若同一栈槽被多次 reload,LLVM 默认不做去重;需靠后续的
MachineCopyPropagation或EarlyCSE优化消除冗余 load
真正影响 reload 效率的,是活跃区间是否被合理分裂。一个未分裂的长区间,会导致反复 spill/reload;而一次精准的 split,可能让 reload 只发生一次,后面全程走寄存器。
最容易被忽略的是:溢出引入的 load/store 本身会延长指令延迟、增加寄存器压力,并可能触发新的溢出循环。所以实际调优时,与其盯着单个变量要不要 spill,不如看整个函数的 getMaxCallFrameSize() 和 getNumVirtRegs() ——它们才是压力的真实刻度。











