|
|
|
|
@ -1,64 +1,954 @@
|
|
|
|
|
#include "mir/MIR.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <stack>
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "utils/Log.h"
|
|
|
|
|
|
|
|
|
|
namespace mir {
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
bool IsAllowedReg(PhysReg reg) {
|
|
|
|
|
switch (reg) {
|
|
|
|
|
case PhysReg::W0:
|
|
|
|
|
case PhysReg::W1:
|
|
|
|
|
case PhysReg::W2:
|
|
|
|
|
case PhysReg::W3:
|
|
|
|
|
case PhysReg::W4:
|
|
|
|
|
case PhysReg::W5:
|
|
|
|
|
case PhysReg::W6:
|
|
|
|
|
case PhysReg::W7:
|
|
|
|
|
case PhysReg::W8:
|
|
|
|
|
case PhysReg::W9:
|
|
|
|
|
case PhysReg::W10:
|
|
|
|
|
case PhysReg::X0:
|
|
|
|
|
case PhysReg::X1:
|
|
|
|
|
case PhysReg::X2:
|
|
|
|
|
case PhysReg::X3:
|
|
|
|
|
case PhysReg::X4:
|
|
|
|
|
case PhysReg::X5:
|
|
|
|
|
case PhysReg::X6:
|
|
|
|
|
case PhysReg::X7:
|
|
|
|
|
case PhysReg::X8:
|
|
|
|
|
case PhysReg::X9:
|
|
|
|
|
case PhysReg::X10:
|
|
|
|
|
case PhysReg::X29:
|
|
|
|
|
case PhysReg::X30:
|
|
|
|
|
case PhysReg::SP:
|
|
|
|
|
case PhysReg::S0:
|
|
|
|
|
case PhysReg::S1:
|
|
|
|
|
case PhysReg::S2:
|
|
|
|
|
case PhysReg::S3:
|
|
|
|
|
case PhysReg::S4:
|
|
|
|
|
case PhysReg::S5:
|
|
|
|
|
case PhysReg::S6:
|
|
|
|
|
case PhysReg::S7:
|
|
|
|
|
case PhysReg::S8:
|
|
|
|
|
case PhysReg::S9:
|
|
|
|
|
case PhysReg::S10:
|
|
|
|
|
return true;
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 物理寄存器定义
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
// 可分配的 GPR (32-bit):w0-w11(共12个)
|
|
|
|
|
static const std::vector<PhysReg> kAllocGPR = {
|
|
|
|
|
PhysReg::W0, PhysReg::W1, PhysReg::W2, PhysReg::W3,
|
|
|
|
|
PhysReg::W4, PhysReg::W5, PhysReg::W6, PhysReg::W7,
|
|
|
|
|
PhysReg::W8, PhysReg::W9, PhysReg::W10, PhysReg::W11,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 可分配的 GPR64 (64-bit):x0-x11(共12个)
|
|
|
|
|
static const std::vector<PhysReg> kAllocGPR64 = {
|
|
|
|
|
PhysReg::X0, PhysReg::X1, PhysReg::X2, PhysReg::X3,
|
|
|
|
|
PhysReg::X4, PhysReg::X5, PhysReg::X6, PhysReg::X7,
|
|
|
|
|
PhysReg::X8, PhysReg::X9, PhysReg::X10, PhysReg::X11,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 可分配的 FPR:s0-s10(共11个)
|
|
|
|
|
static const std::vector<PhysReg> kAllocFPR = {
|
|
|
|
|
PhysReg::S0, PhysReg::S1, PhysReg::S2, PhysReg::S3,
|
|
|
|
|
PhysReg::S4, PhysReg::S5, PhysReg::S6, PhysReg::S7,
|
|
|
|
|
PhysReg::S8, PhysReg::S9, PhysReg::S10,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Callee-saved 寄存器
|
|
|
|
|
static const std::set<PhysReg> kCalleeSavedGPR = {
|
|
|
|
|
PhysReg::W8, PhysReg::W9, PhysReg::W10, PhysReg::W11,
|
|
|
|
|
};
|
|
|
|
|
static const std::set<PhysReg> kCalleeSavedGPR64 = {
|
|
|
|
|
PhysReg::X8, PhysReg::X9, PhysReg::X10, PhysReg::X11,
|
|
|
|
|
};
|
|
|
|
|
static const std::set<PhysReg> kCalleeSavedFPR = {
|
|
|
|
|
PhysReg::S8, PhysReg::S9, PhysReg::S10,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Caller-saved 寄存器(被函数调用破坏)
|
|
|
|
|
static const std::set<PhysReg> kCallerSavedGPR = {
|
|
|
|
|
PhysReg::W0, PhysReg::W1, PhysReg::W2, PhysReg::W3,
|
|
|
|
|
PhysReg::W4, PhysReg::W5, PhysReg::W6, PhysReg::W7,
|
|
|
|
|
};
|
|
|
|
|
static const std::set<PhysReg> kCallerSavedGPR64 = {
|
|
|
|
|
PhysReg::X0, PhysReg::X1, PhysReg::X2, PhysReg::X3,
|
|
|
|
|
PhysReg::X4, PhysReg::X5, PhysReg::X6, PhysReg::X7,
|
|
|
|
|
};
|
|
|
|
|
static const std::set<PhysReg> kCallerSavedFPR = {
|
|
|
|
|
PhysReg::S0, PhysReg::S1, PhysReg::S2, PhysReg::S3,
|
|
|
|
|
PhysReg::S4, PhysReg::S5, PhysReg::S6, PhysReg::S7,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool IsFloatReg(PhysReg r) {
|
|
|
|
|
return r >= PhysReg::S0 && r <= PhysReg::S10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// W/X 寄存器别名:w0-w11 和 x0-x11 是同一物理寄存器的 32/64 位视图
|
|
|
|
|
PhysReg WToX(PhysReg w) {
|
|
|
|
|
int idx = static_cast<int>(w) - static_cast<int>(PhysReg::W0);
|
|
|
|
|
if (idx >= 0 && idx <= 11)
|
|
|
|
|
return static_cast<PhysReg>(static_cast<int>(PhysReg::X0) + idx);
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PhysReg XToW(PhysReg x) {
|
|
|
|
|
int idx = static_cast<int>(x) - static_cast<int>(PhysReg::X0);
|
|
|
|
|
if (idx >= 0 && idx <= 11)
|
|
|
|
|
return static_cast<PhysReg>(static_cast<int>(PhysReg::W0) + idx);
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将物理寄存器及其别名都加入集合
|
|
|
|
|
void InsertWithAlias(std::set<PhysReg>& s, PhysReg r) {
|
|
|
|
|
s.insert(r);
|
|
|
|
|
if (r >= PhysReg::W0 && r <= PhysReg::W11) {
|
|
|
|
|
s.insert(WToX(r));
|
|
|
|
|
} else if (r >= PhysReg::X0 && r <= PhysReg::X11) {
|
|
|
|
|
s.insert(XToW(r));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsGPR64(PhysReg r) {
|
|
|
|
|
return (r >= PhysReg::X0 && r <= PhysReg::X11) ||
|
|
|
|
|
r == PhysReg::X29 || r == PhysReg::X30 || r == PhysReg::SP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确定物理寄存器对应的 VRegClass
|
|
|
|
|
VRegClass ClassForPhysReg(PhysReg r) {
|
|
|
|
|
if (IsFloatReg(r)) return VRegClass::FPR;
|
|
|
|
|
if (IsGPR64(r)) return VRegClass::GPR64;
|
|
|
|
|
return VRegClass::GPR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取虚拟寄存器类别的可分配物理寄存器列表
|
|
|
|
|
const std::vector<PhysReg>& GetAllocRegs(VRegClass rc) {
|
|
|
|
|
switch (rc) {
|
|
|
|
|
case VRegClass::GPR: return kAllocGPR;
|
|
|
|
|
case VRegClass::GPR64: return kAllocGPR64;
|
|
|
|
|
case VRegClass::FPR: return kAllocFPR;
|
|
|
|
|
}
|
|
|
|
|
return kAllocGPR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 判断是否应该提升的寄存器
|
|
|
|
|
// 只提升临时计算寄存器 (w8-w11, x8-x11, s8-s10)
|
|
|
|
|
// 不提升 ABI 寄存器 (w0-w7, x0-x7, s0-s7) 和特殊寄存器 (x29, x30, sp)
|
|
|
|
|
bool ShouldPromote(PhysReg r) {
|
|
|
|
|
if (r == PhysReg::X29 || r == PhysReg::X30 || r == PhysReg::SP) return false;
|
|
|
|
|
// 不提升 ABI caller-saved 寄存器(w0-w7, x0-x7, s0-s7)
|
|
|
|
|
if (r >= PhysReg::W0 && r <= PhysReg::W7) return false;
|
|
|
|
|
if (r >= PhysReg::X0 && r <= PhysReg::X7) return false;
|
|
|
|
|
if (r >= PhysReg::S0 && r <= PhysReg::S7) return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 1. 构建 CFG
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void BuildCFG(MachineFunction& func) {
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
bb_ptr->ClearCFG();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
auto& bb = *bb_ptr;
|
|
|
|
|
for (const auto& inst : bb.GetInstructions()) {
|
|
|
|
|
auto op = inst.GetOpcode();
|
|
|
|
|
if (op == Opcode::B) {
|
|
|
|
|
auto* target = func.FindBlock(inst.GetOperands()[0].GetSymbol());
|
|
|
|
|
if (target) {
|
|
|
|
|
bb.AddSuccessor(target);
|
|
|
|
|
target->AddPredecessor(&bb);
|
|
|
|
|
}
|
|
|
|
|
} else if (op == Opcode::Bcond || op == Opcode::FBcond) {
|
|
|
|
|
auto* target = func.FindBlock(inst.GetOperands()[0].GetSymbol());
|
|
|
|
|
if (target) {
|
|
|
|
|
bb.AddSuccessor(target);
|
|
|
|
|
target->AddPredecessor(&bb);
|
|
|
|
|
}
|
|
|
|
|
} else if (op == Opcode::Cbnz || op == Opcode::Cbz) {
|
|
|
|
|
auto* target = func.FindBlock(inst.GetOperands()[1].GetSymbol());
|
|
|
|
|
if (target) {
|
|
|
|
|
bb.AddSuccessor(target);
|
|
|
|
|
target->AddPredecessor(&bb);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// fall-through:如果最后一条指令不是无条件跳转/ret,则下一个块是后继
|
|
|
|
|
if (!bb.GetInstructions().empty()) {
|
|
|
|
|
auto last_op = bb.GetInstructions().back().GetOpcode();
|
|
|
|
|
if (last_op != Opcode::B && last_op != Opcode::Ret) {
|
|
|
|
|
const auto& blocks = func.GetBlocks();
|
|
|
|
|
for (size_t i = 0; i + 1 < blocks.size(); ++i) {
|
|
|
|
|
if (blocks[i].get() == &bb) {
|
|
|
|
|
auto* next = blocks[i + 1].get();
|
|
|
|
|
bb.AddSuccessor(next);
|
|
|
|
|
next->AddPredecessor(&bb);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 2. VRegInfo 结构
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
struct VRegInfo {
|
|
|
|
|
int id = 0;
|
|
|
|
|
VRegClass rc = VRegClass::GPR;
|
|
|
|
|
int spill_slot = -1;
|
|
|
|
|
bool is_spilled = false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 3. 将 MIR 中的物理寄存器提升为虚拟寄存器
|
|
|
|
|
// ============================================================================
|
|
|
|
|
//
|
|
|
|
|
// 策略:只提升临时计算寄存器 (w8-w11, x8-x11, s8-s10)。
|
|
|
|
|
// ABI 寄存器 (w0-w7, x0-x7, s0-s7) 保持物理寄存器不变,因为它们用于:
|
|
|
|
|
// - 函数参数传递、返回值、调用约定
|
|
|
|
|
// 跨块的值通过栈槽传递,所以无需跨块跟踪 vreg。
|
|
|
|
|
// 图着色分配器仍然可以将 vreg 分配到 w0-w7 等寄存器。
|
|
|
|
|
|
|
|
|
|
void PromoteToVRegs(MachineFunction& func,
|
|
|
|
|
std::vector<VRegInfo>& vreg_infos) {
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
auto& insts = bb_ptr->GetInstructions();
|
|
|
|
|
// 块内物理寄存器 → vreg 的映射
|
|
|
|
|
std::unordered_map<int, int> phys_to_vreg;
|
|
|
|
|
|
|
|
|
|
auto EnsureSize = [&](int vreg_id) {
|
|
|
|
|
if (static_cast<int>(vreg_infos.size()) <= vreg_id)
|
|
|
|
|
vreg_infos.resize(vreg_id + 1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto GetOrCreateVReg = [&](PhysReg reg) -> int {
|
|
|
|
|
int key = static_cast<int>(reg);
|
|
|
|
|
auto it = phys_to_vreg.find(key);
|
|
|
|
|
if (it != phys_to_vreg.end()) return it->second;
|
|
|
|
|
VRegClass rc = ClassForPhysReg(reg);
|
|
|
|
|
int vreg_id = func.CreateVReg(rc);
|
|
|
|
|
EnsureSize(vreg_id);
|
|
|
|
|
vreg_infos[vreg_id] = {vreg_id, rc, -1, false};
|
|
|
|
|
phys_to_vreg[key] = vreg_id;
|
|
|
|
|
return vreg_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto CreateNewVReg = [&](PhysReg reg) -> int {
|
|
|
|
|
VRegClass rc = ClassForPhysReg(reg);
|
|
|
|
|
int vreg_id = func.CreateVReg(rc);
|
|
|
|
|
EnsureSize(vreg_id);
|
|
|
|
|
vreg_infos[vreg_id] = {vreg_id, rc, -1, false};
|
|
|
|
|
phys_to_vreg[static_cast<int>(reg)] = vreg_id;
|
|
|
|
|
return vreg_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 辅助:提升 use 位置的操作数
|
|
|
|
|
auto PromoteUse = [&](Operand& op) {
|
|
|
|
|
if (op.IsReg() && ShouldPromote(op.GetReg())) {
|
|
|
|
|
PhysReg orig = op.GetReg();
|
|
|
|
|
int vreg = GetOrCreateVReg(orig);
|
|
|
|
|
op = Operand::VReg(vreg, ClassForPhysReg(orig));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 辅助:提升 def 位置的操作数(为 def 创建新 vreg)
|
|
|
|
|
auto PromoteDef = [&](Operand& op) {
|
|
|
|
|
if (op.IsReg() && ShouldPromote(op.GetReg())) {
|
|
|
|
|
PhysReg orig = op.GetReg();
|
|
|
|
|
int vreg = CreateNewVReg(orig);
|
|
|
|
|
op = Operand::VReg(vreg, ClassForPhysReg(orig));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < insts.size(); ++i) {
|
|
|
|
|
auto& inst = insts[i];
|
|
|
|
|
auto opcode = inst.GetOpcode();
|
|
|
|
|
|
|
|
|
|
// 跳过控制流/伪指令
|
|
|
|
|
if (opcode == Opcode::Prologue || opcode == Opcode::Epilogue ||
|
|
|
|
|
opcode == Opcode::B || opcode == Opcode::Bcond ||
|
|
|
|
|
opcode == Opcode::FBcond || opcode == Opcode::Ret)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Bl:清除所有 caller-saved 映射(它们被调用破坏了)
|
|
|
|
|
if (opcode == Opcode::Bl) {
|
|
|
|
|
// callee-saved (w8-w11等) 的映射也要清除,因为调用可能破坏它们
|
|
|
|
|
// (虽然按约定不应该,但这里保守处理)
|
|
|
|
|
phys_to_vreg.clear();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto& ops = inst.GetOperands();
|
|
|
|
|
|
|
|
|
|
// Cbnz/Cbz: ops[0] 是 use
|
|
|
|
|
if (opcode == Opcode::Cbnz || opcode == Opcode::Cbz) {
|
|
|
|
|
if (!ops.empty()) PromoteUse(ops[0]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CmpOnlyRR / FCmpOnlyRR: ops[0], ops[1] 都是 use(不写寄存器,只设条件码)
|
|
|
|
|
if (opcode == Opcode::CmpOnlyRR || opcode == Opcode::FCmpOnlyRR) {
|
|
|
|
|
for (size_t j = 0; j < std::min(ops.size(), size_t(2)); ++j)
|
|
|
|
|
PromoteUse(ops[j]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- 先处理 use 操作数 ----
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case Opcode::MovReg:
|
|
|
|
|
case Opcode::FMovReg:
|
|
|
|
|
if (ops.size() > 1) PromoteUse(ops[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Opcode::StoreStack:
|
|
|
|
|
case Opcode::StoreStackOffset:
|
|
|
|
|
case Opcode::StoreGlobal:
|
|
|
|
|
if (!ops.empty()) PromoteUse(ops[0]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Opcode::StoreIndirect:
|
|
|
|
|
if (!ops.empty()) PromoteUse(ops[0]);
|
|
|
|
|
if (ops.size() > 1) PromoteUse(ops[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Opcode::LoadIndirect:
|
|
|
|
|
if (ops.size() > 1) PromoteUse(ops[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Opcode::AddRI: case Opcode::SubRI:
|
|
|
|
|
case Opcode::LsrRI: case Opcode::LslRI:
|
|
|
|
|
case Opcode::FSqrtRR: case Opcode::SIToFP: case Opcode::FPToSI:
|
|
|
|
|
if (ops.size() > 1) PromoteUse(ops[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Opcode::AddRR: case Opcode::AddRR_UXTW: case Opcode::SubRR:
|
|
|
|
|
case Opcode::MulRR: case Opcode::DivRR:
|
|
|
|
|
case Opcode::ModRR: case Opcode::LslRR:
|
|
|
|
|
case Opcode::FAddRR: case Opcode::FSubRR:
|
|
|
|
|
case Opcode::FMulRR: case Opcode::FDivRR:
|
|
|
|
|
if (ops.size() > 1) PromoteUse(ops[1]);
|
|
|
|
|
if (ops.size() > 2) PromoteUse(ops[2]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Opcode::CmpRR: case Opcode::FCmpRR:
|
|
|
|
|
if (ops.size() > 1) PromoteUse(ops[1]);
|
|
|
|
|
if (ops.size() > 2) PromoteUse(ops[2]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---- 然后处理 def 操作数 ----
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case Opcode::MovImm: case Opcode::FMovImm:
|
|
|
|
|
case Opcode::MovReg: case Opcode::FMovReg:
|
|
|
|
|
case Opcode::LoadStack: case Opcode::LoadStackOffset:
|
|
|
|
|
case Opcode::LoadStackAddr: case Opcode::LoadIndirect:
|
|
|
|
|
case Opcode::LoadGlobal: case Opcode::LoadGlobalAddr:
|
|
|
|
|
case Opcode::AddRI: case Opcode::SubRI:
|
|
|
|
|
case Opcode::AddRR: case Opcode::AddRR_UXTW: case Opcode::SubRR:
|
|
|
|
|
case Opcode::MulRR: case Opcode::DivRR:
|
|
|
|
|
case Opcode::ModRR: case Opcode::LsrRI:
|
|
|
|
|
case Opcode::LslRI: case Opcode::LslRR:
|
|
|
|
|
case Opcode::FAddRR: case Opcode::FSubRR:
|
|
|
|
|
case Opcode::FMulRR: case Opcode::FDivRR:
|
|
|
|
|
case Opcode::FSqrtRR: case Opcode::SIToFP: case Opcode::FPToSI:
|
|
|
|
|
case Opcode::CmpRR: case Opcode::FCmpRR:
|
|
|
|
|
if (!ops.empty()) PromoteDef(ops[0]);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 4. VReg 活跃性分析
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
struct VRegLiveInfo {
|
|
|
|
|
std::set<int> live_in;
|
|
|
|
|
std::set<int> live_out;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using VRegLiveMap = std::unordered_map<MachineBasicBlock*, VRegLiveInfo>;
|
|
|
|
|
|
|
|
|
|
void GetVRegDefsUses(const MachineInstr& inst,
|
|
|
|
|
std::set<int>& defs, std::set<int>& uses) {
|
|
|
|
|
const auto& ops = inst.GetOperands();
|
|
|
|
|
auto opcode = inst.GetOpcode();
|
|
|
|
|
|
|
|
|
|
// Use 操作数
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case Opcode::MovReg: case Opcode::FMovReg:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::StoreStack: case Opcode::StoreStackOffset:
|
|
|
|
|
case Opcode::StoreGlobal:
|
|
|
|
|
if (!ops.empty() && ops[0].IsVReg()) uses.insert(ops[0].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::StoreIndirect:
|
|
|
|
|
if (!ops.empty() && ops[0].IsVReg()) uses.insert(ops[0].GetVRegId());
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::LoadIndirect:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::AddRI: case Opcode::SubRI:
|
|
|
|
|
case Opcode::LsrRI: case Opcode::LslRI:
|
|
|
|
|
case Opcode::FSqrtRR: case Opcode::SIToFP: case Opcode::FPToSI:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::AddRR: case Opcode::AddRR_UXTW: case Opcode::SubRR:
|
|
|
|
|
case Opcode::MulRR: case Opcode::DivRR:
|
|
|
|
|
case Opcode::ModRR: case Opcode::LslRR:
|
|
|
|
|
case Opcode::FAddRR: case Opcode::FSubRR:
|
|
|
|
|
case Opcode::FMulRR: case Opcode::FDivRR:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
if (ops.size() > 2 && ops[2].IsVReg()) uses.insert(ops[2].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::CmpRR: case Opcode::FCmpRR:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
if (ops.size() > 2 && ops[2].IsVReg()) uses.insert(ops[2].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::CmpOnlyRR: case Opcode::FCmpOnlyRR:
|
|
|
|
|
if (!ops.empty() && ops[0].IsVReg()) uses.insert(ops[0].GetVRegId());
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsVReg()) uses.insert(ops[1].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::Cbnz: case Opcode::Cbz:
|
|
|
|
|
if (!ops.empty() && ops[0].IsVReg()) uses.insert(ops[0].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Def 操作数
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case Opcode::MovImm: case Opcode::FMovImm:
|
|
|
|
|
case Opcode::MovReg: case Opcode::FMovReg:
|
|
|
|
|
case Opcode::LoadStack: case Opcode::LoadStackOffset:
|
|
|
|
|
case Opcode::LoadStackAddr: case Opcode::LoadIndirect:
|
|
|
|
|
case Opcode::LoadGlobal: case Opcode::LoadGlobalAddr:
|
|
|
|
|
case Opcode::AddRI: case Opcode::SubRI:
|
|
|
|
|
case Opcode::AddRR: case Opcode::AddRR_UXTW: case Opcode::SubRR:
|
|
|
|
|
case Opcode::MulRR: case Opcode::DivRR:
|
|
|
|
|
case Opcode::ModRR: case Opcode::LsrRI:
|
|
|
|
|
case Opcode::LslRI: case Opcode::LslRR:
|
|
|
|
|
case Opcode::FAddRR: case Opcode::FSubRR:
|
|
|
|
|
case Opcode::FMulRR: case Opcode::FDivRR:
|
|
|
|
|
case Opcode::FSqrtRR: case Opcode::SIToFP: case Opcode::FPToSI:
|
|
|
|
|
case Opcode::CmpRR: case Opcode::FCmpRR:
|
|
|
|
|
if (!ops.empty() && ops[0].IsVReg()) defs.insert(ops[0].GetVRegId());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VRegLiveMap ComputeVRegLiveness(MachineFunction& func) {
|
|
|
|
|
VRegLiveMap live_map;
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
live_map[bb_ptr.get()] = VRegLiveInfo{};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool changed = true;
|
|
|
|
|
while (changed) {
|
|
|
|
|
changed = false;
|
|
|
|
|
const auto& blocks = func.GetBlocks();
|
|
|
|
|
for (int bi = static_cast<int>(blocks.size()) - 1; bi >= 0; --bi) {
|
|
|
|
|
auto* bb = blocks[bi].get();
|
|
|
|
|
auto& info = live_map[bb];
|
|
|
|
|
|
|
|
|
|
// live_out = union of successors' live_in
|
|
|
|
|
std::set<int> new_live_out;
|
|
|
|
|
for (auto* succ : bb->GetSuccessors()) {
|
|
|
|
|
const auto& succ_in = live_map[succ].live_in;
|
|
|
|
|
new_live_out.insert(succ_in.begin(), succ_in.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 从块末尾向前扫描计算 live_in
|
|
|
|
|
std::set<int> live = new_live_out;
|
|
|
|
|
const auto& insts = bb->GetInstructions();
|
|
|
|
|
for (int i = static_cast<int>(insts.size()) - 1; i >= 0; --i) {
|
|
|
|
|
std::set<int> defs, uses_set;
|
|
|
|
|
GetVRegDefsUses(insts[i], defs, uses_set);
|
|
|
|
|
for (auto v : defs) live.erase(v);
|
|
|
|
|
for (auto v : uses_set) live.insert(v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (live != info.live_in || new_live_out != info.live_out) {
|
|
|
|
|
info.live_in = std::move(live);
|
|
|
|
|
info.live_out = std::move(new_live_out);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return live_map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 5. 干涉图构建
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
// 获取指令中定义和使用的物理寄存器(非 vreg 的)
|
|
|
|
|
void GetPhysRegDefsUses(const MachineInstr& inst,
|
|
|
|
|
std::set<PhysReg>& phys_defs,
|
|
|
|
|
std::set<PhysReg>& phys_uses) {
|
|
|
|
|
const auto& ops = inst.GetOperands();
|
|
|
|
|
auto opcode = inst.GetOpcode();
|
|
|
|
|
|
|
|
|
|
// 对于 Bl 指令,所有 caller-saved 寄存器被隐式定义(破坏)
|
|
|
|
|
if (opcode == Opcode::Bl) {
|
|
|
|
|
for (auto r : kCallerSavedGPR) phys_defs.insert(r);
|
|
|
|
|
for (auto r : kCallerSavedGPR64) phys_defs.insert(r);
|
|
|
|
|
for (auto r : kCallerSavedFPR) phys_defs.insert(r);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use 位置的物理寄存器
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case Opcode::MovReg: case Opcode::FMovReg:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsReg() && !ShouldPromote(ops[1].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[1].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::StoreStack: case Opcode::StoreStackOffset:
|
|
|
|
|
case Opcode::StoreGlobal:
|
|
|
|
|
if (!ops.empty() && ops[0].IsReg() && !ShouldPromote(ops[0].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[0].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::StoreIndirect:
|
|
|
|
|
if (!ops.empty() && ops[0].IsReg() && !ShouldPromote(ops[0].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[0].GetReg());
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsReg() && !ShouldPromote(ops[1].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[1].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::AddRI: case Opcode::SubRI:
|
|
|
|
|
case Opcode::LsrRI: case Opcode::LslRI:
|
|
|
|
|
case Opcode::FSqrtRR: case Opcode::SIToFP: case Opcode::FPToSI:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsReg() && !ShouldPromote(ops[1].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[1].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::AddRR: case Opcode::AddRR_UXTW: case Opcode::SubRR:
|
|
|
|
|
case Opcode::MulRR: case Opcode::DivRR:
|
|
|
|
|
case Opcode::ModRR: case Opcode::LslRR:
|
|
|
|
|
case Opcode::FAddRR: case Opcode::FSubRR:
|
|
|
|
|
case Opcode::FMulRR: case Opcode::FDivRR:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsReg() && !ShouldPromote(ops[1].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[1].GetReg());
|
|
|
|
|
if (ops.size() > 2 && ops[2].IsReg() && !ShouldPromote(ops[2].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[2].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::CmpRR: case Opcode::FCmpRR:
|
|
|
|
|
case Opcode::CmpOnlyRR: case Opcode::FCmpOnlyRR:
|
|
|
|
|
if (!ops.empty() && ops[0].IsReg() && !ShouldPromote(ops[0].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[0].GetReg());
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsReg() && !ShouldPromote(ops[1].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[1].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::Cbnz: case Opcode::Cbz:
|
|
|
|
|
if (!ops.empty() && ops[0].IsReg() && !ShouldPromote(ops[0].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[0].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
case Opcode::LoadIndirect:
|
|
|
|
|
if (ops.size() > 1 && ops[1].IsReg() && !ShouldPromote(ops[1].GetReg()))
|
|
|
|
|
phys_uses.insert(ops[1].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Def 位置的物理寄存器
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case Opcode::MovImm: case Opcode::FMovImm:
|
|
|
|
|
case Opcode::MovReg: case Opcode::FMovReg:
|
|
|
|
|
case Opcode::LoadStack: case Opcode::LoadStackOffset:
|
|
|
|
|
case Opcode::LoadStackAddr: case Opcode::LoadIndirect:
|
|
|
|
|
case Opcode::LoadGlobal: case Opcode::LoadGlobalAddr:
|
|
|
|
|
case Opcode::AddRI: case Opcode::SubRI:
|
|
|
|
|
case Opcode::AddRR: case Opcode::AddRR_UXTW: case Opcode::SubRR:
|
|
|
|
|
case Opcode::MulRR: case Opcode::DivRR:
|
|
|
|
|
case Opcode::ModRR: case Opcode::LsrRI:
|
|
|
|
|
case Opcode::LslRI: case Opcode::LslRR:
|
|
|
|
|
case Opcode::FAddRR: case Opcode::FSubRR:
|
|
|
|
|
case Opcode::FMulRR: case Opcode::FDivRR:
|
|
|
|
|
case Opcode::FSqrtRR: case Opcode::SIToFP: case Opcode::FPToSI:
|
|
|
|
|
case Opcode::CmpRR: case Opcode::FCmpRR:
|
|
|
|
|
if (!ops.empty() && ops[0].IsReg() && !ShouldPromote(ops[0].GetReg()))
|
|
|
|
|
phys_defs.insert(ops[0].GetReg());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct InterferenceGraph {
|
|
|
|
|
int num_vregs = 0;
|
|
|
|
|
std::vector<std::set<int>> adj;
|
|
|
|
|
std::vector<int> degree;
|
|
|
|
|
// 每个 vreg 不能使用的物理寄存器集合(与物理寄存器的干涉)
|
|
|
|
|
std::vector<std::set<PhysReg>> phys_interference;
|
|
|
|
|
|
|
|
|
|
void Init(int n) {
|
|
|
|
|
num_vregs = n;
|
|
|
|
|
adj.resize(n);
|
|
|
|
|
degree.resize(n, 0);
|
|
|
|
|
phys_interference.resize(n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddEdge(int u, int v) {
|
|
|
|
|
if (u == v) return;
|
|
|
|
|
if (u < 0 || u >= num_vregs || v < 0 || v >= num_vregs) return;
|
|
|
|
|
if (adj[u].count(v)) return;
|
|
|
|
|
adj[u].insert(v);
|
|
|
|
|
adj[v].insert(u);
|
|
|
|
|
degree[u]++;
|
|
|
|
|
degree[v]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddPhysInterference(int vreg, PhysReg phys) {
|
|
|
|
|
if (vreg < 0 || vreg >= num_vregs) return;
|
|
|
|
|
// 同时插入物理寄存器及其 W/X 别名
|
|
|
|
|
InsertWithAlias(phys_interference[vreg], phys);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
InterferenceGraph BuildInterferenceGraph(
|
|
|
|
|
MachineFunction& func,
|
|
|
|
|
const VRegLiveMap& live_map,
|
|
|
|
|
int num_vregs) {
|
|
|
|
|
InterferenceGraph ig;
|
|
|
|
|
ig.Init(num_vregs);
|
|
|
|
|
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
auto* bb = bb_ptr.get();
|
|
|
|
|
const auto& insts = bb->GetInstructions();
|
|
|
|
|
auto it = live_map.find(bb);
|
|
|
|
|
if (it == live_map.end()) continue;
|
|
|
|
|
|
|
|
|
|
std::set<int> live = it->second.live_out;
|
|
|
|
|
// 追踪当前活跃的物理寄存器
|
|
|
|
|
std::set<PhysReg> phys_live;
|
|
|
|
|
|
|
|
|
|
// 从块末尾向前扫描
|
|
|
|
|
for (int i = static_cast<int>(insts.size()) - 1; i >= 0; --i) {
|
|
|
|
|
std::set<int> defs, uses_set;
|
|
|
|
|
GetVRegDefsUses(insts[i], defs, uses_set);
|
|
|
|
|
|
|
|
|
|
std::set<PhysReg> phys_defs, phys_uses;
|
|
|
|
|
GetPhysRegDefsUses(insts[i], phys_defs, phys_uses);
|
|
|
|
|
|
|
|
|
|
// 对每个 vreg def,与所有当前 live 的 vreg 添加干涉边
|
|
|
|
|
for (int d : defs) {
|
|
|
|
|
for (int l : live) {
|
|
|
|
|
ig.AddEdge(d, l);
|
|
|
|
|
}
|
|
|
|
|
// vreg def 与当前活跃的物理寄存器干涉
|
|
|
|
|
for (auto pr : phys_live) {
|
|
|
|
|
ig.AddPhysInterference(d, pr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 物理寄存器 def 与当前活跃的 vreg 干涉
|
|
|
|
|
for (auto pr : phys_defs) {
|
|
|
|
|
for (int l : live) {
|
|
|
|
|
ig.AddPhysInterference(l, pr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新 vreg 活跃集合
|
|
|
|
|
for (int d : defs) live.erase(d);
|
|
|
|
|
for (int u : uses_set) live.insert(u);
|
|
|
|
|
|
|
|
|
|
// 更新物理寄存器活跃集合
|
|
|
|
|
for (auto pr : phys_defs) phys_live.erase(pr);
|
|
|
|
|
for (auto pr : phys_uses) phys_live.insert(pr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 6. 图着色(Simplify → Select → Spill)
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
struct ColoringResult {
|
|
|
|
|
std::unordered_map<int, PhysReg> assignment;
|
|
|
|
|
std::vector<int> spilled;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool IsCalleeSaved(PhysReg r, VRegClass rc) {
|
|
|
|
|
switch (rc) {
|
|
|
|
|
case VRegClass::GPR: return kCalleeSavedGPR.count(r) > 0;
|
|
|
|
|
case VRegClass::GPR64: return kCalleeSavedGPR64.count(r) > 0;
|
|
|
|
|
case VRegClass::FPR: return kCalleeSavedFPR.count(r) > 0;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ColoringResult ColorGraph(
|
|
|
|
|
InterferenceGraph& ig,
|
|
|
|
|
const std::vector<VRegInfo>& vreg_infos,
|
|
|
|
|
MachineFunction& func) {
|
|
|
|
|
int n = ig.num_vregs;
|
|
|
|
|
ColoringResult result;
|
|
|
|
|
if (n == 0) return result;
|
|
|
|
|
|
|
|
|
|
// Simplify: 迭代移除度 < K 的节点入栈
|
|
|
|
|
std::vector<bool> removed(n, false);
|
|
|
|
|
std::stack<int> select_stack;
|
|
|
|
|
std::vector<int> cur_degree(ig.degree);
|
|
|
|
|
|
|
|
|
|
auto K = [&](int v) -> int {
|
|
|
|
|
return static_cast<int>(GetAllocRegs(vreg_infos[v].rc).size());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int remaining = n;
|
|
|
|
|
while (remaining > 0) {
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (int v = 0; v < n; ++v) {
|
|
|
|
|
if (removed[v]) continue;
|
|
|
|
|
if (cur_degree[v] < K(v)) {
|
|
|
|
|
select_stack.push(v);
|
|
|
|
|
removed[v] = true;
|
|
|
|
|
remaining--;
|
|
|
|
|
for (int nb : ig.adj[v]) {
|
|
|
|
|
if (!removed[nb]) cur_degree[nb]--;
|
|
|
|
|
}
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
// Potential spill:选度数最大的节点
|
|
|
|
|
int best = -1;
|
|
|
|
|
int best_degree = -1;
|
|
|
|
|
for (int v = 0; v < n; ++v) {
|
|
|
|
|
if (removed[v]) continue;
|
|
|
|
|
if (cur_degree[v] > best_degree) {
|
|
|
|
|
best_degree = cur_degree[v];
|
|
|
|
|
best = v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (best >= 0) {
|
|
|
|
|
select_stack.push(best);
|
|
|
|
|
removed[best] = true;
|
|
|
|
|
remaining--;
|
|
|
|
|
for (int nb : ig.adj[best]) {
|
|
|
|
|
if (!removed[nb]) cur_degree[nb]--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Select: 从栈中弹出,尝试着色
|
|
|
|
|
std::vector<int> color(n, -1);
|
|
|
|
|
|
|
|
|
|
while (!select_stack.empty()) {
|
|
|
|
|
int v = select_stack.top();
|
|
|
|
|
select_stack.pop();
|
|
|
|
|
|
|
|
|
|
const auto& alloc_regs = GetAllocRegs(vreg_infos[v].rc);
|
|
|
|
|
|
|
|
|
|
// 收集邻居已使用的颜色 + 物理寄存器干涉
|
|
|
|
|
std::set<PhysReg> used_colors;
|
|
|
|
|
for (int nb : ig.adj[v]) {
|
|
|
|
|
if (color[nb] >= 0) {
|
|
|
|
|
PhysReg nb_color = static_cast<PhysReg>(color[nb]);
|
|
|
|
|
// 插入颜色及其 W/X 别名,防止跨类别冲突
|
|
|
|
|
InsertWithAlias(used_colors, nb_color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 加入与此 vreg 干涉的物理寄存器(已含别名)
|
|
|
|
|
for (auto pr : ig.phys_interference[v]) {
|
|
|
|
|
used_colors.insert(pr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 优先使用 callee-saved(减少保存开销;对仅在块内使用的 vreg 更优)
|
|
|
|
|
PhysReg chosen = PhysReg::W0;
|
|
|
|
|
bool colored = false;
|
|
|
|
|
|
|
|
|
|
for (auto r : alloc_regs) {
|
|
|
|
|
if (used_colors.count(r)) continue;
|
|
|
|
|
if (IsCalleeSaved(r, vreg_infos[v].rc)) {
|
|
|
|
|
chosen = r;
|
|
|
|
|
colored = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!colored) {
|
|
|
|
|
for (auto r : alloc_regs) {
|
|
|
|
|
if (!used_colors.count(r)) {
|
|
|
|
|
chosen = r;
|
|
|
|
|
colored = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (colored) {
|
|
|
|
|
color[v] = static_cast<int>(chosen);
|
|
|
|
|
result.assignment[v] = chosen;
|
|
|
|
|
if (IsCalleeSaved(chosen, vreg_infos[v].rc)) {
|
|
|
|
|
func.AddUsedCalleeSaved(chosen);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.spilled.push_back(v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 7. Spill 处理
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void RewriteSpills(MachineFunction& func,
|
|
|
|
|
const std::vector<int>& spilled,
|
|
|
|
|
std::vector<VRegInfo>& vreg_infos) {
|
|
|
|
|
for (int v : spilled) {
|
|
|
|
|
int slot_size = (vreg_infos[v].rc == VRegClass::GPR64) ? 8 : 4;
|
|
|
|
|
int slot = func.CreateFrameIndex(slot_size);
|
|
|
|
|
vreg_infos[v].spill_slot = slot;
|
|
|
|
|
vreg_infos[v].is_spilled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::set<int> spilled_set(spilled.begin(), spilled.end());
|
|
|
|
|
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
auto& insts = bb_ptr->GetInstructions();
|
|
|
|
|
std::vector<MachineInstr> new_insts;
|
|
|
|
|
new_insts.reserve(insts.size() * 2);
|
|
|
|
|
|
|
|
|
|
for (auto& inst : insts) {
|
|
|
|
|
auto& ops = inst.GetOperands();
|
|
|
|
|
|
|
|
|
|
std::set<int> inst_defs, inst_uses;
|
|
|
|
|
GetVRegDefsUses(inst, inst_defs, inst_uses);
|
|
|
|
|
|
|
|
|
|
// 收集此指令中 spilled vreg 的 use 和 def 位置
|
|
|
|
|
std::vector<std::pair<size_t, int>> use_positions;
|
|
|
|
|
std::vector<std::pair<size_t, int>> def_positions;
|
|
|
|
|
|
|
|
|
|
for (size_t j = 0; j < ops.size(); ++j) {
|
|
|
|
|
if (!ops[j].IsVReg()) continue;
|
|
|
|
|
int vid = ops[j].GetVRegId();
|
|
|
|
|
if (!spilled_set.count(vid)) continue;
|
|
|
|
|
if (inst_uses.count(vid)) use_positions.emplace_back(j, vid);
|
|
|
|
|
if (inst_defs.count(vid)) def_positions.emplace_back(j, vid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto EnsureSize = [&](int id) {
|
|
|
|
|
if (static_cast<int>(vreg_infos.size()) <= id)
|
|
|
|
|
vreg_infos.resize(id + 1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 为 spilled use 插入 LoadStack
|
|
|
|
|
for (auto& [op_idx, vid] : use_positions) {
|
|
|
|
|
VRegClass rc = vreg_infos[vid].rc;
|
|
|
|
|
int new_vreg = func.CreateVReg(rc);
|
|
|
|
|
EnsureSize(new_vreg);
|
|
|
|
|
vreg_infos[new_vreg] = {new_vreg, rc, -1, false};
|
|
|
|
|
new_insts.emplace_back(Opcode::LoadStack,
|
|
|
|
|
std::vector<Operand>{
|
|
|
|
|
Operand::VReg(new_vreg, rc),
|
|
|
|
|
Operand::FrameIndex(vreg_infos[vid].spill_slot)});
|
|
|
|
|
ops[op_idx] = Operand::VReg(new_vreg, rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_insts.push_back(std::move(inst));
|
|
|
|
|
|
|
|
|
|
// 为 spilled def 插入 StoreStack
|
|
|
|
|
for (auto& [op_idx, vid] : def_positions) {
|
|
|
|
|
VRegClass rc = vreg_infos[vid].rc;
|
|
|
|
|
int new_vreg = func.CreateVReg(rc);
|
|
|
|
|
EnsureSize(new_vreg);
|
|
|
|
|
vreg_infos[new_vreg] = {new_vreg, rc, -1, false};
|
|
|
|
|
// 替换 emitted 指令中的 def 操作数
|
|
|
|
|
new_insts.back().GetOperands()[op_idx] = Operand::VReg(new_vreg, rc);
|
|
|
|
|
new_insts.emplace_back(Opcode::StoreStack,
|
|
|
|
|
std::vector<Operand>{
|
|
|
|
|
Operand::VReg(new_vreg, rc),
|
|
|
|
|
Operand::FrameIndex(vreg_infos[vid].spill_slot)});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
insts = std::move(new_insts);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 8. 应用着色结果
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void ApplyColoring(MachineFunction& func,
|
|
|
|
|
const std::unordered_map<int, PhysReg>& assignment) {
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
for (auto& inst : bb_ptr->GetInstructions()) {
|
|
|
|
|
for (auto& op : inst.GetOperands()) {
|
|
|
|
|
if (op.IsVReg()) {
|
|
|
|
|
auto it = assignment.find(op.GetVRegId());
|
|
|
|
|
if (it != assignment.end()) {
|
|
|
|
|
op.AssignPhysReg(it->second);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void RunRegAlloc(MachineFunction& function) {
|
|
|
|
|
for (const auto& bb_ptr : function.GetBlocks()) {
|
|
|
|
|
// ============================================================================
|
|
|
|
|
// 9. 主入口
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
void RunRegAlloc(MachineFunction& func) {
|
|
|
|
|
// 步骤 1: 构建 CFG
|
|
|
|
|
BuildCFG(func);
|
|
|
|
|
|
|
|
|
|
// 步骤 2: 将物理寄存器提升为虚拟寄存器
|
|
|
|
|
std::vector<VRegInfo> vreg_infos;
|
|
|
|
|
PromoteToVRegs(func, vreg_infos);
|
|
|
|
|
|
|
|
|
|
int num_vregs = func.GetNumVRegs();
|
|
|
|
|
if (num_vregs == 0) return;
|
|
|
|
|
|
|
|
|
|
vreg_infos.resize(num_vregs);
|
|
|
|
|
|
|
|
|
|
// 图着色 + spill 迭代
|
|
|
|
|
const int kMaxIterations = 10;
|
|
|
|
|
for (int iter = 0; iter < kMaxIterations; ++iter) {
|
|
|
|
|
// 重建 CFG(spill 后指令变了)
|
|
|
|
|
if (iter > 0) BuildCFG(func);
|
|
|
|
|
|
|
|
|
|
VRegLiveMap live_map = ComputeVRegLiveness(func);
|
|
|
|
|
|
|
|
|
|
num_vregs = func.GetNumVRegs();
|
|
|
|
|
vreg_infos.resize(num_vregs);
|
|
|
|
|
InterferenceGraph ig = BuildInterferenceGraph(func, live_map, num_vregs);
|
|
|
|
|
|
|
|
|
|
ColoringResult result = ColorGraph(ig, vreg_infos, func);
|
|
|
|
|
|
|
|
|
|
if (result.spilled.empty()) {
|
|
|
|
|
ApplyColoring(func, result.assignment);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RewriteSpills(func, result.spilled, vreg_infos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 最后一次尝试
|
|
|
|
|
BuildCFG(func);
|
|
|
|
|
VRegLiveMap live_map = ComputeVRegLiveness(func);
|
|
|
|
|
num_vregs = func.GetNumVRegs();
|
|
|
|
|
vreg_infos.resize(num_vregs);
|
|
|
|
|
InterferenceGraph ig = BuildInterferenceGraph(func, live_map, num_vregs);
|
|
|
|
|
ColoringResult result = ColorGraph(ig, vreg_infos, func);
|
|
|
|
|
ApplyColoring(func, result.assignment);
|
|
|
|
|
|
|
|
|
|
// 最终检查:不应有残留 VReg
|
|
|
|
|
for (auto& bb_ptr : func.GetBlocks()) {
|
|
|
|
|
for (const auto& inst : bb_ptr->GetInstructions()) {
|
|
|
|
|
for (const auto& operand : inst.GetOperands()) {
|
|
|
|
|
if (operand.GetKind() == Operand::Kind::Reg &&
|
|
|
|
|
!IsAllowedReg(operand.GetReg())) {
|
|
|
|
|
throw std::runtime_error(FormatError("mir", "寄存器分配失败"));
|
|
|
|
|
for (const auto& op : inst.GetOperands()) {
|
|
|
|
|
if (op.IsVReg()) {
|
|
|
|
|
throw std::runtime_error(
|
|
|
|
|
FormatError("mir", "寄存器分配失败:存在未着色的虚拟寄存器 v" +
|
|
|
|
|
std::to_string(op.GetVRegId())));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|