[backend]为图着色引入保底修复

This commit is contained in:
Lixuanwang
2025-08-04 18:13:09 +08:00
parent 4db3cc3fb5
commit 72b06c67ca
4 changed files with 543 additions and 31 deletions

View File

@@ -5,6 +5,7 @@ add_library(riscv64_backend_lib STATIC
RISCv64ISel.cpp
RISCv64LLIR.cpp
RISCv64RegAlloc.cpp
RISCv64LinearScan.cpp
Handler/CalleeSavedHandler.cpp
Handler/LegalizeImmediates.cpp
Handler/PrologueEpilogueInsertion.cpp

View File

@@ -0,0 +1,459 @@
#include "RISCv64LinearScan.h"
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include <iostream>
#include <set>
extern int DEBUG;
namespace sysy {
RISCv64LinearScan::RISCv64LinearScan(MachineFunction* mfunc)
: MFunc(mfunc),
ISel(mfunc->getISel()),
vreg_type_map(ISel->getVRegTypeMap()) {
// 初始化可用的物理寄存器池,与图着色版本保持一致
// 整数寄存器
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /*T5保留作为大立即数加载寄存器*/ PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 浮点寄存器
allocable_fp_regs = {
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22,
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
};
// 新增识别所有通过寄存器传递的参数并建立vreg到物理寄存器(preg)的映射
// 这等同于图着色算法中的“预着色”步骤。
if (MFunc->getFunc()) {
int int_arg_idx = 0;
int fp_arg_idx = 0;
for (Argument* arg : MFunc->getFunc()->getArguments()) {
unsigned arg_vreg = ISel->getVReg(arg);
if (arg->getType()->isFloat()) {
if (fp_arg_idx < 8) { // fa0-fa7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_arg_idx);
abi_vreg_map[arg_vreg] = preg;
fp_arg_idx++;
}
} else { // 整数或指针
if (int_arg_idx < 8) { // a0-a7
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
abi_vreg_map[arg_vreg] = preg;
int_arg_idx++;
}
}
}
}
}
void RISCv64LinearScan::run() {
if (DEBUG) std::cerr << "===== Running Linear Scan Register Allocation for function: " << MFunc->getName() << " =====\n";
bool changed = true;
while(changed) {
// 1. 准备阶段
linearizeBlocks();
computeLiveIntervals();
// 2. 执行线性扫描
changed = linearScan();
// 3. 如果有溢出,重写代码,然后下一轮重新开始
if (changed) {
rewriteProgram();
if (DEBUG) std::cerr << "--- Spilling detected, re-running linear scan ---\n";
}
}
// 4. 将最终分配结果应用到机器指令
applyAllocation();
// 5. 收集用到的被调用者保存寄存器
MFunc->getFrameInfo().vreg_to_preg_map = this->vreg_to_preg_map;
collectUsedCalleeSavedRegs();
if (DEBUG) std::cerr << "===== Finished Linear Scan Register Allocation =====\n\n";
}
// 步骤 1.1: 对基本块进行线性化,这里我们简单地按现有顺序排列
void RISCv64LinearScan::linearizeBlocks() {
linear_order_blocks.clear();
for (auto& mbb : MFunc->getBlocks()) {
linear_order_blocks.push_back(mbb.get());
}
}
// 步骤 1.2: 计算活跃区间
void RISCv64LinearScan::computeLiveIntervals() {
instr_numbering.clear();
live_intervals.clear();
unhandled.clear();
// a. 对所有指令进行线性编号
int num = 0;
for (auto* mbb : linear_order_blocks) {
for (auto& instr : mbb->getInstructions()) {
instr_numbering[instr.get()] = num;
num += 2; // 指令编号间隔为2方便在溢出重写时插入指令
}
}
// b. (新逻辑) 遍历所有指令记录每个vreg首次和末次出现的位置
std::map<unsigned, std::pair<int, int>> vreg_ranges; // vreg -> {first_instr_num, last_instr_num}
for (auto* mbb : linear_order_blocks) {
for (auto& instr_ptr : mbb->getInstructions()) {
const MachineInstr* instr = instr_ptr.get();
int instr_num = instr_numbering.at(instr);
std::set<unsigned> use, def;
getInstrUseDef(instr, use, def);
// 合并use和def集合获取本条指令涉及的所有vreg
auto all_vregs = use;
all_vregs.insert(def.begin(), def.end());
// 更新每个vreg的区间边界
for (unsigned vreg : all_vregs) {
if (vreg_ranges.find(vreg) == vreg_ranges.end()) {
// 第一次见到这个vreg记录首次和末次位置
vreg_ranges[vreg] = {instr_num, instr_num};
} else {
// 更新末次位置
vreg_ranges[vreg].second = std::max(vreg_ranges[vreg].second, instr_num);
}
}
}
}
// c. 根据记录的边界创建LiveInterval对象
for (auto const& [vreg, range] : vreg_ranges) {
live_intervals.emplace(vreg, LiveInterval(vreg));
live_intervals.at(vreg).start = range.first;
live_intervals.at(vreg).end = range.second;
}
// d. 将所有计算出的活跃区间放入 unhandled 列表
for (auto& pair : live_intervals) {
unhandled.push_back(&pair.second);
}
std::sort(unhandled.begin(), unhandled.end(), [](const LiveInterval* a, const LiveInterval* b){
return a->start < b->start;
});
}
// 步骤 2: 线性扫描主算法
bool RISCv64LinearScan::linearScan() {
// 初始化/重置状态
active.clear();
spilled_vregs.clear();
vreg_to_preg_map.clear();
free_int_regs.clear();
free_fp_regs.clear();
free_int_regs.insert(allocable_int_regs.begin(), allocable_int_regs.end());
free_fp_regs.insert(allocable_fp_regs.begin(), allocable_fp_regs.end());
// 1. 将ABI参数的vreg直接分配给其固定的物理寄存器
vreg_to_preg_map.insert(abi_vreg_map.begin(), abi_vreg_map.end());
// 2. 从unhandled列表中移除这些ABI参数区间并将其加入active列表
std::vector<LiveInterval*> normal_unhandled;
for(LiveInterval* interval : unhandled) {
if(abi_vreg_map.count(interval->vreg)) {
// 这是一个ABI参数区间它已经被“预分配”
active.push_back(interval);
// 从空闲池中移除对应的物理寄存器
PhysicalReg preg = abi_vreg_map.at(interval->vreg);
if (isFPVReg(interval->vreg)) {
free_fp_regs.erase(preg);
} else {
free_int_regs.erase(preg);
}
} else {
// 这是一个普通区间,留待后续处理
normal_unhandled.push_back(interval);
}
}
unhandled = normal_unhandled; // 更新unhandled列表只包含普通区间
// 3. 对active列表现在只包含ABI参数按结束点排序
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){
return a->end < b->end;
});
for (LiveInterval* current : unhandled) {
// a. 检查并释放 active 列表中已经结束的区间
std::vector<LiveInterval*> new_active;
for (LiveInterval* active_interval : active) {
if (active_interval->end < current->start) {
// 此区间已结束,释放其物理寄存器
PhysicalReg preg = vreg_to_preg_map.at(active_interval->vreg);
if (isFPVReg(active_interval->vreg)) free_fp_regs.insert(preg);
else free_int_regs.insert(preg);
} else {
new_active.push_back(active_interval);
}
}
active = new_active;
// b. 尝试为当前区间分配寄存器
chooseRegForInterval(current);
}
return !spilled_vregs.empty();
}
void RISCv64LinearScan::chooseRegForInterval(LiveInterval* current) {
bool is_fp = isFPVReg(current->vreg);
auto& free_regs = is_fp ? free_fp_regs : free_int_regs;
if (!free_regs.empty()) {
// 有可用寄存器
PhysicalReg preg = *free_regs.begin();
free_regs.erase(free_regs.begin());
vreg_to_preg_map[current->vreg] = preg;
active.push_back(current);
// 保持 active 列表按结束点排序
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){
return a->end < b->end;
});
} else {
// 没有可用寄存器,需要溢出
spillAtInterval(current);
}
}
void RISCv64LinearScan::spillAtInterval(LiveInterval* current) {
// 启发式:比较当前区间和 active 列表中结束点最晚的区间
LiveInterval* spill_candidate = active.back(); // active已按end排序最后一个就是结束最晚的
if (spill_candidate->end > current->end) {
// active中的区间结束得更晚溢出它
PhysicalReg preg = vreg_to_preg_map.at(spill_candidate->vreg);
// 将被溢出区间的物理寄存器分配给当前区间
vreg_to_preg_map[current->vreg] = preg;
// 更新 active 列表
active.pop_back(); // 移除被溢出的
active.push_back(current); // 加入当前的
std::sort(active.begin(), active.end(), [](const LiveInterval* a, const LiveInterval* b){
return a->end < b->end;
});
spilled_vregs.insert(spill_candidate->vreg);
if(DEBUG) std::cerr << " Spilling vreg" << spill_candidate->vreg << " to make room for vreg" << current->vreg << "\n";
} else {
// 当前区间结束得更晚,直接溢出当前区间
spilled_vregs.insert(current->vreg);
if(DEBUG) std::cerr << " Spilling current vreg" << current->vreg << "\n";
}
}
// 步骤 3: 重写程序,插入溢出代码
void RISCv64LinearScan::rewriteProgram() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int spill_offset = frame_info.locals_size; // 溢出区域接在局部变量之后
for (unsigned vreg : spilled_vregs) {
if (frame_info.spill_offsets.count(vreg)) continue; // 避免重复分配
int size = isFPVReg(vreg) ? 4 : (vreg_type_map.at(vreg)->isPointer() ? 8 : 4);
spill_offset += size;
spill_offset = (spill_offset + 7) & ~7; // 8字节对齐
frame_info.spill_offsets[vreg] = -(16 + spill_offset);
}
frame_info.spill_size = spill_offset - frame_info.locals_size;
for (auto& mbb : MFunc->getBlocks()) {
auto& instrs = mbb->getInstructions();
std::vector<std::unique_ptr<MachineInstr>> new_instrs;
for (auto it = instrs.begin(); it != instrs.end(); ++it) {
auto& instr = *it;
std::set<unsigned> use, def;
getInstrUseDef(instr.get(), use, def);
// 为每个溢出的 use 创建 load
for (unsigned old_vreg : use) {
if (spilled_vregs.count(old_vreg)) {
Type* type = vreg_type_map.at(old_vreg);
unsigned new_temp_vreg = ISel->getNewVReg(type);
RVOpcodes load_op = isFPVReg(old_vreg) ? RVOpcodes::FLW : (type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))
));
new_instrs.push_back(std::move(load));
// 替换原指令中的 use
for(auto& op : instr->getOperands()) {
if(op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if(reg_op->isVirtual() && reg_op->getVRegNum() == old_vreg) {
reg_op->setVRegNum(new_temp_vreg);
}
} else if(op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op.get());
auto base_reg = mem_op->getBase();
if(base_reg->isVirtual() && base_reg->getVRegNum() == old_vreg) {
base_reg->setVRegNum(new_temp_vreg);
}
}
}
}
}
new_instrs.push_back(std::move(instr));
// 为每个溢出的 def 创建 store
for (unsigned old_vreg : def) {
if (spilled_vregs.count(old_vreg)) {
Type* type = vreg_type_map.at(old_vreg);
unsigned new_temp_vreg = ISel->getNewVReg(type);
// 替换原指令中的 def
for(auto& op : new_instrs.back()->getOperands()) {
if(op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if(reg_op->isVirtual() && reg_op->getVRegNum() == old_vreg) {
reg_op->setVRegNum(new_temp_vreg);
}
}
}
RVOpcodes store_op = isFPVReg(old_vreg) ? RVOpcodes::FSW : (type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(new_temp_vreg));
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(old_vreg))
));
new_instrs.push_back(std::move(store));
}
}
}
instrs = std::move(new_instrs);
}
}
// 步骤 4: 应用最终分配结果
void RISCv64LinearScan::applyAllocation() {
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr_ptr : mbb->getInstructions()) {
for (auto& op_ptr : instr_ptr->getOperands()) {
if (op_ptr->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (vreg_to_preg_map.count(vreg)) {
reg_op->setPReg(vreg_to_preg_map.at(vreg));
} else {
// 如果一个vreg最终没有颜色这通常意味着它是一个短生命周期的临时变量
// 在溢出重写中产生,但在下一轮分配前就被优化掉了。
// 或者是一个从未被使用的定义。
// 给他一个临时寄存器以防万一。
reg_op->setPReg(PhysicalReg::T5);
}
}
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
auto reg_op = mem_op->getBase();
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (vreg_to_preg_map.count(vreg)) {
reg_op->setPReg(vreg_to_preg_map.at(vreg));
} else {
reg_op->setPReg(PhysicalReg::T5);
}
}
}
}
}
}
}
// 辅助函数: 获取指令的use/def集合 (仅虚拟寄存器)
void RISCv64LinearScan::getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def) {
// 这个函数与图着色版本中的 getInstrUseDef 逻辑完全相同,此处直接复用
auto opcode = instr->getOpcode();
const auto& operands = instr->getOperands();
static const std::map<RVOpcodes, std::pair<std::vector<int>, std::vector<int>>> op_info = {
{RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}},
{RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}},
{RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}},
{RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}},
{RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}},
{RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, {RVOpcodes::LB, {{0}, {}}},
{RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}},
{RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}},
{RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, {RVOpcodes::SB, {{}, {0, 1}}},
{RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}},
{RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, {RVOpcodes::BEQ, {{}, {0, 1}}},
{RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}},
{RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}},
{RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}},
{RVOpcodes::RET, {{}, {}}}, {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}},
{RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}},
{RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}},
{RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}},
{RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}}
};
auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set<unsigned>& s) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<const RegOperand*>(op);
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
} else if (op->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<const MemOperand*>(op);
auto reg_op = mem_op->getBase();
if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum());
}
};
if (op_info.count(opcode)) {
const auto& info = op_info.at(opcode);
for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def);
for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use);
for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use);
} else if (opcode == RVOpcodes::CALL) {
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def);
for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use);
}
}
// 辅助函数: 判断是否为浮点vreg
bool RISCv64LinearScan::isFPVReg(unsigned vreg) const {
return vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isFloat();
}
// 辅助函数: 收集被使用的被调用者保存寄存器
void RISCv64LinearScan::collectUsedCalleeSavedRegs() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
frame_info.used_callee_saved_regs.clear();
const auto& callee_saved_int = getCalleeSavedIntRegs();
const auto& callee_saved_fp = getCalleeSavedFpRegs();
std::set<PhysicalReg> callee_saved_set(callee_saved_int.begin(), callee_saved_int.end());
callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end());
callee_saved_set.insert(PhysicalReg::S0); // s0总是被用作帧指针
for(const auto& pair : vreg_to_preg_map) {
PhysicalReg preg = pair.second;
if(callee_saved_set.count(preg)) {
frame_info.used_callee_saved_regs.insert(preg);
}
}
}
} // namespace sysy

