|
|
|
|
@ -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<LiveInterval>& 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<int> &heap,
|
|
|
|
|
std::vector<LiveInterval> &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<int> 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<Segment> 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<LiveInterval> &intervals,
|
|
|
|
|
@ -469,10 +448,17 @@ int AllocateRegClass(std::vector<LiveInterval> &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,
|
|
|
|
|
|