deploy-20250820-3 #1
@@ -6,6 +6,7 @@ add_library(riscv64_backend_lib STATIC
|
||||
RISCv64LLIR.cpp
|
||||
RISCv64RegAlloc.cpp
|
||||
RISCv64LinearScan.cpp
|
||||
RISCv64SimpleRegAlloc.cpp
|
||||
RISCv64BasicBlockAlloc.cpp
|
||||
Handler/CalleeSavedHandler.cpp
|
||||
Handler/LegalizeImmediates.cpp
|
||||
|
||||
@@ -184,7 +184,7 @@ void RISCv64AsmPrinter::printOperand(MachineOperand* op) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) {
|
||||
std::string RISCv64AsmPrinter::regToString(PhysicalReg reg) const {
|
||||
switch (reg) {
|
||||
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
|
||||
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "RISCv64ISel.h"
|
||||
#include "RISCv64RegAlloc.h"
|
||||
#include "RISCv64LinearScan.h"
|
||||
#include "RISCv64SimpleRegAlloc.h"
|
||||
#include "RISCv64BasicBlockAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Passes.h"
|
||||
@@ -197,6 +198,8 @@ std::string RISCv64CodeGen::module_gen() {
|
||||
}
|
||||
|
||||
std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
// === 完整的后端处理流水线 ===
|
||||
|
||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||
@@ -217,7 +220,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
EliminateFrameIndicesPass efi_pass;
|
||||
efi_pass.runOnMachineFunction(mfunc.get());
|
||||
|
||||
if (DEBUG) {
|
||||
if (true) {
|
||||
std::cerr << "====== stack info after eliminate frame indices ======\n";
|
||||
mfunc->dumpStackFrameInfo(std::cerr);
|
||||
std::stringstream ss_after_eli;
|
||||
@@ -237,7 +240,17 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
// 阶段 3: 物理寄存器分配 (Register Allocation)
|
||||
|
||||
// 首先尝试图着色分配器
|
||||
if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n";
|
||||
// int fooo = 0;
|
||||
int fooo = 0;
|
||||
// DEBUG = 1;
|
||||
// DEEPDEBUG = 1;
|
||||
if (fooo) {
|
||||
RISCv64SimpleRegAlloc simple_alloc(mfunc.get());
|
||||
simple_alloc.run();
|
||||
DEBUG = 0;
|
||||
DEEPDEBUG = 0;
|
||||
} else
|
||||
{if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n";
|
||||
if (!gc_failed) {
|
||||
RISCv64RegAlloc gc_alloc(mfunc.get());
|
||||
|
||||
@@ -296,7 +309,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
RISCv64BasicBlockAlloc bb_alloc(mfunc.get());
|
||||
bb_alloc.run();
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
|
||||
if (DEBUG) {
|
||||
|
||||
667
src/backend/RISCv64/RISCv64SimpleRegAlloc.cpp
Normal file
667
src/backend/RISCv64/RISCv64SimpleRegAlloc.cpp
Normal file
@@ -0,0 +1,667 @@
|
||||
#include "RISCv64SimpleRegAlloc.h"
|
||||
#include "RISCv64AsmPrinter.h"
|
||||
#include "RISCv64Info.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
// 外部调试级别控制变量的定义
|
||||
// 假设这些变量在其他地方定义,例如主程序或一个通用的cpp文件
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
RISCv64SimpleRegAlloc::RISCv64SimpleRegAlloc(MachineFunction* mfunc) : MFunc(mfunc), ISel(mfunc->getISel()) {
|
||||
// 1. 初始化可分配的整数寄存器池
|
||||
// 保留 t0, t1 用于其他目的, t2, t3, t4 作为溢出寄存器
|
||||
allocable_int_regs = {
|
||||
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T4, /*PhysicalReg::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,
|
||||
};
|
||||
|
||||
// 2. 初始化可分配的浮点寄存器池
|
||||
// 保留 f4 作为溢出寄存器
|
||||
allocable_fp_regs = {
|
||||
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, /* 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,
|
||||
};
|
||||
|
||||
// 3. 映射所有物理寄存器(包括整数、浮点和特殊寄存器)到特殊的虚拟寄存器ID
|
||||
// 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
for (unsigned i = 0; i < static_cast<unsigned>(PhysicalReg::INVALID); ++i) {
|
||||
auto preg = static_cast<PhysicalReg>(i);
|
||||
preg_to_vreg_id_map[preg] = offset + i;
|
||||
}
|
||||
}
|
||||
|
||||
// 寄存器分配的主入口点
|
||||
void RISCv64SimpleRegAlloc::run() {
|
||||
if (DEBUG) std::cerr << "===== Running Simple Graph Coloring Allocator for function: " << MFunc->getName() << " =====\n";
|
||||
|
||||
// 实例化一个AsmPrinter用于调试输出,避免重复创建
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
printer.setStream(std::cerr);
|
||||
|
||||
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||
handleCallingConvention();
|
||||
if (DEBUG) {
|
||||
std::cerr << "--- After HandleCallingConvention ---\n";
|
||||
std::cerr << "Pre-colored vregs:\n";
|
||||
for (const auto& pair : color_map) {
|
||||
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 2: 活跃性分析
|
||||
analyzeLiveness();
|
||||
|
||||
// 阶段 3: 构建干扰图
|
||||
buildInterferenceGraph();
|
||||
|
||||
// 阶段 4: 图着色算法分配物理寄存器
|
||||
colorGraph();
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n--- After GraphColoring ---\n";
|
||||
std::cerr << "Assigned colors:\n";
|
||||
for (const auto& pair : color_map) {
|
||||
std::cerr << " %vreg" << pair.first << " -> " << printer.regToString(pair.second) << "\n";
|
||||
}
|
||||
std::cerr << "Spilled vregs:\n";
|
||||
if (spilled_vregs.empty()) {
|
||||
std::cerr << " (None)\n";
|
||||
} else {
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
std::cerr << " %vreg" << vreg << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阶段 5: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||
rewriteFunction();
|
||||
|
||||
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用
|
||||
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cerr << "\n===== Final LLIR after Simple Register Allocation =====\n";
|
||||
printer.run(std::cerr, false); // 使用false来打印最终的物理寄存器
|
||||
std::cerr << "===== Finished Simple Graph Coloring Allocator =====\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [新增] 虚拟寄存器统一预处理
|
||||
* 扫描函数,找到通过栈帧传递的参数,并将后续从该栈帧加载的VReg统一为原始的参数VReg。
|
||||
*/
|
||||
void RISCv64SimpleRegAlloc::unifyArgumentVRegs() {
|
||||
if (MFunc->getBlocks().size() < 2) return; // 至少需要入口和函数体两个块
|
||||
|
||||
std::map<int, unsigned> stack_slot_to_vreg; // 映射: <栈偏移, 原始参数vreg>
|
||||
MachineBasicBlock* entry_block = MFunc->getBlocks().front().get();
|
||||
|
||||
// 步骤 1: 扫描入口块,找到所有参数的“家(home)”在栈上的位置
|
||||
for (const auto& instr : entry_block->getInstructions()) {
|
||||
// 我们寻找 sw %vreg_arg, 0(%vreg_addr) 的模式
|
||||
if (instr->getOpcode() == RVOpcodes::SW || instr->getOpcode() == RVOpcodes::SD || instr->getOpcode() == RVOpcodes::FSW) {
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto src_reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
auto mem_op = static_cast<MemOperand*>(operands[1].get());
|
||||
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
|
||||
|
||||
// 查找定义这个地址vreg的addi指令,以获取偏移量
|
||||
for (const auto& prev_instr : entry_block->getInstructions()) {
|
||||
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
|
||||
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
|
||||
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
|
||||
stack_slot_to_vreg[offset] = src_reg_op->getVRegNum();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack_slot_to_vreg.empty()) return; // 没有找到参数存储,无需处理
|
||||
|
||||
// 步骤 2: 扫描函数体,构建本地vreg到参数vreg的重映射表
|
||||
std::map<unsigned, unsigned> vreg_remap; // 映射: <本地vreg, 原始参数vreg>
|
||||
MachineBasicBlock* body_block = MFunc->getBlocks()[1].get();
|
||||
|
||||
for (const auto& instr : body_block->getInstructions()) {
|
||||
if (instr->getOpcode() == RVOpcodes::LW || instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::FLW) {
|
||||
auto& operands = instr->getOperands();
|
||||
if (operands.size() == 2 && operands[0]->getKind() == MachineOperand::KIND_REG && operands[1]->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto dest_reg_op = static_cast<RegOperand*>(operands[0].get());
|
||||
auto mem_op = static_cast<MemOperand*>(operands[1].get());
|
||||
unsigned addr_vreg = mem_op->getBase()->getVRegNum();
|
||||
|
||||
// 同样地,查找定义地址的addi指令
|
||||
for (const auto& prev_instr : body_block->getInstructions()) {
|
||||
if (prev_instr->getOpcode() == RVOpcodes::ADDI && prev_instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||
auto def_op = static_cast<RegOperand*>(prev_instr->getOperands().front().get());
|
||||
if (def_op->isVirtual() && def_op->getVRegNum() == addr_vreg) {
|
||||
int offset = static_cast<ImmOperand*>(prev_instr->getOperands()[2].get())->getValue();
|
||||
if (stack_slot_to_vreg.count(offset)) {
|
||||
unsigned old_vreg = dest_reg_op->getVRegNum();
|
||||
unsigned new_vreg = stack_slot_to_vreg.at(offset);
|
||||
vreg_remap[old_vreg] = new_vreg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vreg_remap.empty()) return;
|
||||
|
||||
// 步骤 3: 遍历所有指令,应用重映射
|
||||
// 定义一个lambda函数来替换vreg,避免代码重复
|
||||
auto replace_vreg_in_operand = [&](MachineOperand* op) {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(op);
|
||||
if (reg_op->isVirtual() && vreg_remap.count(reg_op->getVRegNum())) {
|
||||
reg_op->setVRegNum(vreg_remap.at(reg_op->getVRegNum()));
|
||||
}
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto base_reg_op = static_cast<MemOperand*>(op)->getBase();
|
||||
if (base_reg_op->isVirtual() && vreg_remap.count(base_reg_op->getVRegNum())) {
|
||||
base_reg_op->setVRegNum(vreg_remap.at(base_reg_op->getVRegNum()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
replace_vreg_in_operand(op.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::handleCallingConvention() {
|
||||
Function* F = MFunc->getFunc();
|
||||
if (!F) return;
|
||||
|
||||
// --- 1. 处理函数传入参数的预着色 ---
|
||||
int int_arg_idx = 0;
|
||||
int float_arg_idx = 0;
|
||||
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
unsigned vreg = ISel->getVReg(arg);
|
||||
if (arg->getType()->isFloat()) {
|
||||
if (float_arg_idx < 8) { // fa0-fa7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
float_arg_idx++;
|
||||
} else {
|
||||
if (int_arg_idx < 8) { // a0-a7
|
||||
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
|
||||
color_map[vreg] = preg;
|
||||
}
|
||||
int_arg_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2. 为CALL指令的返回值预着色 ---
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
if (instr->getOpcode() == RVOpcodes::CALL && !instr->getOperands().empty()) {
|
||||
auto& first_op = instr->getOperands().front();
|
||||
if (first_op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<RegOperand*>(first_op.get());
|
||||
if (reg_op->isVirtual()) {
|
||||
unsigned ret_vreg = reg_op->getVRegNum();
|
||||
auto [type, size] = getTypeAndSize(ret_vreg);
|
||||
if (type == Type::kFloat) {
|
||||
color_map[ret_vreg] = PhysicalReg::F10; // fa0
|
||||
} else {
|
||||
color_map[ret_vreg] = PhysicalReg::A0; // a0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::analyzeLiveness() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Liveness Analysis ---\n";
|
||||
|
||||
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_uses;
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_defs;
|
||||
for (const auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet uses, defs;
|
||||
for (const auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet instr_use, instr_def;
|
||||
getInstrUseDef_Liveness(instr_ptr.get(), instr_use, instr_def);
|
||||
// use[B] = use[B] U (instr_use - def[B])
|
||||
for (unsigned u : instr_use) {
|
||||
if (defs.find(u) == defs.end()) {
|
||||
uses.insert(u);
|
||||
}
|
||||
}
|
||||
// def[B] = def[B] U instr_def
|
||||
defs.insert(instr_def.begin(), instr_def.end());
|
||||
}
|
||||
block_uses[mbb] = uses;
|
||||
block_defs[mbb] = defs;
|
||||
}
|
||||
|
||||
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_live_in;
|
||||
std::map<const MachineBasicBlock*, LiveSet> block_live_out;
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
// 逆序遍历基本块,加速收敛
|
||||
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
|
||||
const auto& mbb_ptr = *it;
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
|
||||
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
|
||||
LiveSet new_live_out;
|
||||
for (auto succ : mbb->successors) {
|
||||
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
|
||||
}
|
||||
|
||||
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
|
||||
LiveSet live_out_minus_def = new_live_out;
|
||||
for (unsigned d : block_defs.at(mbb)) {
|
||||
live_out_minus_def.erase(d);
|
||||
}
|
||||
LiveSet new_live_in = block_uses.at(mbb);
|
||||
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
|
||||
|
||||
// 2.3 检查是否达到不动点
|
||||
if (block_live_out[mbb] != new_live_out || block_live_in[mbb] != new_live_in) {
|
||||
changed = true;
|
||||
block_live_out[mbb] = new_live_out;
|
||||
block_live_in[mbb] = new_live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
|
||||
for (const auto& mbb_ptr : MFunc->getBlocks()) {
|
||||
const MachineBasicBlock* mbb = mbb_ptr.get();
|
||||
LiveSet live_out = block_live_out.at(mbb);
|
||||
|
||||
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
|
||||
const MachineInstr* instr = instr_it->get();
|
||||
live_out_map[instr] = live_out;
|
||||
|
||||
LiveSet use, def;
|
||||
getInstrUseDef_Liveness(instr, use, def);
|
||||
|
||||
LiveSet live_in = use;
|
||||
LiveSet diff = live_out;
|
||||
for (auto vreg : def) {
|
||||
diff.erase(vreg);
|
||||
}
|
||||
live_in.insert(diff.begin(), diff.end());
|
||||
live_in_map[instr] = live_in;
|
||||
|
||||
// 更新 live_out,为块内的上一条指令做准备
|
||||
live_out = live_in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::buildInterferenceGraph() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Interference Graph Construction ---\n";
|
||||
RISCv64AsmPrinter printer(MFunc);
|
||||
printer.setStream(std::cerr);
|
||||
|
||||
// 1. 收集所有图中需要出现的节点 (所有虚拟寄存器和物理寄存器)
|
||||
std::set<unsigned> all_nodes;
|
||||
for (const auto& mbb : MFunc->getBlocks()) {
|
||||
for(const auto& instr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef_Liveness(instr.get(), use, def);
|
||||
all_nodes.insert(use.begin(), use.end());
|
||||
all_nodes.insert(def.begin(), def.end());
|
||||
}
|
||||
}
|
||||
// 确保所有物理寄存器节点也存在
|
||||
for (const auto& pair : preg_to_vreg_id_map) {
|
||||
all_nodes.insert(pair.second);
|
||||
}
|
||||
|
||||
// 2. 初始化干扰图邻接表
|
||||
for (unsigned vreg : all_nodes) { interference_graph[vreg] = {}; }
|
||||
|
||||
// 3. 遍历指令,添加冲突边
|
||||
for (const auto& mbb : MFunc->getBlocks()) {
|
||||
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
|
||||
for (const auto& instr_ptr : mbb->getInstructions()) {
|
||||
const MachineInstr* instr = instr_ptr.get();
|
||||
if (DEEPDEBUG) {
|
||||
std::cerr << " Instr: ";
|
||||
printer.printInstruction(const_cast<MachineInstr*>(instr), true);
|
||||
}
|
||||
|
||||
LiveSet def, use;
|
||||
getInstrUseDef_Liveness(instr, def, use); // 注意Use/Def顺序
|
||||
const LiveSet& live_out = live_out_map.at(instr);
|
||||
|
||||
if (DEEPDEBUG) {
|
||||
printLiveSet(use, "Use ", std::cerr, printer);
|
||||
printLiveSet(def, "Def ", std::cerr, printer);
|
||||
printLiveSet(live_out, "Live_Out", std::cerr, printer);
|
||||
}
|
||||
|
||||
// 规则1: 指令的定义(def)与该指令之后的所有活跃变量(live_out)冲突
|
||||
for (unsigned d : def) {
|
||||
for (unsigned l : live_out) {
|
||||
if (d != l) {
|
||||
if (DEEPDEBUG && interference_graph.at(d).find(l) == interference_graph.at(d).end()) {
|
||||
std::cerr << " Edge (Def-LiveOut): " << regIdToString(d, printer) << " <-> " << regIdToString(l, printer) << "\n";
|
||||
}
|
||||
interference_graph[d].insert(l);
|
||||
interference_graph[l].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 规则2: 对于非MV指令, def与use也冲突
|
||||
if (instr->getOpcode() != RVOpcodes::MV) {
|
||||
for (unsigned d : def) {
|
||||
for (unsigned u : use) {
|
||||
if (d != u) {
|
||||
if (DEEPDEBUG && interference_graph.at(d).find(u) == interference_graph.at(d).end()) {
|
||||
std::cerr << " Edge (Def-Use): " << regIdToString(d, printer) << " <-> " << regIdToString(u, printer) << "\n";
|
||||
}
|
||||
interference_graph[d].insert(u);
|
||||
interference_graph[u].insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有在某一点上同时活跃的寄存器(即live_out集合中的所有成员),
|
||||
// 它们之间必须两两互相干扰。
|
||||
std::vector<unsigned> live_out_vec(live_out.begin(), live_out.end());
|
||||
for (size_t i = 0; i < live_out_vec.size(); ++i) {
|
||||
for (size_t j = i + 1; j < live_out_vec.size(); ++j) {
|
||||
unsigned u = live_out_vec[i];
|
||||
unsigned v = live_out_vec[j];
|
||||
if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) {
|
||||
std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n";
|
||||
}
|
||||
interference_graph[u].insert(v);
|
||||
interference_graph[v].insert(u);
|
||||
}
|
||||
}
|
||||
|
||||
// 规则3: CALL指令会破坏所有调用者保存(caller-saved)寄存器
|
||||
if (instr->getOpcode() == RVOpcodes::CALL) {
|
||||
const auto& caller_saved_int = getCallerSavedIntRegs();
|
||||
const auto& caller_saved_fp = getCallerSavedFpRegs();
|
||||
|
||||
for (unsigned live_vreg : live_out) {
|
||||
auto [type, size] = getTypeAndSize(live_vreg);
|
||||
if (type == Type::kFloat) {
|
||||
for (PhysicalReg cs_reg : caller_saved_fp) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
if (live_vreg != cs_vreg_id) {
|
||||
interference_graph[live_vreg].insert(cs_vreg_id);
|
||||
interference_graph[cs_vreg_id].insert(live_vreg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (PhysicalReg cs_reg : caller_saved_int) {
|
||||
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
|
||||
if (live_vreg != cs_vreg_id) {
|
||||
interference_graph[live_vreg].insert(cs_vreg_id);
|
||||
interference_graph[cs_vreg_id].insert(live_vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if CALL
|
||||
if (DEEPDEBUG) std::cerr << " ----------------\n";
|
||||
} // end for instr
|
||||
} // end for mbb
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::colorGraph() {
|
||||
// 1. 收集所有需要着色的虚拟寄存器
|
||||
std::vector<unsigned> vregs_to_color;
|
||||
for (auto const& [vreg, neighbors] : interference_graph) {
|
||||
// 只为未预着色的、真正的虚拟寄存器进行着色
|
||||
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
vregs_to_color.push_back(vreg);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 按冲突度从高到低排序,进行贪心着色
|
||||
std::sort(vregs_to_color.begin(), vregs_to_color.end(), [&](unsigned a, unsigned b) {
|
||||
return interference_graph.at(a).size() > interference_graph.at(b).size();
|
||||
});
|
||||
|
||||
// 3. 遍历并着色
|
||||
for (unsigned vreg : vregs_to_color) {
|
||||
std::set<PhysicalReg> used_colors;
|
||||
// 收集所有邻居的颜色
|
||||
for (unsigned neighbor_id : interference_graph.at(vreg)) {
|
||||
// A. 邻居是已着色的vreg
|
||||
if (color_map.count(neighbor_id)) {
|
||||
used_colors.insert(color_map.at(neighbor_id));
|
||||
}
|
||||
// B. 邻居是物理寄存器本身
|
||||
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
|
||||
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
|
||||
used_colors.insert(neighbor_preg);
|
||||
}
|
||||
}
|
||||
|
||||
// 根据vreg类型选择寄存器池
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
const auto& allocable_regs = (type == Type::kFloat) ? allocable_fp_regs : allocable_int_regs;
|
||||
|
||||
bool colored = false;
|
||||
for (PhysicalReg preg : allocable_regs) {
|
||||
if (used_colors.find(preg) == used_colors.end()) {
|
||||
color_map[vreg] = preg;
|
||||
colored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colored) {
|
||||
spilled_vregs.insert(vreg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::rewriteFunction() {
|
||||
if (DEBUG) std::cerr << "\n--- Starting Function Rewrite (Spilling & Substitution) ---\n";
|
||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||
|
||||
// 1. 为所有溢出的vreg计算栈偏移量
|
||||
// 溢出区域紧跟在局部变量区域之后
|
||||
int current_offset = frame_info.locals_end_offset;
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
// 按变量大小对齐
|
||||
current_offset -= size;
|
||||
current_offset = current_offset & -size;
|
||||
frame_info.spill_offsets[vreg] = current_offset;
|
||||
}
|
||||
// 更新总的溢出区域大小
|
||||
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
|
||||
|
||||
// 2. 插入加载/存储指令
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
LiveSet use, def;
|
||||
getInstrUseDef(instr_ptr.get(), use, def); // 这里用不含物理寄存器的版本
|
||||
|
||||
// a. 为溢出的 'use' 操作数插入加载指令
|
||||
for (unsigned vreg : use) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
RVOpcodes load_op;
|
||||
PhysicalReg target_preg;
|
||||
if (type == Type::kFloat) { load_op = RVOpcodes::FLW; target_preg = FP_SPILL_REG; }
|
||||
else if (type == Type::kPointer) { load_op = RVOpcodes::LD; target_preg = PTR_SPILL_REG; }
|
||||
else { load_op = RVOpcodes::LW; target_preg = INT_SPILL_REG; }
|
||||
|
||||
auto load = std::make_unique<MachineInstr>(load_op);
|
||||
load->addOperand(std::make_unique<RegOperand>(target_preg));
|
||||
load->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(load));
|
||||
}
|
||||
}
|
||||
|
||||
// b. 放入原始指令
|
||||
new_instructions.push_back(std::move(instr_ptr));
|
||||
|
||||
// c. 为溢出的 'def' 操作数插入存储指令
|
||||
for (unsigned vreg : def) {
|
||||
if (spilled_vregs.count(vreg)) {
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
RVOpcodes store_op;
|
||||
PhysicalReg src_preg;
|
||||
if (type == Type::kFloat) { store_op = RVOpcodes::FSW; src_preg = FP_SPILL_REG; }
|
||||
else if (type == Type::kPointer) { store_op = RVOpcodes::SD; src_preg = PTR_SPILL_REG; }
|
||||
else { store_op = RVOpcodes::SW; src_preg = INT_SPILL_REG; }
|
||||
|
||||
auto store = std::make_unique<MachineInstr>(store_op);
|
||||
store->addOperand(std::make_unique<RegOperand>(src_preg));
|
||||
store->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
|
||||
));
|
||||
new_instructions.push_back(std::move(store));
|
||||
}
|
||||
}
|
||||
}
|
||||
mbb->getInstructions() = std::move(new_instructions);
|
||||
}
|
||||
|
||||
// 3. 最后,将所有指令中的虚拟寄存器替换为物理寄存器
|
||||
for (auto& mbb : MFunc->getBlocks()) {
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
instr_ptr->replaceVRegWithPReg(0, PhysicalReg::ZERO); // 保底处理
|
||||
// 为已着色的vreg替换
|
||||
for(const auto& color_pair : color_map) {
|
||||
instr_ptr->replaceVRegWithPReg(color_pair.first, color_pair.second);
|
||||
}
|
||||
// 为溢出的vreg替换
|
||||
for (unsigned vreg : spilled_vregs) {
|
||||
auto [type, size] = getTypeAndSize(vreg);
|
||||
PhysicalReg spill_preg;
|
||||
if (type == Type::kFloat) spill_preg = FP_SPILL_REG;
|
||||
else if (type == Type::kPointer) spill_preg = PTR_SPILL_REG;
|
||||
else spill_preg = INT_SPILL_REG;
|
||||
instr_ptr->replaceVRegWithPReg(vreg, spill_preg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 辅助函数实现 ---
|
||||
|
||||
void RISCv64SimpleRegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||
auto opcode = instr->getOpcode();
|
||||
const auto& operands = instr->getOperands();
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
|
||||
auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned {
|
||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||
auto reg_op = static_cast<const RegOperand*>(op);
|
||||
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
|
||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
auto reg_op = static_cast<const MemOperand*>(op)->getBase();
|
||||
return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast<unsigned>(reg_op->getPReg()));
|
||||
}
|
||||
return (unsigned)-1;
|
||||
};
|
||||
|
||||
if (op_info.count(opcode)) {
|
||||
const auto& info = op_info.at(opcode);
|
||||
for (int idx : info.first) if (idx < operands.size()) {
|
||||
unsigned reg_id = get_any_reg_id(operands[idx].get());
|
||||
if (reg_id != (unsigned)-1) def.insert(reg_id);
|
||||
}
|
||||
for (int idx : info.second) if (idx < operands.size()) {
|
||||
unsigned reg_id = get_any_reg_id(operands[idx].get());
|
||||
if (reg_id != (unsigned)-1) use.insert(reg_id);
|
||||
}
|
||||
for (const auto& op : operands) {
|
||||
if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||
unsigned reg_id = get_any_reg_id(op.get());
|
||||
if (reg_id != (unsigned)-1) use.insert(reg_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (opcode == RVOpcodes::CALL) {
|
||||
if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) {
|
||||
def.insert(get_any_reg_id(operands[0].get()));
|
||||
}
|
||||
for (size_t i = 1; i < operands.size(); ++i) {
|
||||
if (operands[i]->getKind() == MachineOperand::KIND_REG) {
|
||||
use.insert(get_any_reg_id(operands[i].get()));
|
||||
}
|
||||
}
|
||||
for (auto preg : getCallerSavedIntRegs()) def.insert(offset + static_cast<unsigned>(preg));
|
||||
for (auto preg : getCallerSavedFpRegs()) def.insert(offset + static_cast<unsigned>(preg));
|
||||
def.insert(offset + static_cast<unsigned>(PhysicalReg::RA));
|
||||
}
|
||||
else if (opcode == RVOpcodes::RET) {
|
||||
use.insert(offset + static_cast<unsigned>(PhysicalReg::A0));
|
||||
use.insert(offset + static_cast<unsigned>(PhysicalReg::F10)); // fa0
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Type::Kind, unsigned> RISCv64SimpleRegAlloc::getTypeAndSize(unsigned vreg) {
|
||||
const auto& vreg_type_map = ISel->getVRegTypeMap();
|
||||
if (vreg_type_map.count(vreg)) {
|
||||
Type* type = vreg_type_map.at(vreg);
|
||||
if (type->isFloat()) return {Type::kFloat, 4};
|
||||
if (type->isPointer()) return {Type::kPointer, 8};
|
||||
}
|
||||
// 默认或未知类型按32位整数处理
|
||||
return {Type::kInt, 4};
|
||||
}
|
||||
|
||||
std::string RISCv64SimpleRegAlloc::regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const {
|
||||
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
|
||||
if (id >= offset) {
|
||||
PhysicalReg reg = static_cast<PhysicalReg>(id - offset);
|
||||
return printer.regToString(reg);
|
||||
} else {
|
||||
return "%vreg" + std::to_string(id);
|
||||
}
|
||||
}
|
||||
|
||||
void RISCv64SimpleRegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer) {
|
||||
os << " " << name << " (" << s.size() << "): { ";
|
||||
for (unsigned vreg : s) {
|
||||
os << regIdToString(vreg, printer) << " ";
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
// 辅助函数
|
||||
void setStream(std::ostream& os) { OS = &os; }
|
||||
// 辅助函数
|
||||
std::string regToString(PhysicalReg reg);
|
||||
std::string regToString(PhysicalReg reg) const;
|
||||
std::string formatInstr(const MachineInstr *instr);
|
||||
|
||||
private:
|
||||
|
||||
107
src/include/backend/RISCv64/RISCv64SimpleRegAlloc.h
Normal file
107
src/include/backend/RISCv64/RISCv64SimpleRegAlloc.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef RISCV64_SIMPLE_REGALLOC_H
|
||||
#define RISCV64_SIMPLE_REGALLOC_H
|
||||
|
||||
#include "RISCv64LLIR.h"
|
||||
#include "RISCv64ISel.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// 外部调试级别控制变量的声明
|
||||
extern int DEBUG;
|
||||
extern int DEEPDEBUG;
|
||||
|
||||
namespace sysy {
|
||||
|
||||
class RISCv64AsmPrinter; // 前向声明
|
||||
|
||||
/**
|
||||
* @class RISCv64SimpleRegAlloc
|
||||
* @brief 一个简单的一次性图着色寄存器分配器。
|
||||
* * 该分配器遵循一个线性的、非迭代的流程:
|
||||
* 1. 活跃性分析
|
||||
* 2. 构建冲突图
|
||||
* 3. 贪心图着色
|
||||
* 4. 重写函数代码,插入溢出指令
|
||||
* * 它与新版后端流水线兼容,但保留了旧版分配器的核心逻辑。
|
||||
* 溢出处理使用硬编码的物理寄存器。
|
||||
*/
|
||||
class RISCv64SimpleRegAlloc {
|
||||
public:
|
||||
RISCv64SimpleRegAlloc(MachineFunction* mfunc);
|
||||
|
||||
/**
|
||||
* @brief 运行寄存器分配的主函数。
|
||||
*/
|
||||
void run();
|
||||
|
||||
private:
|
||||
using LiveSet = std::set<unsigned>;
|
||||
using InterferenceGraph = std::map<unsigned, LiveSet>;
|
||||
|
||||
// --- 分配流程的各个阶段 ---
|
||||
void unifyArgumentVRegs();
|
||||
void handleCallingConvention();
|
||||
void analyzeLiveness();
|
||||
void buildInterferenceGraph();
|
||||
void colorGraph();
|
||||
void rewriteFunction();
|
||||
|
||||
// --- 辅助函数 ---
|
||||
|
||||
/**
|
||||
* @brief 获取指令的Use/Def集合,包含物理寄存器,用于活跃性分析。
|
||||
* @param instr 机器指令。
|
||||
* @param use 输出参数,存储使用的寄存器ID。
|
||||
* @param def 输出参数,存储定义的寄存器ID。
|
||||
*/
|
||||
void getInstrUseDef_Liveness(const MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
/**
|
||||
* @brief 根据vreg的类型信息返回其大小和类型种类。
|
||||
* @param vreg 虚拟寄存器号。
|
||||
* @return 一个包含类型信息和大小(字节)的pair。
|
||||
*/
|
||||
std::pair<Type::Kind, unsigned> getTypeAndSize(unsigned vreg);
|
||||
|
||||
/**
|
||||
* @brief 打印调试用的活跃集信息。
|
||||
*/
|
||||
void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os, const RISCv64AsmPrinter& printer);
|
||||
|
||||
/**
|
||||
* @brief 将寄存器ID(虚拟或物理)转换为可读字符串。
|
||||
*/
|
||||
std::string regIdToString(unsigned id, const RISCv64AsmPrinter& printer) const;
|
||||
|
||||
// --- 成员变量 ---
|
||||
MachineFunction* MFunc;
|
||||
RISCv64ISel* ISel;
|
||||
|
||||
// 可分配的寄存器池
|
||||
std::vector<PhysicalReg> allocable_int_regs;
|
||||
std::vector<PhysicalReg> allocable_fp_regs;
|
||||
|
||||
// 硬编码的溢出专用物理寄存器
|
||||
const PhysicalReg INT_SPILL_REG = PhysicalReg::T2; // 用于 32-bit int
|
||||
const PhysicalReg PTR_SPILL_REG = PhysicalReg::T3; // 用于 64-bit pointer
|
||||
const PhysicalReg FP_SPILL_REG = PhysicalReg::F4; // 用于 32-bit float (ft4)
|
||||
|
||||
// 活跃性分析结果
|
||||
std::map<const MachineInstr*, LiveSet> live_in_map;
|
||||
std::map<const MachineInstr*, LiveSet> live_out_map;
|
||||
|
||||
// 冲突图
|
||||
InterferenceGraph interference_graph;
|
||||
|
||||
// 着色结果和溢出列表
|
||||
std::map<unsigned, PhysicalReg> color_map;
|
||||
std::set<unsigned> spilled_vregs;
|
||||
|
||||
// 映射:将物理寄存器ID映射到它们在冲突图中的特殊虚拟ID
|
||||
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map;
|
||||
};
|
||||
|
||||
} // namespace sysy
|
||||
|
||||
#endif // RISCV64_SIMPLE_REGALLOC_H
|
||||
Reference in New Issue
Block a user