diff --git a/src/include/mir/MIR.h b/src/include/mir/MIR.h index 88e6ea38..3022c33f 100644 --- a/src/include/mir/MIR.h +++ b/src/include/mir/MIR.h @@ -547,7 +547,8 @@ namespace mir public: void Init(int num_regs); - void Assign(LiveInterval *li, int phys_reg); + bool Assign(LiveInterval *li, int phys_reg); + void ForceAssign(LiveInterval *li, int phys_reg); void Unassign(LiveInterval *li); bool CheckInterference(const LiveInterval &li, int phys_reg) const; LiveInterval *GetConflict(const LiveInterval &li, int phys_reg) const; diff --git a/src/mir/GreedyAlloc.cpp b/src/mir/GreedyAlloc.cpp index 7f8e2468..491d5c7e 100644 --- a/src/mir/GreedyAlloc.cpp +++ b/src/mir/GreedyAlloc.cpp @@ -39,7 +39,9 @@ const int* GetRegList(RegClass rc, int& count) // 堆排序:高 cascade(已被驱逐过的)永远排在低 cascade 之后; // 同等 cascade 按 spill_weight 降序(堆顶权重最大,优先分配)。 -// heap 存储 vreg 索引,避免 TrySplit 中 intervals.push_back 导致指针失效 +// heap 存储 vreg 索引 +// Stage 0 (new): 短活范围优先——弦图完美消除序近似 +// Stage 1+ (deferred/evicted): spill_weight 降序 struct SpillWeightCmp { const std::vector& intervals; @@ -50,6 +52,8 @@ struct SpillWeightCmp const auto& lb = intervals[b]; if (la.generation != lb.generation) return la.generation > lb.generation; + if (la.deferred_count == 0 && lb.deferred_count == 0) + return la.Length() > lb.Length(); return la.spill_weight < lb.spill_weight; } }; @@ -220,9 +224,8 @@ bool TryAssign(LiveInterval &li, LiveRegMatrix &m, int hint) { if (hint < 0) return false; if (IsCallerSavedGP(hint) && li.SegmentCrossesCall()) return false; - if (!m.CheckInterference(li, hint)) + if (!m.CheckInterference(li, hint) && m.Assign(&li, hint)) { - m.Assign(&li, hint); li.assigned_reg = hint; return true; } @@ -238,9 +241,8 @@ bool TryAnyFreeReg(LiveInterval &li, LiveRegMatrix &m) { int r = regs[i]; if (IsCallerSavedGP(r) && li.SegmentCrossesCall()) continue; - if (!m.CheckInterference(li, r)) + if (!m.CheckInterference(li, r) && m.Assign(&li, r)) { - m.Assign(&li, r); li.assigned_reg = r; return true; } @@ -266,9 +268,8 @@ bool TryEvict(LiveInterval &li, LiveRegMatrix &m, int r = regs[i]; if (IsCallerSavedGP(r) && li.SegmentCrossesCall()) continue; auto *conflict = m.GetConflict(li, r); - if (!conflict) + if (!conflict && m.Assign(&li, r)) { - m.Assign(&li, r); li.assigned_reg = r; return true; } @@ -290,13 +291,16 @@ bool TryEvict(LiveInterval &li, LiveRegMatrix &m, heap.push_back(victim->vreg); std::push_heap(heap.begin(), heap.end(), cmp); - m.Assign(&li, best_reg); - li.assigned_reg = best_reg; - return true; + if (m.Assign(&li, best_reg)) + { + li.assigned_reg = best_reg; + return true; + } + return false; } -// ---- TrySplit(简化版——只用于最复杂的 vreg)---- - // 注意:push_back 会使引用失效,通过 vreg 索引安全访问 +// ---- TrySplit:在最大使用间隙处分裂(LLVM local split 简化版)---- + // 参考: llvm/lib/CodeGen/RegAllocGreedy.cpp tryLocalSplit() bool TrySplit(int vreg_idx, LiveRegMatrix &m, std::vector &heap, std::vector &intervals, @@ -308,26 +312,27 @@ bool TryEvict(LiveInterval &li, LiveRegMatrix &m, auto &li = intervals[vreg_idx]; if (li.uses.size() < 3) return false; - // 在中间位置分裂:hot 段尝试分配,cold 段入堆 - int mid = (int)li.uses.size() / 2; - int split_pos = li.uses[mid].pos; - int hot_start = li.FirstUsePos(); - int hot_end = split_pos; - int cold_start = split_pos + 1; - int cold_end = li.LastUsePos(); + std::vector sorted_uses; + for (auto &u : li.uses) sorted_uses.push_back(u.pos); + std::sort(sorted_uses.begin(), sorted_uses.end()); + + int best_gap = 0, split_after = -1; + for (size_t i = 1; i < sorted_uses.size(); ++i) { + int gap = sorted_uses[i] - sorted_uses[i - 1]; + if (gap > best_gap && gap >= 2) { best_gap = gap; split_after = sorted_uses[i - 1]; } + } + if (split_after < 0) return false; + int hot_start = li.FirstUsePos(), hot_end = split_after; + int cold_start = split_after + 1, cold_end = li.LastUsePos(); if (hot_end < hot_start || cold_end < cold_start) return false; - // 构建 cold 子区间(在 push_back 前提取所需字段,避免引用失效) LiveInterval cold; - cold.reg_class = li.reg_class; - cold.generation = li.generation + 1; - cold.hint_reg = -1; - cold.assigned_reg = -1; + cold.reg_class = li.reg_class; cold.generation = li.generation + 1; + cold.hint_reg = -1; cold.assigned_reg = -1; cold.vreg = func.CreateVReg(li.vreg_class); - for (auto &seg : li.segments) - { + for (auto &seg : li.segments) { if (seg.end < cold_start || seg.start > cold_end) continue; Segment clipped = seg; clipped.start = std::max(seg.start, cold_start); @@ -335,63 +340,37 @@ bool TryEvict(LiveInterval &li, LiveRegMatrix &m, cold.segments.push_back(clipped); } for (auto &use : li.uses) - if (cold_start <= use.pos && use.pos <= cold_end) - cold.uses.push_back(use); - + if (cold_start <= use.pos && use.pos <= cold_end) cold.uses.push_back(use); if (cold.uses.empty()) return false; float w = 0.0f; - for (auto &use : cold.uses) - { - int blk = (use.pos >= 0 && use.pos < (int)pos_to_block.size()) - ? pos_to_block[use.pos] : 0; - float mult = 1.0f; - if (use.is_def) mult *= 0.5f; + for (auto &use : cold.uses) { + int blk = (use.pos >= 0 && use.pos < (int)pos_to_block.size()) ? pos_to_block[use.pos] : 0; + float mult = use.is_def ? 0.5f : 1.0f; w += mult; } cold.spill_weight = w / cold.Length(); - int cold_vreg = cold.vreg; intervals.push_back(std::move(cold)); - // push_back 后 li 引用可能失效,通过 vreg_idx 安全访问 - // 修剪原 vreg 为 hot 段 auto &li_safe = intervals[vreg_idx]; std::vector hot_segs; - for (auto &seg : li_safe.segments) - { + for (auto &seg : li_safe.segments) { if (seg.end < hot_start || seg.start > hot_end) continue; Segment clipped = seg; clipped.start = std::max(seg.start, hot_start); clipped.end = std::min(seg.end, hot_end); - if (clipped.start <= clipped.end) - hot_segs.push_back(clipped); + if (clipped.start <= clipped.end) hot_segs.push_back(clipped); } li_safe.segments = std::move(hot_segs); - li_safe.uses.erase( - std::remove_if(li_safe.uses.begin(), li_safe.uses.end(), - [&](const UsePosition &u) { - return u.pos < hot_start || u.pos > hot_end; - }), - li_safe.uses.end()); - - // 尝试给 hot 分配 - if (!TryAnyFreeReg(li_safe, m)) - { - li_safe.assigned_reg = -2; - spilled.push_back(vreg_idx); - } + li_safe.uses.erase(std::remove_if(li_safe.uses.begin(), li_safe.uses.end(), + [&](const UsePosition &u) { return u.pos < hot_start || u.pos > hot_end; }), li_safe.uses.end()); - // cold 入堆 + if (!TryAnyFreeReg(li_safe, m)) { li_safe.assigned_reg = -2; spilled.push_back(vreg_idx); } auto &cold_ref = intervals[cold_vreg]; - if (!TryAnyFreeReg(cold_ref, m)) - { - heap.push_back(cold_vreg); - std::push_heap(heap.begin(), heap.end(), cmp); - } + if (!TryAnyFreeReg(cold_ref, m)) { heap.push_back(cold_vreg); std::push_heap(heap.begin(), heap.end(), cmp); } return true; } - // ---- 主分配函数:对一类寄存器执行贪婪分配 ---- // 返回 spilled 数量 int AllocateRegClass(std::vector &intervals, @@ -469,10 +448,17 @@ int AllocateRegClass(std::vector &intervals, void LiveRegMatrix::Init(int num_regs) { reg_assignments_.assign(num_regs, {}); } -void LiveRegMatrix::Assign(LiveInterval *li, int phys_reg) +void LiveRegMatrix::ForceAssign(LiveInterval *li, int phys_reg) { - if (phys_reg < 0 || phys_reg >= (int)reg_assignments_.size()) return; + if (phys_reg >= 0 && phys_reg < (int)reg_assignments_.size()) + reg_assignments_[phys_reg].push_back(li); +} + +bool LiveRegMatrix::Assign(LiveInterval *li, int phys_reg) +{ + if (phys_reg < 0 || phys_reg >= (int)reg_assignments_.size()) return false; reg_assignments_[phys_reg].push_back(li); + return true; } void LiveRegMatrix::Unassign(LiveInterval *li) @@ -581,7 +567,7 @@ static void AllocateRegistersForFunction(MachineFunction &function) { if (li.vreg >= 0 && li.IsAllocated() && (li.reg_class == RegClass::GPR32 || li.reg_class == RegClass::GPR64)) - gp_matrix.Assign(&li, li.assigned_reg); + gp_matrix.ForceAssign(&li, li.assigned_reg); } AllocateRegClass(intervals, RegClass::GPR32, gp_matrix, @@ -597,7 +583,7 @@ static void AllocateRegistersForFunction(MachineFunction &function) for (auto &li : intervals) { if (li.vreg >= 0 && li.IsAllocated() && li.reg_class == RegClass::FPR32) - fp_matrix.Assign(&li, li.assigned_reg); + fp_matrix.ForceAssign(&li, li.assigned_reg); } AllocateRegClass(intervals, RegClass::FPR32, fp_matrix,