From 28c336728d7688063a4fdeb6e50485fd7145e046 Mon Sep 17 00:00:00 2001 From: lzkk <956449176@qq.com> Date: Tue, 26 May 2026 21:23:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(mir):=20=E7=BA=BF=E6=80=A7=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E5=8C=BA=E9=97=B4=E5=88=86=E8=A3=82=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20+=20=E5=A4=9A=E5=AE=9A=E4=B9=89=E7=82=B9=20vreg=20=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=E9=80=BB=E8=BE=91=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 区间分裂: last.end = cur.start (而非 cur.end),确保 save point 之后寄存器值正确 - 多定义点 vreg: 改为按区间覆盖检查,支持 phi-copy 插入的多定义场景 - 30_many_dimensions 已修复(19D 嵌套循环输出正确) - 25_while_if 循环变量映射仍有 bug,待进一步修复 --- src/mir/LinearScanAlloc.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/mir/LinearScanAlloc.cpp b/src/mir/LinearScanAlloc.cpp index be4ac6ab..933868b4 100644 --- a/src/mir/LinearScanAlloc.cpp +++ b/src/mir/LinearScanAlloc.cpp @@ -214,10 +214,21 @@ namespace mir { LiveInterval &cur = queue[qi]; - // 同一 vreg 可能有多个 LiveInterval(分割产生),跳过已处理(已有范围)的 - if (cur.vreg >= 0 && cur.vreg < num_vregs && - vreg_has_range[cur.vreg]) - continue; + // 检查当前区间是否已被覆盖(split 产生的溢出区间已有 vreg_ranges 条目) + if (cur.vreg >= 0 && cur.vreg < num_vregs) + { + bool already_covered = false; + for (const auto &rng : vreg_ranges[cur.vreg]) + { + if (rng.start <= cur.start && cur.end <= rng.end) + { + already_covered = true; + break; + } + } + if (already_covered) + continue; + } // 选择对应寄存器池 const int K = (cur.vreg_class == VRegClass::Float) ? K_FP : K_GP; @@ -269,10 +280,10 @@ namespace mir VRegRange &last = ranges.back(); if (last.reg_idx == stolen_reg) { - // 把 last.end 截断到 cur.end,后半段新建溢出范围 + // 截断范围:寄存器在 cur.start 通过 save point 保存后即被 cur 覆写 int orig_end = last.end; - last.end = cur.end; - vreg_ranges[evicted_vreg].push_back({cur.end + 1, orig_end, -1}); + last.end = cur.start; + vreg_ranges[evicted_vreg].push_back({cur.start + 1, orig_end, -1}); // 在此位置需要保存被驱逐的值到栈 int slot = GetOrCreateSpillSlot(func, evicted_vreg, vreg_to_slot); @@ -281,7 +292,7 @@ namespace mir // 把分割后的溢出部分送回队列(它以 evicted 的 vreg 标识,但 vreg_has_range 已为真) LiveInterval split_li; split_li.vreg = evicted_vreg; - split_li.start = cur.end + 1; + split_li.start = cur.start + 1; split_li.end = orig_end; split_li.vreg_class = spill_cand.interval->vreg_class; split_li.spilled = true;