View File

@@ -55,41 +55,12 @@ void RISCv64RegAlloc::run() {
if (DEBUG) std::cerr << "===== Running Graph Coloring Register Allocation for function: " << MFunc->getName() << " =====\n";
const int MAX_ITERATIONS = 50;
int iteration = 0;
while (iteration++ < MAX_ITERATIONS) {
while (true) {
if (doAllocation()) {
break;
} else {
rewriteProgram();
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation (iteration " << iteration << ") ---\n";
if (iteration >= MAX_ITERATIONS) {
std::cerr << "ERROR: Register allocation failed to converge after " << MAX_ITERATIONS << " iterations\n";
std::cerr << " Spill worklist size: " << spillWorklist.size() << "\n";
std::cerr << " Total nodes: " << (initial.size() + coloredNodes.size()) << "\n";
// Emergency spill remaining nodes to break the loop
std::cerr << " Emergency spilling remaining spill worklist nodes...\n";
for (unsigned node : spillWorklist) {
spilledNodes.insert(node);
}
// Also spill any nodes that didn't get colors
std::set<unsigned> uncolored;
for (unsigned node : initial) {
if (color_map.find(node) == color_map.end()) {
uncolored.insert(node);
}
}
for (unsigned node : uncolored) {
spilledNodes.insert(node);
}
// Force completion
break;
}
if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation ---\n";
}
}

View File

@@ -0,0 +1,81 @@
#ifndef RISCV64_LINEARSCAN_H
#define RISCV64_LINEARSCAN_H
#include "RISCv64LLIR.h"
#include "RISCv64ISel.h"
#include <vector>
#include <map>
#include <set>
#include <algorithm>
namespace sysy {
// 前向声明
class MachineBasicBlock;
class MachineFunction;
class RISCv64ISel;
/**
* @brief 表示一个虚拟寄存器的活跃区间。
* 包含起始和结束指令编号。为了简化,我们不处理有“洞”的区间。
*/
struct LiveInterval {
unsigned vreg = 0;
int start = -1;
int end = -1;
LiveInterval(unsigned vreg) : vreg(vreg) {}
// 用于排序,按起始点从小到大
bool operator<(const LiveInterval& other) const {
return start < other.start;
}
};
class RISCv64LinearScan {
public:
RISCv64LinearScan(MachineFunction* mfunc);
void run();
private:
// --- 核心算法流程 ---
void linearizeBlocks();
void computeLiveIntervals();
bool linearScan();
void rewriteProgram();
void applyAllocation();
void chooseRegForInterval(LiveInterval* current);
void spillAtInterval(LiveInterval* current);
// --- 辅助函数 ---
void getInstrUseDef(const MachineInstr* instr, std::set<unsigned>& use, std::set<unsigned>& def);
bool isFPVReg(unsigned vreg) const;
void collectUsedCalleeSavedRegs();
MachineFunction* MFunc;
RISCv64ISel* ISel;
// --- 线性扫描数据结构 ---
std::vector<MachineBasicBlock*> linear_order_blocks;
std::map<const MachineInstr*, int> instr_numbering;
std::map<unsigned, LiveInterval> live_intervals;
std::vector<LiveInterval*> unhandled;
std::vector<LiveInterval*> active; // 活跃且已分配物理寄存器的区间
std::set<unsigned> spilled_vregs; // 记录在本轮被决定溢出的vreg
// --- 寄存器池和分配结果 ---
std::vector<PhysicalReg> allocable_int_regs;
std::vector<PhysicalReg> allocable_fp_regs;
std::set<PhysicalReg> free_int_regs;
std::set<PhysicalReg> free_fp_regs;
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
std::map<unsigned, PhysicalReg> abi_vreg_map;
const std::map<unsigned, Type*>& vreg_type_map;
};
} // namespace sysy
#endif // RISCV64_LINEARSCAN_H