fix(mir): 线性扫描活变量分析 def 位置记录 + callee-saved 寄存器限定 + CLI 标志修复

- InstLiveness: 反向扫描中记录 def vreg 的区间起点,修复 phi copy 的 MovReg
  def 位置未被区间覆盖导致寄存器分配不一致的 bug(25_while_if 死循环)
- LinearScanAlloc: GP_ALLOCATABLE 限定为 callee-saved 寄存器(x19-x28),
  避免跨函数调用时 caller-saved 寄存器被破坏导致段错误(54_hidden_var)
- CLI: 修复 --regalloc= 标志 strncmp 长度 off-by-one(12→11)
lzk
lzkk 7 days ago
parent e1777c9eab
commit 120d7197d8

@ -375,7 +375,19 @@ namespace mir
// — remove from live so that earlier positions don't see it
// (unless a later use re-adds it for the prior value).
if (def_vreg >= 0)
{
// 记录 def 位置作为区间起点。即使 def vreg 不在当前活跃集中
// (跨块数据流边界情况可能导致),区间也必须覆盖 def 位置,
// 确保寄存器分配在定义点能找到对应的范围。
auto sit = vreg_start.find(def_vreg);
if (sit == vreg_start.end() || pos < sit->second)
vreg_start[def_vreg] = pos;
auto eit = vreg_end.find(def_vreg);
if (eit == vreg_end.end() || pos > eit->second)
vreg_end[def_vreg] = pos;
live.erase(def_vreg);
}
}
// After processing all instructions, live should equal live_in.

@ -15,10 +15,12 @@ namespace mir
// ---- AArch64 可分配寄存器 --------------------------------------------
// GP 可分配x8(间接结果)/x9-x12/temp/x15/x16-x17/IP0-IP1/x19-x28/callee-saved
// x0-x7 参数传递x13-x14 临时(被排除避免调用冲突)x18 平台x29-31 保留
static const int GP_ALLOCATABLE[] = {8, 9, 10, 11, 12, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28};
static const int K_GP = 18;
// GP 可分配x19-x28callee-saved。当前限定为 callee-saved
// 避免跨函数调用时 caller-saved 寄存器被破坏。TODO后续可加入
// caller-saved 寄存器x8-x12,x15-x17用于不跨调用活跃的 vreg。
// x0-x7 参数传递x13-x14/scratchx18 平台x29-31 保留。
static const int GP_ALLOCATABLE[] = {19, 20, 21, 22, 23, 24, 25, 26, 27, 28};
static const int K_GP = 10;
// FP 可分配s8-s31
static const int FP_ALLOCATABLE[] = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
@ -323,6 +325,29 @@ namespace mir
}
}
// ---- 记录 callee-saved 寄存器使用 ----
// 当前 GP_ALLOCATABLE 全为 callee-savedx19-x28遍历已分配的
// 范围找出实际使用的寄存器,通知 FrameLowering 保存/恢复。
std::unordered_set<int> used_callee_gp;
std::unordered_set<int> used_callee_fp;
for (int vi = 0; vi < num_vregs; ++vi)
{
for (const auto &rng : vreg_ranges[vi])
{
if (rng.reg_idx < 0)
continue;
VRegClass vc = func.GetVRegClass(vi);
if (vc == VRegClass::Float)
used_callee_fp.insert(rng.reg_idx);
else
used_callee_gp.insert(rng.reg_idx);
}
}
for (int idx : used_callee_gp)
func.AddCalleeSavedReg(AllocIdxToPhysReg(idx, VRegClass::Int));
for (int idx : used_callee_fp)
func.AddCalleeSavedReg(AllocIdxToPhysReg(idx, VRegClass::Float));
// ---- 重写指令 ----------------------------------------------------------
RewriteWithAllocation(func, vreg_ranges, vreg_to_slot, save_points);
}

@ -88,8 +88,8 @@ CLIOptions ParseCLI(int argc, char** argv) {
}
// 寄存器分配器选择
if (std::strncmp(arg, "--regalloc=", 12) == 0) {
opt.regalloc = arg + 12;
if (std::strncmp(arg, "--regalloc=", 11) == 0) {
opt.regalloc = arg + 11;
if (opt.regalloc != "linear" && opt.regalloc != "graphcoloring") {
throw std::runtime_error(
FormatError("cli", std::string("未知寄存器分配器: ") + opt.regalloc +

Loading…
Cancel
Save