fix: nested 子模块引用父槽无预着色保护致读错物理槽

子模块 alloc 时引用父槽的 LOAD_VAR.a/STORE_VAR.rd 被当作自身 vreg 染色移走,
父侧 collect_escaped 只保护父不移动槽,子侧无对称保护。以 param_layout.base
(inherited_reg_start 分界)识别父槽引用并预着色恒等,spill 自由色排除。

新增 nested_parent_slot_regress 回归测试(field/method + 高压力变量),
workspace 全绿 + clippy 干净。
This commit is contained in:
2026-08-06 20:34:55 +08:00
parent c47a0a73d1
commit d65fa03de6
3 changed files with 145 additions and 0 deletions
+24
View File
@@ -269,6 +269,9 @@ pub(super) fn spilled_builtin_bindings(f: &IRFunction, map: &AllocMap) -> Vec<(S
}
// escaped 色(递归 nested 的 LOAD_VAR.a / STORE_VAR.rd)
collect_escaped(&f.nested, &mut excluded);
// own-escaped 色(B013 延伸):本函数 LOAD_VAR.a / STORE_VAR.rd 引用父槽(< base)。
// 与 graph.rs collect_own_escaped 对称——spill 自由色不得占用父槽号。
collect_own_escaped(f, &mut excluded);
// 窗口
for c in map.arg_window_base..=253 {
excluded.push(c);
@@ -321,6 +324,27 @@ fn collect_escaped(nested: &[IRFunction], out: &mut Vec<u32>) {
}
}
/// 收集本函数 LOAD_VAR.a / STORE_VAR.rd 中引用父槽(槽号 < param_layout.base)的 vreg。
/// 与 graph.rs::collect_own_escaped 对称:base = emit inherited_reg_start 分界线。
fn collect_own_escaped(f: &IRFunction, out: &mut Vec<u32>) {
let base = f.param_layout.base;
if base == 0 {
return;
}
for inst in &f.insts {
let slot = match inst.op {
OpCode::LOAD_VAR => inst.a,
OpCode::STORE_VAR => inst.rd,
_ => Operand::None,
};
if let Operand::Reg(r) = slot {
if r < base {
out.push(r);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;