|
|
|
|
@ -296,95 +296,101 @@ bool TryEvict(LiveInterval &li, LiveRegMatrix &m,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- TrySplit(简化版——只用于最复杂的 vreg)----
|
|
|
|
|
bool TrySplit(LiveInterval &li, LiveRegMatrix &m,
|
|
|
|
|
std::vector<int> &heap,
|
|
|
|
|
std::vector<LiveInterval> &intervals,
|
|
|
|
|
const std::vector<int> &pos_to_block,
|
|
|
|
|
std::vector<int> &spilled,
|
|
|
|
|
MachineFunction &func,
|
|
|
|
|
const SpillWeightCmp &cmp)
|
|
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
if (hot_end < hot_start || cold_end < cold_start) return false;
|
|
|
|
|
|
|
|
|
|
// 构建 cold 子区间
|
|
|
|
|
LiveInterval cold;
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (seg.end < cold_start || seg.start > cold_end) continue;
|
|
|
|
|
Segment clipped = seg;
|
|
|
|
|
clipped.start = std::max(seg.start, cold_start);
|
|
|
|
|
clipped.end = std::min(seg.end, cold_end);
|
|
|
|
|
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.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;
|
|
|
|
|
w += mult;
|
|
|
|
|
}
|
|
|
|
|
cold.spill_weight = w / cold.Length();
|
|
|
|
|
|
|
|
|
|
intervals.push_back(std::move(cold));
|
|
|
|
|
LiveInterval &cold_ref = intervals.back();
|
|
|
|
|
|
|
|
|
|
// 修剪 li 为 hot 段
|
|
|
|
|
li.segments.clear();
|
|
|
|
|
for (auto &seg : intervals[li.vreg].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)
|
|
|
|
|
li.segments.push_back(clipped);
|
|
|
|
|
}
|
|
|
|
|
li.uses.erase(
|
|
|
|
|
std::remove_if(li.uses.begin(), li.uses.end(),
|
|
|
|
|
[&](const UsePosition &u) {
|
|
|
|
|
return u.pos < hot_start || u.pos > hot_end;
|
|
|
|
|
}),
|
|
|
|
|
li.uses.end());
|
|
|
|
|
|
|
|
|
|
// 尝试给 hot 分配
|
|
|
|
|
if (!TryAnyFreeReg(li, m))
|
|
|
|
|
{
|
|
|
|
|
li.assigned_reg = -2;
|
|
|
|
|
spilled.push_back(li.vreg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cold 入堆
|
|
|
|
|
if (!TryAnyFreeReg(cold_ref, m))
|
|
|
|
|
{
|
|
|
|
|
heap.push_back(cold_ref.vreg);
|
|
|
|
|
std::push_heap(heap.begin(), heap.end(), cmp);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// 注意:push_back 会使引用失效,通过 vreg 索引安全访问
|
|
|
|
|
bool TrySplit(int vreg_idx, LiveRegMatrix &m,
|
|
|
|
|
std::vector<int> &heap,
|
|
|
|
|
std::vector<LiveInterval> &intervals,
|
|
|
|
|
const std::vector<int> &pos_to_block,
|
|
|
|
|
std::vector<int> &spilled,
|
|
|
|
|
MachineFunction &func,
|
|
|
|
|
const SpillWeightCmp &cmp)
|
|
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
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.vreg = func.CreateVReg(li.vreg_class);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
clipped.end = std::min(seg.end, cold_end);
|
|
|
|
|
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.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;
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cold 入堆
|
|
|
|
|
auto &cold_ref = intervals[cold_vreg];
|
|
|
|
|
if (!TryAnyFreeReg(cold_ref, m))
|
|
|
|
|
{
|
|
|
|
|
heap.push_back(cold_vreg);
|
|
|
|
|
std::push_heap(heap.begin(), heap.end(), cmp);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- 主分配函数:对一类寄存器执行贪婪分配 ----
|
|
|
|
|
// 返回 spilled 数量
|
|
|
|
|
@ -436,7 +442,18 @@ int AllocateRegClass(std::vector<LiveInterval> &intervals,
|
|
|
|
|
{
|
|
|
|
|
if (TryEvict(li, matrix, heap, cmp)) continue;
|
|
|
|
|
}
|
|
|
|
|
if (TrySplit(li, matrix, heap, intervals,
|
|
|
|
|
|
|
|
|
|
// LLVM Defer 机制: 首次分配失败时推迟到下一轮,让更小的范围先分配
|
|
|
|
|
// 参考: llvm/lib/CodeGen/RegAllocGreedy.cpp selectOrSplit() RS_New→RS_Deferred
|
|
|
|
|
if (li.deferred_count == 0)
|
|
|
|
|
{
|
|
|
|
|
li.deferred_count = 1;
|
|
|
|
|
heap.push_back(vreg);
|
|
|
|
|
std::push_heap(heap.begin(), heap.end(), cmp);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TrySplit(vreg, matrix, heap, intervals,
|
|
|
|
|
pos_to_block, spilled, func, cmp)) continue;
|
|
|
|
|
|
|
|
|
|
li.assigned_reg = -2;
|
|
|
|
|
|