Merge branch 'backend-float' into backend

This commit is contained in:
Lixuanwang
2025-07-30 18:26:06 +08:00
12 changed files with 1099 additions and 297 deletions

View File

@@ -1,6 +1,8 @@
#include "CalleeSavedHandler.h"
#include <set>
#include <vector> //
#include <algorithm>
#include <iterator> //
namespace sysy {
@@ -14,23 +16,34 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
// 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。
StackFrameInfo& frame_info = mfunc->getFrameInfo();
std::set<PhysicalReg> used_callee_saved;
// [修改] 分别记录被使用的整数和浮点被调用者保存寄存器
std::set<PhysicalReg> used_int_callee_saved;
std::set<PhysicalReg> used_fp_callee_saved;
// 1. 扫描所有指令找出被使用的s寄存器 (s1-s11)
// 1. 扫描所有指令找出被使用的s寄存器 (s1-s11) 和 fs寄存器 (fs0-fs11)
for (auto& mbb : mfunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
for (auto& op : instr->getOperands()) {
auto check_and_insert_reg = [&](RegOperand* reg_op) {
if (!reg_op->isVirtual()) {
PhysicalReg preg = reg_op->getPReg();
// [修改] 区分整数和浮点被调用者保存寄存器
// s0 由序言/尾声处理器专门处理,这里不计入
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
used_callee_saved.insert(preg);
used_int_callee_saved.insert(preg);
}
// fs0-fs11 在我们的枚举中对应 f8,f9,f18-f27
else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) {
used_fp_callee_saved.insert(preg);
}
}
};
if (op->getKind() == MachineOperand::KIND_REG) {
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
} else if (op->getKind() == MachineOperand::KIND_MEM) {
@@ -40,83 +53,109 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
}
}
if (used_callee_saved.empty()) {
// 如果没有使用任何需要处理的 callee-saved 寄存器,则直接返回
if (used_int_callee_saved.empty() && used_fp_callee_saved.empty()) {
frame_info.callee_saved_size = 0; // 确保大小被初始化
return; // 无需操作
return;
}
// 2. 计算为 callee-saved 寄存器分配的栈空间
// 这里的关键是,偏移的基准点要在局部变量和溢出槽之下。
int callee_saved_size = used_callee_saved.size() * 8;
frame_info.callee_saved_size = callee_saved_size; // 将大小存入 FrameInfo
// 2. 计算为 callee-saved 寄存器分配的栈空间大小
// 每个寄存器在RV64中都占用8字节
int callee_saved_size = (used_int_callee_saved.size() + used_fp_callee_saved.size()) * 8;
frame_info.callee_saved_size = callee_saved_size;
// 3. 计算无冲突的栈偏移
// 栈向下增长,所以偏移是负数。
// ra/s0 占用 -8 和 -16。局部变量和溢出区在它们之下。callee-saved 区在更下方。
// 我们使用相对于 s0 的偏移。s0 将指向栈顶 (sp + total_size)。
int base_offset = -16 - frame_info.locals_size - frame_info.spill_size;
// 为了栈帧布局确定性,对寄存器进行排序
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
std::sort(sorted_regs.begin(), sorted_regs.end());
// 4. 在函数序言插入保存指令
// 3. 在函数序言中插入保存指令
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
auto& entry_instrs = entry_block->getInstructions();
auto prologue_end = entry_instrs.begin();
// 插入点通常在函数入口标签之后
auto insert_pos = entry_instrs.begin();
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
insert_pos = std::next(insert_pos);
}
// 找到序言结束的位置通常是addi s0, sp, size之后但为了让优化器看到我们插在更前面
// 合理的位置是在 IR 指令开始之前,即在任何非序言指令(如第一个标签)之前。
// 为简单起见,我们直接插入到块的开头,后续重排 pass 会处理。
// (更优的实现会寻找一个特定的插入点)
// 为了布局确定性,对寄存器进行排序并按序保存
std::vector<PhysicalReg> sorted_int_regs(used_int_callee_saved.begin(), used_int_callee_saved.end());
std::vector<PhysicalReg> sorted_fp_regs(used_fp_callee_saved.begin(), used_fp_callee_saved.end());
std::sort(sorted_int_regs.begin(), sorted_int_regs.end());
std::sort(sorted_fp_regs.begin(), sorted_fp_regs.end());
std::vector<std::unique_ptr<MachineInstr>> save_instrs;
int current_offset = -16; // ra和s0已占用-8和-16从-24开始分配
int current_offset = base_offset;
for (PhysicalReg reg : sorted_regs) {
// 准备整数保存指令 (sd)
for (PhysicalReg reg : sorted_int_regs) {
current_offset -= 8;
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
sd->addOperand(std::make_unique<RegOperand>(reg));
sd->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
std::make_unique<ImmOperand>(current_offset)
));
// 从头部插入,但要放在函数标签之后
entry_instrs.insert(entry_instrs.begin() + 1, std::move(sd));
save_instrs.push_back(std::move(sd));
}
// 准备浮点保存指令 (fsd)
for (PhysicalReg reg : sorted_fp_regs) {
current_offset -= 8;
auto fsd = std::make_unique<MachineInstr>(RVOpcodes::FSD); // 使用浮点保存指令
fsd->addOperand(std::make_unique<RegOperand>(reg));
fsd->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset)
));
save_instrs.push_back(std::move(fsd));
}
// 5. 在函数结尾ret之前插入恢复指令使用反向遍历来避免迭代器失效
// 一次性插入所有保存指令
if (!save_instrs.empty()) {
entry_instrs.insert(insert_pos,
std::make_move_iterator(save_instrs.begin()),
std::make_move_iterator(save_instrs.end()));
}
// 4. 在函数结尾ret之前插入恢复指令
for (auto& mbb : mfunc->getBlocks()) {
// 使用手动控制的反向循环
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
// 1. 创建一个临时vector来存储所有需要插入的恢复指令
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
current_offset = -16; // 重置偏移量用于恢复
int current_offset_load = base_offset;
// 以相同的顺序(例如 s1, s2, ...)创建恢复指令
for (PhysicalReg reg : sorted_regs) {
// 准备恢复整数寄存器 (ld) - 以与保存时相同的顺序
for (PhysicalReg reg : sorted_int_regs) {
current_offset -= 8;
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
ld->addOperand(std::make_unique<RegOperand>(reg));
ld->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset_load)
std::make_unique<ImmOperand>(current_offset)
));
restore_instrs.push_back(std::move(ld));
current_offset_load -= 8;
}
// 2. 使用 make_move_iterator 一次性将所有恢复指令插入到 RET 指令之前
// 这可以高效地转移指令的所有权,并且只让迭代器失效一次。
// 准备恢复浮点寄存器 (fld)
for (PhysicalReg reg : sorted_fp_regs) {
current_offset -= 8;
auto fld = std::make_unique<MachineInstr>(RVOpcodes::FLD); // 使用浮点加载指令
fld->addOperand(std::make_unique<RegOperand>(reg));
fld->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(current_offset)
));
restore_instrs.push_back(std::move(fld));
}
// 一次性插入所有恢复指令
if (!restore_instrs.empty()) {
mbb->getInstructions().insert(it,
std::make_move_iterator(restore_instrs.begin()),
std::make_move_iterator(restore_instrs.end())
);
mbb->getInstructions().insert(it,
std::make_move_iterator(restore_instrs.begin()),
std::make_move_iterator(restore_instrs.end()));
}
// 找到了RET并处理完毕后就可以跳出内层循环继续寻找下一个基本块
break;
// 处理完一个基本块的RET后迭代器已失效需跳出当前块的循环
goto next_block_label;
}
}
next_block_label:;
}
}

View File

@@ -52,6 +52,8 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
case RVOpcodes::ADDI:
case RVOpcodes::ADDIW: {
auto& operands = instr_ptr->getOperands();
// 确保操作数足够多,以防万一
if (operands.size() < 3) break;
auto imm_op = static_cast<ImmOperand*>(operands.back().get());
if (!isLegalImmediate(imm_op->getValue())) {
@@ -73,7 +75,7 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
add->addOperand(std::move(rd_op));
add->addOperand(std::move(rs1_op));
add->addOperand(std::make_unique<RegOperand>(TEMP_REG));
if (DEEPDEBUG) {
std::cerr << " New sequence:\n ";
temp_printer.printInstruction(li.get(), true);
@@ -92,7 +94,8 @@ void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) {
// 处理所有内存加载/存储指令
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD: {
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW: case RVOpcodes::FSW: {
auto& operands = instr_ptr->getOperands();
auto mem_op = static_cast<MemOperand*>(operands.back().get());
auto offset_op = mem_op->getOffset();

View File

@@ -1,4 +1,6 @@
#include "PrologueEpilogueInsertion.h"
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果
namespace sysy {
@@ -6,7 +8,13 @@ char PrologueEpilogueInsertionPass::ID = 0;
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
StackFrameInfo& frame_info = mfunc->getFrameInfo();
Function* F = mfunc->getFunc();
RISCv64ISel* isel = mfunc->getISel();
// [关键] 获取寄存器分配的结果 (vreg -> preg 的映射)
// RegAlloc Pass 必须已经运行过
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
// 完全遵循 AsmPrinter 中的计算逻辑
int total_stack_size = frame_info.locals_size +
frame_info.spill_size +
@@ -24,7 +32,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
// 严格按照 AsmPrinter 的打印顺序来创建和组织指令
// 1. addi sp, sp, -aligned_stack_size
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
@@ -57,10 +64,63 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
prologue_instrs.push_back(std::move(set_fp));
// 确定插入点(在函数名标签之后)
// --- [正确逻辑] 在s0设置完毕后使用物理寄存器加载栈参数 ---
if (F && isel) {
// 定义暂存寄存器
const PhysicalReg INT_SCRATCH_REG = PhysicalReg::T5;
const PhysicalReg FP_SCRATCH_REG = PhysicalReg::F7;
int arg_idx = 0;
for (Argument* arg : F->getArguments()) {
if (arg_idx >= 8) {
unsigned vreg = isel->getVReg(arg);
// 确认RegAlloc已经为这个vreg计算了偏移量并且分配了物理寄存器
if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) {
int offset = frame_info.alloca_offsets.at(vreg);
PhysicalReg dest_preg = vreg_to_preg_map.at(vreg);
Type* arg_type = arg->getType();
// 根据类型执行不同的加载序列
if (arg_type->isFloat()) {
// 1. flw ft7, offset(s0)
auto load_arg = std::make_unique<MachineInstr>(RVOpcodes::FLW);
load_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
load_arg->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
prologue_instrs.push_back(std::move(load_arg));
// 2. fmv.s dest_preg, ft7
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
move_arg->addOperand(std::make_unique<RegOperand>(FP_SCRATCH_REG));
prologue_instrs.push_back(std::move(move_arg));
} else {
// 确定是加载32位(lw)还是64位(ld)
RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
// 1. lw/ld t5, offset(s0)
auto load_arg = std::make_unique<MachineInstr>(load_op);
load_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
load_arg->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
prologue_instrs.push_back(std::move(load_arg));
// 2. mv dest_preg, t5
auto move_arg = std::make_unique<MachineInstr>(RVOpcodes::MV);
move_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
move_arg->addOperand(std::make_unique<RegOperand>(INT_SCRATCH_REG));
prologue_instrs.push_back(std::move(move_arg));
}
}
}
arg_idx++;
}
}
// 确定插入点
auto insert_pos = entry_instrs.begin();
// [重要] 这里我们不再需要跳过LABEL因为AsmPrinter将不再打印函数名标签
// 第一个基本块的标签就是函数入口
// 一次性将所有序言指令插入
if (!prologue_instrs.empty()) {
@@ -69,14 +129,13 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::make_move_iterator(prologue_instrs.end()));
}
// --- 2. 插入尾声 ---
// --- 2. 插入尾声 (此部分逻辑保持不变) ---
for (auto& mbb : mfunc->getBlocks()) {
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
if ((*it)->getOpcode() == RVOpcodes::RET) {
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
// 同样严格按照 AsmPrinter 的打印顺序
// 1. ld ra, (aligned_stack_size - 8)(sp)
// 1. ld ra
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
restore_ra->addOperand(std::make_unique<MemOperand>(
@@ -85,7 +144,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
));
epilogue_instrs.push_back(std::move(restore_ra));
// 2. ld s0, (aligned_stack_size - 16)(sp)
// 2. ld s0
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
restore_fp->addOperand(std::make_unique<MemOperand>(
@@ -106,7 +165,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::make_move_iterator(epilogue_instrs.begin()),
std::make_move_iterator(epilogue_instrs.end()));
}
// 处理完一个基本块中的RET后迭代器已失效需跳出
goto next_block;
}
}

View File

@@ -7,9 +7,15 @@ namespace sysy {
// 检查是否为内存加载/存储指令,以处理特殊的打印格式
bool isMemoryOp(RVOpcodes opcode) {
switch (opcode) {
// --- 整数加载/存储 (原有逻辑) ---
case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD:
case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU:
case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD:
case RVOpcodes::FLW:
case RVOpcodes::FSW:
// 如果未来支持双精度也在这里添加FLD/FSD
// case RVOpcodes::FLD:
// case RVOpcodes::FSD:
return true;
default:
return false;
@@ -73,7 +79,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::LHU: *OS << "lhu "; break; case RVOpcodes::LBU: *OS << "lbu "; break;
case RVOpcodes::SW: *OS << "sw "; break; case RVOpcodes::SH: *OS << "sh "; break;
case RVOpcodes::SB: *OS << "sb "; break; case RVOpcodes::LD: *OS << "ld "; break;
case RVOpcodes::SD: *OS << "sd "; break;
case RVOpcodes::SD: *OS << "sd "; break; case RVOpcodes::FLW: *OS << "flw "; break;
case RVOpcodes::FSW: *OS << "fsw "; break; case RVOpcodes::FLD: *OS << "fld "; break;
case RVOpcodes::FSD: *OS << "fsd "; break;
case RVOpcodes::J: *OS << "j "; break; case RVOpcodes::JAL: *OS << "jal "; break;
case RVOpcodes::JALR: *OS << "jalr "; break; case RVOpcodes::RET: *OS << "ret"; break;
case RVOpcodes::BEQ: *OS << "beq "; break; case RVOpcodes::BNE: *OS << "bne "; break;
@@ -82,7 +90,20 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
case RVOpcodes::LI: *OS << "li "; break; case RVOpcodes::LA: *OS << "la "; break;
case RVOpcodes::MV: *OS << "mv "; break; case RVOpcodes::NEG: *OS << "neg "; break;
case RVOpcodes::NEGW: *OS << "negw "; break; case RVOpcodes::SEQZ: *OS << "seqz "; break;
case RVOpcodes::SNEZ: *OS << "snez "; break;
case RVOpcodes::SNEZ: *OS << "snez "; break;
case RVOpcodes::FADD_S: *OS << "fadd.s "; break;
case RVOpcodes::FSUB_S: *OS << "fsub.s "; break;
case RVOpcodes::FMUL_S: *OS << "fmul.s "; break;
case RVOpcodes::FDIV_S: *OS << "fdiv.s "; break;
case RVOpcodes::FNEG_S: *OS << "fneg.s "; break;
case RVOpcodes::FEQ_S: *OS << "feq.s "; break;
case RVOpcodes::FLT_S: *OS << "flt.s "; break;
case RVOpcodes::FLE_S: *OS << "fle.s "; break;
case RVOpcodes::FCVT_S_W: *OS << "fcvt.s.w "; break;
case RVOpcodes::FCVT_W_S: *OS << "fcvt.w.s "; break;
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
*OS << "call ";
// 遍历所有操作数,只寻找并打印函数名标签
@@ -117,6 +138,12 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
// It should have been eliminated by RegAlloc
if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter");
*OS << "frame_addr "; break;
case RVOpcodes::FRAME_LOAD_F:
if (!debug) throw std::runtime_error("FRAME_LOAD_F not eliminated before AsmPrinter");
*OS << "frame_load_f "; break;
case RVOpcodes::FRAME_STORE_F:
if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter");
*OS << "frame_store_f "; break;
default:
throw std::runtime_error("Unknown opcode in AsmPrinter");
}

View File

@@ -16,7 +16,7 @@ std::string RISCv64CodeGen::code_gen() {
std::string RISCv64CodeGen::module_gen() {
std::stringstream ss;
// --- [新逻辑] 步骤1将全局变量分为.data和.bss两组 ---
// --- 步骤1将全局变量分为.data和.bss两组 ---
std::vector<GlobalValue*> data_globals;
std::vector<GlobalValue*> bss_globals;
@@ -42,7 +42,7 @@ std::string RISCv64CodeGen::module_gen() {
}
}
// --- [新逻辑] 步骤2生成 .bss 段的代码 ---
// --- 步骤2生成 .bss 段的代码 ---
if (!bss_globals.empty()) {
ss << ".bss\n"; // 切换到 .bss 段
for (GlobalValue* global : bss_globals) {
@@ -61,14 +61,13 @@ std::string RISCv64CodeGen::module_gen() {
}
}
// --- [旧逻辑保留] 步骤3生成 .data 段的代码 ---
// --- 步骤3生成 .data 段的代码 ---
if (!data_globals.empty()) {
ss << ".data\n"; // 切换到 .data 段
for (GlobalValue* global : data_globals) {
ss << ".globl " << global->getName() << "\n";
ss << global->getName() << ":\n";
const auto& init_values = global->getInitValues();
// 使用您原有的逻辑来处理显式初始化的值
for (size_t i = 0; i < init_values.getValues().size(); ++i) {
auto val = init_values.getValues()[i];
auto count = init_values.getNumbers()[i];
@@ -87,7 +86,7 @@ std::string RISCv64CodeGen::module_gen() {
}
}
// --- 处理函数 (.text段) 的逻辑保持不变 ---
// --- 处理函数 (.text段) ---
if (!module->getFunctions().empty()) {
ss << ".text\n";
for (const auto& func_pair : module->getFunctions()) {
@@ -99,7 +98,6 @@ std::string RISCv64CodeGen::module_gen() {
return ss.str();
}
// function_gen 现在是包含具体优化名称的、完整的处理流水线
std::string RISCv64CodeGen::function_gen(Function* func) {
// === 完整的后端处理流水线 ===

View File

@@ -10,7 +10,23 @@ namespace sysy {
// DAG节点定义 (内部实现)
struct RISCv64ISel::DAGNode {
enum NodeKind {ARGUMENT, CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET, GET_ELEMENT_PTR};
enum NodeKind {
ARGUMENT,
CONSTANT, // 整数或地址常量
LOAD,
STORE,
BINARY, // 整数二元运算
CALL,
RETURN,
BRANCH,
ALLOCA_ADDR,
UNARY, // 整数一元运算
MEMSET,
GET_ELEMENT_PTR,
FP_CONSTANT, // 浮点常量
FBINARY, // 浮点二元运算 (如 FADD, FSUB, FCMP)
FUNARY, // 浮点一元运算 (如 FCVT, FNEG)
};
NodeKind kind;
Value* value = nullptr;
std::vector<DAGNode*> operands;
@@ -29,11 +45,20 @@ unsigned RISCv64ISel::getVReg(Value* val) {
if (vreg_counter == 0) {
vreg_counter = 1; // vreg 0 保留
}
vreg_map[val] = vreg_counter++;
unsigned new_vreg = vreg_counter++;
vreg_map[val] = new_vreg;
vreg_to_value_map[new_vreg] = val;
vreg_type_map[new_vreg] = val->getType();
}
return vreg_map.at(val);
}
unsigned RISCv64ISel::getNewVReg(Type* type) {
unsigned new_vreg = vreg_counter++;
vreg_type_map[new_vreg] = type; // 记录这个新vreg的类型
return new_vreg;
}
// 主入口函数
std::unique_ptr<MachineFunction> RISCv64ISel::runOnFunction(Function* func) {
F = func;
@@ -161,18 +186,52 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
break;
case DAGNode::FP_CONSTANT: {
// RISC-V没有直接加载浮点立即数的指令
// 标准做法是1. 将浮点数的32位二进制表示加载到一个整数寄存器
// 2. 使用 fmv.w.x 指令将位模式从整数寄存器移动到浮点寄存器
auto const_val = dynamic_cast<ConstantValue*>(node->value);
auto float_vreg = getVReg(const_val);
auto temp_int_vreg = getNewVReg(Type::getIntType()); // 临时整数虚拟寄存器
float f_val = const_val->getFloat();
// 使用 reinterpret_cast 获取浮点数的32位二进制表示
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
// 1. li temp_int_vreg, float_bits
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
li->addOperand(std::make_unique<ImmOperand>(float_bits));
CurMBB->addInstruction(std::move(li));
// 2. fmv.w.x float_vreg, temp_int_vreg
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
CurMBB->addInstruction(std::move(fmv));
break;
}
case DAGNode::LOAD: {
auto dest_vreg = getVReg(node->value);
Value* ptr_val = node->operands[0]->value;
// --- 修改点 ---
// 1. 获取加载结果的类型 (即这个LOAD指令自身的类型)
Type* loaded_type = node->value->getType();
// 2. 根据类型选择正确的伪指令或真实指令操作码
RVOpcodes frame_opcode = loaded_type->isPointer() ? RVOpcodes::FRAME_LOAD_D : RVOpcodes::FRAME_LOAD_W;
RVOpcodes real_opcode = loaded_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
RVOpcodes frame_opcode;
RVOpcodes real_opcode;
if (loaded_type->isPointer()) {
frame_opcode = RVOpcodes::FRAME_LOAD_D;
real_opcode = RVOpcodes::LD;
} else if (loaded_type->isFloat()) {
frame_opcode = RVOpcodes::FRAME_LOAD_F;
real_opcode = RVOpcodes::FLW;
} else { // 默认为整数
frame_opcode = RVOpcodes::FRAME_LOAD_W;
real_opcode = RVOpcodes::LW;
}
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
// 3. 创建使用新的、区分宽度的伪指令
@@ -183,7 +242,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
// 对于全局变量,先用 la 加载其地址
auto addr_vreg = getNewVReg();
auto addr_vreg = getNewVReg(Type::getPointerType(global->getType()));
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
@@ -220,20 +279,51 @@ void RISCv64ISel::selectNode(DAGNode* node) {
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
CurMBB->addInstruction(std::move(li));
// 区分整数常量和浮点常量
if (val_const->isInt()) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
CurMBB->addInstruction(std::move(li));
} else if (val_const->isFloat()) {
// 先将浮点数的位模式加载到整数vreg再用fmv.w.x移到浮点vreg
auto temp_int_vreg = getNewVReg(Type::getIntType());
auto float_vreg = getVReg(val_const);
float f_val = val_const->getFloat();
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
// 1. li temp_int_vreg, float_bits
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
li->addOperand(std::make_unique<ImmOperand>(float_bits));
CurMBB->addInstruction(std::move(li));
// 2. fmv.w.x float_vreg, temp_int_vreg
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
CurMBB->addInstruction(std::move(fmv));
}
}
auto val_vreg = getVReg(val_to_store);
// --- 修改点 ---
// 1. 获取被存储的值的类型
Type* stored_type = val_to_store->getType();
// 2. 根据类型选择正确的伪指令或真实指令操作码
RVOpcodes frame_opcode = stored_type->isPointer() ? RVOpcodes::FRAME_STORE_D : RVOpcodes::FRAME_STORE_W;
RVOpcodes real_opcode = stored_type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
RVOpcodes frame_opcode;
RVOpcodes real_opcode;
if (stored_type->isPointer()) {
frame_opcode = RVOpcodes::FRAME_STORE_D;
real_opcode = RVOpcodes::SD;
} else if (stored_type->isFloat()) {
frame_opcode = RVOpcodes::FRAME_STORE_F;
real_opcode = RVOpcodes::FSW;
} else { // 默认为整数
frame_opcode = RVOpcodes::FRAME_STORE_W;
real_opcode = RVOpcodes::SW;
}
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
// 3. 创建使用新的、区分宽度的伪指令
@@ -244,7 +334,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
} else if (auto global = dynamic_cast<GlobalValue*>(ptr_val)) {
// 向全局变量存储
auto addr_vreg = getNewVReg();
auto addr_vreg = getNewVReg(Type::getIntType());
auto la = std::make_unique<MachineInstr>(RVOpcodes::LA);
la->addOperand(std::make_unique<RegOperand>(addr_vreg));
la->addOperand(std::make_unique<LabelOperand>(global->getName()));
@@ -304,7 +394,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
}
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
auto base_addr_vreg = getNewVReg(); // 创建一个新的临时vreg来存放基地址
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
// 情况一:基地址是局部栈变量
if (auto alloca_base = dynamic_cast<AllocaInst*>(base)) {
@@ -497,6 +587,109 @@ void RISCv64ISel::selectNode(DAGNode* node) {
break;
}
case DAGNode::FBINARY: {
auto bin = dynamic_cast<BinaryInst*>(node->value);
auto dest_vreg = getVReg(bin);
auto lhs_vreg = getVReg(bin->getLhs());
auto rhs_vreg = getVReg(bin->getRhs());
switch (bin->getKind()) {
case Instruction::kFAdd: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FADD_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFSub: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FSUB_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFMul: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMUL_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFDiv: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FDIV_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
// --- 浮点比较指令 ---
// 注意:比较结果(0或1)写入的是一个通用整数寄存器(dest_vreg)
case Instruction::kFCmpEQ: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFCmpLT: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFCmpLE: {
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
// --- 通过交换操作数或组合指令实现其余比较 ---
case Instruction::kFCmpGT: { // a > b 等价于 b < a
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg)); // 操作数交换
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFCmpGE: { // a >= b 等价于 b <= a
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg)); // 操作数交换
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFCmpNE: { // a != b 等价于 !(a == b)
// 1. 先用 feq.s 比较,结果存入 dest_vreg
auto feq = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
feq->addOperand(std::make_unique<RegOperand>(dest_vreg));
feq->addOperand(std::make_unique<RegOperand>(lhs_vreg));
feq->addOperand(std::make_unique<RegOperand>(rhs_vreg));
CurMBB->addInstruction(std::move(feq));
// 2. 再用 seqz 对结果取反 (如果相等(1)则变0如果不等(0)则变1)
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
CurMBB->addInstruction(std::move(seqz));
break;
}
default:
throw std::runtime_error("Unsupported float binary instruction in ISel");
}
break;
}
case DAGNode::UNARY: {
auto unary = dynamic_cast<UnaryInst*>(node->value);
auto dest_vreg = getVReg(unary);
@@ -524,109 +717,245 @@ void RISCv64ISel::selectNode(DAGNode* node) {
break;
}
case DAGNode::FUNARY: {
auto unary = dynamic_cast<UnaryInst*>(node->value);
auto dest_vreg = getVReg(unary);
auto src_vreg = getVReg(unary->getOperand());
switch (unary->getKind()) {
case Instruction::kItoF: { // 整数 to 浮点
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFtoI: { // 浮点 to 整数
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kFNeg: { // 浮点取负
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FNEG_S);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(instr));
break;
}
// --- 处理位传送指令 ---
case Instruction::kBitItoF: { // 整数位模式 -> 浮点寄存器
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
CurMBB->addInstruction(std::move(instr));
break;
}
case Instruction::kBitFtoI: { // 浮点位模式 -> 整数寄存器
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_X_W);
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
CurMBB->addInstruction(std::move(instr));
break;
}
default:
throw std::runtime_error("Unsupported float unary instruction in ISel");
}
break;
}
case DAGNode::CALL: {
auto call = dynamic_cast<CallInst*>(node->value);
// 处理函数参数放入a0-a7物理寄存器
size_t num_operands = node->operands.size();
size_t reg_arg_count = std::min(num_operands, (size_t)8);
for (size_t i = 0; i < reg_arg_count; ++i) {
DAGNode* arg_node = node->operands[i];
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + i);
if (arg_node->kind == DAGNode::CONSTANT) {
if (auto const_val = dynamic_cast<ConstantValue*>(arg_node->value)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(arg_preg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
// --- 步骤 1: 分配寄存器参数和栈参数 ---
// 根据RISC-V调用约定前8个整数/指针参数通过a0-a7传递
// 前8个浮点参数通过fa0-fa7传递 (物理寄存器 f10-f17)。其余参数通过栈传递。
int int_reg_idx = 0; // a0-a7 的索引
int fp_reg_idx = 0; // fa0-fa7 的索引
// 用于存储需要通过栈传递的参数
std::vector<DAGNode*> stack_args;
for (size_t i = 0; i < num_operands; ++i) {
DAGNode* arg_node = node->operands[i];
Value* arg_val = arg_node->value;
Type* arg_type = arg_val->getType();
// 判断参数是浮点类型还是整型/指针类型
if (arg_type->isFloat()) {
if (fp_reg_idx < 8) {
// --- 处理浮点寄存器参数 (fa0-fa7, 对应物理寄存器 F10-F17) ---
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + fp_reg_idx);
fp_reg_idx++;
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
// 如果是浮点常量,需要先物化
// 1. 获取其32位二进制表示
float f_val = const_val->getFloat();
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
// 2. 将位模式加载到一个临时整数寄存器 (使用t0)
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
li->addOperand(std::make_unique<ImmOperand>(float_bits));
CurMBB->addInstruction(std::move(li));
// 3. 使用fmv.w.x将位模式从整数寄存器移动到目标浮点参数寄存器
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
fmv_wx->addOperand(std::make_unique<RegOperand>(arg_preg));
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
CurMBB->addInstruction(std::move(fmv_wx));
} else {
// 如果已经是虚拟寄存器,直接用 fmv.s 移动
auto src_vreg = getVReg(arg_val);
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
fmv_s->addOperand(std::make_unique<RegOperand>(arg_preg));
fmv_s->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(fmv_s));
}
} else {
// 浮点寄存器已用完,放到栈上传递
stack_args.push_back(arg_node);
}
} else { // 整数或指针参数
if (int_reg_idx < 8) {
// --- 处理整数/指针寄存器参数 (a0-a7) ---
auto arg_preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_reg_idx);
int_reg_idx++;
if (arg_node->kind == DAGNode::CONSTANT) {
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(arg_preg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
}
} else {
auto src_vreg = getVReg(arg_val);
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(mv));
}
} else {
// 整数寄存器已用完,放到栈上传递
stack_args.push_back(arg_node);
}
} else {
auto src_vreg = getVReg(arg_node->value);
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(arg_preg));
mv->addOperand(std::make_unique<RegOperand>(src_vreg));
CurMBB->addInstruction(std::move(mv));
}
}
if (num_operands > 8) {
size_t stack_arg_count = num_operands - 8;
int stack_space = stack_arg_count * 8; // RV64中每个参数槽位8字节
// 2a. 在栈上分配空间
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
CurMBB->addInstruction(std::move(alloc_instr));
// --- 步骤 2: 处理所有栈参数 ---
int stack_space = 0;
if (!stack_args.empty()) {
// 计算栈参数所需的总空间RV64中每个槽位为8字节
stack_space = stack_args.size() * 8;
// 根据ABI为call分配的栈空间需要16字节对齐
if (stack_space % 16 != 0) {
stack_space += 16 - (stack_space % 16);
}
// 在栈上分配空间
if (stack_space > 0) {
auto alloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
alloc_instr->addOperand(std::make_unique<ImmOperand>(-stack_space));
CurMBB->addInstruction(std::move(alloc_instr));
}
// 将每个参数存储到栈上对应的位置
for (size_t i = 0; i < stack_args.size(); ++i) {
DAGNode* arg_node = stack_args[i];
Value* arg_val = arg_node->value;
Type* arg_type = arg_val->getType();
int offset = i * 8;
// 2b. 存储每个栈参数
for (size_t i = 8; i < num_operands; ++i) {
DAGNode* arg_node = node->operands[i];
unsigned src_vreg;
// 准备源寄存器
if (arg_node->kind == DAGNode::CONSTANT) {
// 如果是常量,先加载到临时寄存器
src_vreg = getNewVReg();
auto const_val = dynamic_cast<ConstantValue*>(arg_node->value);
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(src_vreg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
// 如果是常量先加载到临时vreg
if (auto const_val = dynamic_cast<ConstantValue*>(arg_val)) {
src_vreg = getNewVReg(arg_type);
if(arg_type->isFloat()) {
auto temp_int_vreg = getNewVReg(Type::getIntType());
float f_val = const_val->getFloat();
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
li->addOperand(std::make_unique<ImmOperand>(float_bits));
CurMBB->addInstruction(std::move(li));
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
fmv_wx->addOperand(std::make_unique<RegOperand>(src_vreg));
fmv_wx->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
CurMBB->addInstruction(std::move(fmv_wx));
} else {
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(src_vreg));
li->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li));
}
} else {
src_vreg = getVReg(arg_node->value);
src_vreg = getVReg(arg_val);
}
// 计算在栈上的偏移量
int offset = (i - 8) * 8;
// 生成 sd 指令
auto sd_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
sd_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
sd_instr->addOperand(std::make_unique<MemOperand>(
// 根据类型选择 fsw (浮点) 或 sd (整型/指针) 存储指令
std::unique_ptr<MachineInstr> store_instr;
if (arg_type->isFloat()) {
store_instr = std::make_unique<MachineInstr>(RVOpcodes::FSW);
} else {
store_instr = std::make_unique<MachineInstr>(RVOpcodes::SD);
}
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
store_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::SP),
std::make_unique<ImmOperand>(offset)
));
CurMBB->addInstruction(std::move(sd_instr));
CurMBB->addInstruction(std::move(store_instr));
}
}
// --- 步骤 3: 生成CALL指令 ---
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
if (!call->getType()->isVoid()) {
unsigned dest_vreg = getVReg(call);
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
}
// 将函数名标签作为后续操作数
call_instr->addOperand(std::make_unique<LabelOperand>(call->getCallee()->getName()));
// 将所有参数的虚拟寄存器也作为后续操作数供getInstrUseDef分析
for (size_t i = 0; i < num_operands; ++i) {
if (node->operands[i]->kind != DAGNode::CONSTANT) { // 常量参数已直接加载无需作为use
if (node->operands[i]->kind != DAGNode::CONSTANT && node->operands[i]->kind != DAGNode::FP_CONSTANT) {
call_instr->addOperand(std::make_unique<RegOperand>(getVReg(node->operands[i]->value)));
}
}
CurMBB->addInstruction(std::move(call_instr));
if (num_operands > 8) {
size_t stack_arg_count = num_operands - 8;
int stack_space = stack_arg_count * 8;
// --- 步骤 4: 处理返回值 ---
if (!call->getType()->isVoid()) {
unsigned dest_vreg = getVReg(call);
if (call->getType()->isFloat()) {
// 浮点返回值在 fa0 (物理寄存器 F10)
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
fmv_s->addOperand(std::make_unique<RegOperand>(dest_vreg));
fmv_s->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
CurMBB->addInstruction(std::move(fmv_s));
} else {
// 整数/指针返回值在 a0
auto mv = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv->addOperand(std::make_unique<RegOperand>(dest_vreg));
mv->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
CurMBB->addInstruction(std::move(mv));
}
}
// --- 步骤 5: 回收为栈参数分配的空间 ---
if (stack_space > 0) {
auto dealloc_instr = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
dealloc_instr->addOperand(std::make_unique<ImmOperand>(stack_space));
CurMBB->addInstruction(std::move(dealloc_instr));
}
// 处理返回值从a0移动到目标虚拟寄存器
// if (!call->getType()->isVoid()) {
// auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
// mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(call)));
// mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
// CurMBB->addInstruction(std::move(mv_instr));
// }
break;
}
@@ -634,17 +963,47 @@ void RISCv64ISel::selectNode(DAGNode* node) {
auto ret_inst_ir = dynamic_cast<ReturnInst*>(node->value);
if (ret_inst_ir && ret_inst_ir->hasReturnValue()) {
Value* ret_val = ret_inst_ir->getReturnValue();
// [V2优点] 在RETURN节点内加载常量返回值
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li_instr));
Type* ret_type = ret_val->getType();
if (ret_type->isFloat()) {
// --- 处理浮点返回值 ---
// 返回值需要被放入 fa0 (物理寄存器 F10)
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
// 如果是浮点常量需要先物化到fa0
float f_val = const_val->getFloat();
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
// 1. 加载位模式到临时整数寄存器 (t0)
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
li->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
li->addOperand(std::make_unique<ImmOperand>(float_bits));
CurMBB->addInstruction(std::move(li));
// 2. 将位模式从 t0 移动到 fa0
auto fmv_wx = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
fmv_wx->addOperand(std::make_unique<RegOperand>(PhysicalReg::T0));
CurMBB->addInstruction(std::move(fmv_wx));
} else {
// 如果是vreg直接用 fmv.s 移动到 fa0
auto fmv_s = std::make_unique<MachineInstr>(RVOpcodes::FMV_S);
fmv_s->addOperand(std::make_unique<RegOperand>(PhysicalReg::F10)); // fa0
fmv_s->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
CurMBB->addInstruction(std::move(fmv_s));
}
} else {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
CurMBB->addInstruction(std::move(mv_instr));
// --- 处理整数/指针返回值 ---
// 返回值需要被放入 a0
// [V2优点] 在RETURN节点内加载常量返回值
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
li_instr->addOperand(std::make_unique<ImmOperand>(const_val->getInt()));
CurMBB->addInstruction(std::move(li_instr));
} else {
auto mv_instr = std::make_unique<MachineInstr>(RVOpcodes::MV);
mv_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
mv_instr->addOperand(std::make_unique<RegOperand>(getVReg(ret_val)));
CurMBB->addInstruction(std::move(mv_instr));
}
}
}
// [V1设计保留] 函数尾声epilogue不由RETURN节点生成
@@ -870,7 +1229,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
CurMBB->addInstruction(std::move(mv));
}
// --- Step 2: [最终权威版] 遵循LLVM GEP语义迭代计算地址 ---
// --- Step 2: 遵循LLVM GEP语义迭代计算地址 ---
// 初始被索引的类型,是基指针指向的那个类型 (例如, [2 x i32])
Type* current_type = gep->getBasePointer()->getType()->as<PointerType>()->getBaseType();
@@ -967,25 +1326,54 @@ RISCv64ISel::DAGNode* RISCv64ISel::create_node(int kind_int, Value* val, std::ma
return raw_node_ptr;
}
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(Value* val_ir, std::map<Value*, DAGNode*>& value_to_node, std::vector<std::unique_ptr<DAGNode>>& nodes_storage) {
RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(
Value* val_ir,
std::map<Value*, DAGNode*>& value_to_node,
std::vector<std::unique_ptr<DAGNode>>& nodes_storage
) {
// 空指针错误处理
if (val_ir == nullptr) {
throw std::runtime_error("get_operand_node received a null Value.");
}
// 规则1如果这个Value已经有对应的节点直接返回
if (value_to_node.count(val_ir)) {
return value_to_node[val_ir];
} else if (dynamic_cast<ConstantValue*>(val_ir)) {
}
if (auto const_val = dynamic_cast<ConstantValue*>(val_ir)) {
if (const_val->isInt()) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else {
// 为浮点常量创建新的FP_CONSTANT节点
return create_node(DAGNode::FP_CONSTANT, val_ir, value_to_node, nodes_storage);
}
}
if (dynamic_cast<GlobalValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<GlobalValue*>(val_ir)) {
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
}
if (dynamic_cast<AllocaInst*>(val_ir)) {
return create_node(DAGNode::ALLOCA_ADDR, val_ir, value_to_node, nodes_storage);
} else if (dynamic_cast<Argument*>(val_ir)) {
// Argument 是一个叶子节点,它代表一个在函数入口就可用的值。
}
if (dynamic_cast<Argument*>(val_ir)) {
return create_node(DAGNode::ARGUMENT, val_ir, value_to_node, nodes_storage);
}
// 默认行为:如果一个操作数不是上面任何一种叶子节点,
// 并且没有在value_to_node中找到意味着它不是由另一条指令定义的
// 这是一个逻辑问题。但为了保持向前兼容我们暂时保留旧的LOAD行为
// 尽管在修复Argument后它不应该再被错误触发。
return create_node(DAGNode::LOAD, val_ir, value_to_node, nodes_storage);
if (dynamic_cast<ConstantVariable*>(val_ir)) {
// 全局常量数组和全局变量类似,在指令选择层面都表现为一个常量地址
// 因此也为它创建一个 CONSTANT 类型的节点
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
}
// 如果代码执行到这里意味着val_ir不是上述任何一种叶子节点
// 且它也不是在当前基本块中定义的否则它会在value_to_node中被找到
// 这说明它是一个来自前驱块的Live-In值。
// 我们将其视为一个与函数参数(Argument)类似的“块输入值”并为它创建一个ARGUMENT节点。
// 这样,后续的指令选择逻辑就知道这个值是直接可用的,无需在当前块内计算。
if (dynamic_cast<Instruction*>(val_ir)) {
return create_node(DAGNode::ARGUMENT, val_ir, value_to_node, nodes_storage);
}
// 如果一个Value不是任何已知类型也不是指令那说明出现了未处理的情况抛出异常。
throw std::runtime_error("Unhandled Value type in get_operand_node for value named: " + val_ir->getName());
}
std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicBlock* bb) {
@@ -1032,6 +1420,17 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
if(value_to_node.count(bin)) continue;
if (bin->getKind() == Instruction::kFSub) {
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
// 使用isZero()来判断浮点数0.0,比直接比较更健壮
if (const_lhs->isZero()) {
// 这是一个浮点取负操作,创建 FUNARY 节点
auto funary_node = create_node(DAGNode::FUNARY, bin, value_to_node, nodes_storage);
funary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
continue; // 处理完毕,跳到下一条指令
}
}
}
if (bin->getKind() == BinaryInst::kSub) {
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
if (const_lhs->getInt() == 0) {
@@ -1041,13 +1440,24 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
}
}
}
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
if (bin->getKind() >= Instruction::kFAdd) { // 假设浮点指令枚举值更大
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
} else {
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
}
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
if(value_to_node.count(un)) continue;
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
if (un->getKind() >= Instruction::kFNeg) {
auto funary_node = create_node(DAGNode::FUNARY, un, value_to_node, nodes_storage);
funary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
} else {
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
}
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
if(value_to_node.count(call)) continue;
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
@@ -1135,6 +1545,7 @@ void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, co
case DAGNode::ALLOCA_ADDR: return "ALLOCA_ADDR";
case DAGNode::UNARY: return "UNARY";
case DAGNode::MEMSET: return "MEMSET";
case DAGNode::GET_ELEMENT_PTR: return "GET_ELEMENT_PTR";
default: return "UNKNOWN";
}
};

View File

@@ -10,9 +10,10 @@
namespace sysy {
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
// 1. 初始化可分配的整数寄存器池
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, /*PhysicalReg::T5,*/PhysicalReg::T6,
PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6, // T5是大立即数传送寄存器
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
@@ -20,26 +21,39 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 创建一个包含所有通用整数寄存器的临时列表
const std::vector<PhysicalReg> all_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
// 2. 初始化可分配的浮点寄存器池
allocable_fp_regs = {
// 浮点临时寄存器 ft0-ft11
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
// 浮点参数/返回值寄存器 fa0-fa7
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13,
PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
// 浮点保存寄存器 fs0-fs11
PhysicalReg::F8, PhysicalReg::F9,
PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21,
PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25,
PhysicalReg::F26, PhysicalReg::F27
};
// 映射物理寄存器到特殊的虚拟寄存器ID用于干扰图中的物理寄存器节点
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
for (PhysicalReg preg : all_int_regs) {
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
// 3. 映射所有物理寄存器包括整数、浮点和特殊寄存器到特殊的虚拟寄存器ID
// 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器
for (int i = 0; i < static_cast<int>(PhysicalReg::PHYS_REG_START_ID); ++i) {
auto preg = static_cast<PhysicalReg>(i);
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + i;
}
}
// 寄存器分配的主入口点
void RISCv64RegAlloc::run() {
// --- 在所有流程开始前构建完整的vreg到Value的反向映射 ---
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
for (const auto& pair : vreg_map_from_isel) {
Value* val = pair.first;
unsigned vreg = pair.second;
vreg_to_value_map[vreg] = val;
}
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
@@ -68,7 +82,10 @@ void RISCv64RegAlloc::run() {
// 阶段 5: 图着色算法分配物理寄存器
colorGraph();
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
rewriteFunction();
rewriteFunction();
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中供后续Pass使用
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
}
/**
@@ -82,35 +99,38 @@ void RISCv64RegAlloc::handleCallingConvention() {
RISCv64ISel* isel = MFunc->getISel();
// --- 部分1处理函数传入参数的预着色 ---
// 获取函数的Argument对象列表
if (F) {
auto& args = F->getArguments();
// RISC-V RV64G调用约定前8个整型/指针参数通过 a0-a7 传递
int arg_idx = 0;
// 遍历 Argument* 列表
for (Argument* arg : args) {
if (arg_idx >= 8) {
break;
}
// 获取该 Argument 对象对应的虚拟寄存器ID
// 通过 MachineFunction -> RISCv64ISel -> vreg_map 来获取
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
assert(vreg_map_from_isel.count(arg) && "Argument not found in ISel's vreg_map!");
// 1. 获取该 Argument 对象对应的虚拟寄存器
unsigned vreg = isel->getVReg(arg);
// 2. 根据参数索引,确定对应的物理寄存器 (a0, a1, ...)
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
// 3. 在 color_map 中,将 vreg "预着色" 为对应的物理寄存器
color_map[vreg] = preg;
// [修改] 为整数参数和浮点参数分别维护索引
int int_arg_idx = 0;
int float_arg_idx = 0;
arg_idx++;
for (Argument* arg : args) {
// [修改] 根据参数类型决定使用哪个寄存器池和索引
if (arg->getType()->isFloat()) {
// --- 处理浮点参数 ---
if (float_arg_idx >= 8) continue; // fa0-fa7
unsigned vreg = isel->getVReg(arg);
// 浮点参数使用 fa10-fa17 (在RISC-V ABI中对应F10-F17)
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) continue; // a0-a7
unsigned vreg = isel->getVReg(arg);
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
color_map[vreg] = preg;
int_arg_idx++;
}
}
}
// // --- 部分2[新逻辑] 遍历所有指令,为CALL指令的返回值预着色为 a0 ---
// // 这是为了强制寄存器分配器知道call的结果物理上出现在a0寄存器。
// --- 部分2为CALL指令的返回值预着色 ---
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
if (instr->getOpcode() == RVOpcodes::CALL) {
@@ -121,11 +141,17 @@ void RISCv64RegAlloc::handleCallingConvention() {
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
unsigned ret_vreg = reg_op->getVRegNum();
// 强制将这个虚拟寄存器预着色为 a0
color_map[ret_vreg] = PhysicalReg::A0;
if (DEBUG) {
std::cout << "[DEBUG] Pre-coloring vreg" << ret_vreg
<< " to a0 for CALL instruction." << std::endl;
// [修改] 检查返回值的类型,预着色到 a0 或 fa0
assert(MFunc->getISel()->getVRegValueMap().count(ret_vreg) && "Return vreg not found in value map!");
Value* ret_val = MFunc->getISel()->getVRegValueMap().at(ret_vreg);
if (ret_val->getType()->isFloat()) {
// 浮点返回值预着色到 fa0 (F10)
color_map[ret_vreg] = PhysicalReg::F10;
} else {
// 整数/指针返回值预着色到 a0
color_map[ret_vreg] = PhysicalReg::A0;
}
}
}
@@ -218,6 +244,30 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(load_instr));
} else if (opcode == RVOpcodes::FRAME_LOAD_F) {
// 展开浮点加载伪指令
RVOpcodes real_load_op = RVOpcodes::FLW; // 对应的真实指令是 flw
auto& operands = instr_ptr->getOperands();
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
int offset = frame_info.alloca_offsets.at(alloca_vreg);
auto addr_vreg = isel->getNewVReg();
// 展开为: addi addr_vreg, s0, offset
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
addi->addOperand(std::make_unique<ImmOperand>(offset));
new_instructions.push_back(std::move(addi));
// 展开为: flw dest_vreg, 0(addr_vreg)
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
load_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(load_instr));
} else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D) {
// 确定要生成的真实存储指令是 sw 还是 sd
RVOpcodes real_store_op = (opcode == RVOpcodes::FRAME_STORE_W) ? RVOpcodes::SW : RVOpcodes::SD;
@@ -243,6 +293,30 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(store_instr));
} else if (opcode == RVOpcodes::FRAME_STORE_F) {
// 展开浮点存储伪指令
RVOpcodes real_store_op = RVOpcodes::FSW; // 对应的真实指令是 fsw
auto& operands = instr_ptr->getOperands();
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
int offset = frame_info.alloca_offsets.at(alloca_vreg);
auto addr_vreg = isel->getNewVReg();
// 展开为: addi addr_vreg, s0, offset
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
addi->addOperand(std::make_unique<ImmOperand>(offset));
new_instructions.push_back(std::move(addi));
// 展开为: fsw src_vreg, 0(addr_vreg)
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
store_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(addr_vreg),
std::make_unique<ImmOperand>(0)));
new_instructions.push_back(std::move(store_instr));
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) {
auto& operands = instr_ptr->getOperands();
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
@@ -277,7 +351,7 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
// 1. 特殊指令的 `is_def` 标志调整
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW ||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
@@ -324,6 +398,27 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
}
return; // CALL 指令处理完毕
}
// 2.1 浮点比较指令添加特殊规则
// 它们的源操作数是浮点寄存器,但目标操作数是整数寄存器
if (opcode == RVOpcodes::FEQ_S || opcode == RVOpcodes::FLT_S || opcode == RVOpcodes::FLE_S) {
auto& operands = instr->getOperands();
// Def: 第一个操作数 (整数vreg)
if (operands[0]->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(operands[0].get());
if(reg_op->isVirtual()) def.insert(reg_op->getVRegNum());
}
// Use: 第二、三个操作数 (浮点vreg)
if (operands[1]->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(operands[1].get());
if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum());
}
if (operands[2]->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(operands[2].get());
if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum());
}
return; // 处理完毕
}
// 3. 对其他所有指令的通用处理逻辑 [已重构和修复]
for (const auto& op : instr->getOperands()) {
@@ -351,7 +446,7 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
}
}
} 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()) {
@@ -364,7 +459,7 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
}
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW) &&
!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
@@ -605,28 +700,53 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
}
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
for (PhysicalReg cs_reg : caller_saved_regs) {
if (preg_to_vreg_id_map.count(cs_reg)) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
// 辅助函数用于判断一个vreg是整数类型还是浮点类型
auto is_fp_vreg = [&](unsigned vreg) {
if (vreg_to_value_map.count(vreg)) {
return vreg_to_value_map.at(vreg)->getType()->isFloat();
}
// 对于ISel创建的、没有直接IR Value对应的临时vreg
// 默认其为整数类型。这是一个合理的兜底策略。
return false;
};
// --- 处理整数寄存器干扰 ---
const std::vector<PhysicalReg>& caller_saved_int_regs = getCallerSavedIntRegs();
for (PhysicalReg cs_reg : caller_saved_int_regs) {
// 确保物理寄存器在映射表中,我们已在构造函数中保证了这一点
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
for (unsigned live_vreg_out : live_out) {
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
// [新增调试逻辑] 打印添加的干扰边及其原因
for (unsigned live_vreg_out : live_out) {
// 只为整数vreg添加与整数preg的干扰
if (!is_fp_vreg(live_vreg_out)) {
if (cs_vreg_id != live_vreg_out) {
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
std::cerr << " Edge (CALL) : preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
std::cerr << " Edge (CALL, Int): preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
}
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
} else {
// 如果物理寄存器没有对应的特殊虚拟寄存器ID可能是因为它不是调用者保存的寄存器。
// 这种情况通常不应该发生,但我们可以在这里添加一个警告或错误处理。
if (DEEPDEBUG) {
std::cerr << "Warning: Physical register " << static_cast<int>(cs_reg)
<< " does not have a corresponding special vreg ID.\n";
}
}
// --- 处理浮点寄存器干扰 ---
const std::vector<PhysicalReg>& caller_saved_fp_regs = getCallerSavedFpRegs();
for (PhysicalReg cs_reg : caller_saved_fp_regs) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
for (unsigned live_vreg_out : live_out) {
// 只为浮点vreg添加与浮点preg的干扰
if (is_fp_vreg(live_vreg_out)) {
if (cs_vreg_id != live_vreg_out) {
// 添加与整数版本一致的调试代码
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
std::cerr << " Edge (CALL, FP): preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
}
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
}
}
@@ -650,34 +770,70 @@ void RISCv64RegAlloc::colorGraph() {
return interference_graph[a].size() > interference_graph[b].size();
});
// [调试] 辅助函数用于判断一个vreg是整数还是浮点类型并打印详细诊断信息
auto is_fp_vreg = [&](unsigned vreg) {
if (DEEPDEBUG) {
std::cout << " [Debug is_fp_vreg] Checking vreg" << vreg << ": ";
}
if (vreg_to_value_map.count(vreg)) {
Value* val = vreg_to_value_map.at(vreg);
bool is_float = val->getType()->isFloat();
if (DEEPDEBUG) {
std::cout << "Found in map. Value is '" << val->getName()
<< "', Type is " << (is_float ? "FLOAT" : "INT")
<< ". Returning " << (is_float ? "true" : "false") << ".\n";
}
return is_float;
}
if (DEEPDEBUG) {
std::cout << "NOT found in vreg_to_value_map. Defaulting to INT. Returning false.\n";
}
// 对于ISel创建的、没有直接IR Value对应的临时vreg默认其为整数类型。
return false;
};
// 着色
for (unsigned vreg : sorted_vregs) {
std::set<PhysicalReg> used_colors;
for (unsigned neighbor_id : interference_graph.at(vreg)) {
// --- 关键改进 (来自 rec 分支) ---
// 情况 1: 邻居是一个已经被着色的虚拟寄存器
// 收集邻居颜色的逻辑保持不变
if (color_map.count(neighbor_id)) {
used_colors.insert(color_map.at(neighbor_id));
}
// 情况 2: 邻居本身就是一个代表物理寄存器的节点
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
// 从特殊ID反向解析出是哪个物理寄存器
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
used_colors.insert(neighbor_preg);
}
}
bool is_float = is_fp_vreg(vreg);
const auto& allocable_regs = is_float ? allocable_fp_regs : allocable_int_regs;
// [调试] 打印着色决策过程
if (DEBUG) {
std::cout << "[DEBUG] Coloring %vreg" << vreg
<< ": Type is " << (is_float ? "FLOAT" : "INT")
<< ", choosing from " << (is_float ? "Float" : "Integer") << " pool.\n";
}
bool colored = false;
for (PhysicalReg preg : allocable_int_regs) {
for (PhysicalReg preg : allocable_regs) {
if (used_colors.find(preg) == used_colors.end()) {
color_map[vreg] = preg;
colored = true;
if (DEBUG) {
RISCv64AsmPrinter p(MFunc); // For regToString
std::cout << " -> Assigned to physical register: " << p.regToString(preg) << "\n";
}
break;
}
}
if (!colored) {
spilled_vregs.insert(vreg);
if (DEBUG) {
std::cout << " -> FAILED to color. Spilling.\n";
}
}
}
}
@@ -686,7 +842,7 @@ void RISCv64RegAlloc::rewriteFunction() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = frame_info.locals_size;
// --- FIX 1: 动态计算溢出槽大小 ---
// --- 动态计算溢出槽大小 ---
// 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。
for (unsigned vreg : spilled_vregs) {
// 从反向映射中查找 vreg 对应的 IR Value
@@ -704,23 +860,40 @@ void RISCv64RegAlloc::rewriteFunction() {
}
frame_info.spill_size = current_offset - frame_info.locals_size;
// 定义专用的溢出寄存器
const PhysicalReg INT_SPILL_REG = PhysicalReg::T6; // t6
const PhysicalReg FP_SPILL_REG = PhysicalReg::F7; // ft7
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);
// --- FIX 2: 为溢出的 'use' 操作数插入正确的加载指令 ---
// --- 为溢出的 'use' 操作数插入正确的加载指令 ---
for (unsigned vreg : use) {
if (spilled_vregs.count(vreg)) {
// 同样地,根据 vreg 的类型决定使用 lw 还是 ld
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
RVOpcodes load_op = val->getType()->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
// 根据vreg类型决定加载指令(lw/ld/flw)和目标物理寄存器(t6/ft7)
RVOpcodes load_op;
PhysicalReg target_preg;
if (val->getType()->isFloat()) {
load_op = RVOpcodes::FLW;
target_preg = FP_SPILL_REG;
} else if (val->getType()->isPointer()) {
load_op = RVOpcodes::LD;
target_preg = INT_SPILL_REG;
} else {
load_op = RVOpcodes::LW;
target_preg = INT_SPILL_REG;
}
int offset = frame_info.spill_offsets.at(vreg);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(vreg));
load->addOperand(std::make_unique<RegOperand>(target_preg)); // 加载到专用溢出寄存器
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
@@ -731,17 +904,29 @@ void RISCv64RegAlloc::rewriteFunction() {
new_instructions.push_back(std::move(instr_ptr));
// --- FIX 3: 为溢出的 'def' 操作数插入正确的存储指令 ---
// --- 为溢出的 'def' 操作数插入正确的存储指令 ---
for (unsigned vreg : def) {
if (spilled_vregs.count(vreg)) {
// 根据 vreg 的类型决定使用 sw 还是 sd
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
RVOpcodes store_op = val->getType()->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
// 根据vreg类型决定存储指令(sw/sd/fsw)和源物理寄存器(t6/ft7)
RVOpcodes store_op;
PhysicalReg src_preg;
if (val->getType()->isFloat()) {
store_op = RVOpcodes::FSW;
src_preg = FP_SPILL_REG;
} else if (val->getType()->isPointer()) {
store_op = RVOpcodes::SD;
src_preg = INT_SPILL_REG;
} else {
store_op = RVOpcodes::SW;
src_preg = INT_SPILL_REG;
}
int offset = frame_info.spill_offsets.at(vreg);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(vreg));
store->addOperand(std::make_unique<RegOperand>(src_preg)); // 从专用溢出寄存器存储
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
@@ -757,40 +942,29 @@ void RISCv64RegAlloc::rewriteFunction() {
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr_ptr : mbb->getInstructions()) {
for (auto& op_ptr : instr_ptr->getOperands()) {
// 情况一:操作数本身就是一个寄存器 (例如 add rd, rs1, rs2 中的所有操作数)
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
// 定义一个处理寄存器操作数的 lambda 函数
auto process_reg_op = [&](RegOperand* reg_op) {
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (color_map.count(vreg)) {
PhysicalReg preg = color_map.at(vreg);
reg_op->setPReg(preg);
reg_op->setPReg(color_map.at(vreg));
} else if (spilled_vregs.count(vreg)) {
// 如果vreg被溢出,替换为专用溢出物理寄存器t6
reg_op->setPReg(PhysicalReg::T6);
}
}
}
// 情况二:操作数是一个内存地址 (例如 lw rd, offset(rs1) 中的 offset(rs1))
else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
// 获取内存操作数内部的“基址寄存器”
auto base_reg_op = mem_op->getBase();
// 对这个基址寄存器,执行与情况一完全相同的替换逻辑
if(base_reg_op->isVirtual()){
unsigned vreg = base_reg_op->getVRegNum();
if(color_map.count(vreg)) {
// 如果基址vreg被成功着色替换
PhysicalReg preg = color_map.at(vreg);
base_reg_op->setPReg(preg);
} else if (spilled_vregs.count(vreg)) {
// 如果基址vreg被溢出替换为t6
base_reg_op->setPReg(PhysicalReg::T6);
// 根据vreg类型,替换为对应的专用溢出寄存器
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
if (val->getType()->isFloat()) {
reg_op->setPReg(FP_SPILL_REG);
} else {
reg_op->setPReg(INT_SPILL_REG);
}
}
}
};
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
process_reg_op(static_cast<RegOperand*>(op_ptr.get()));
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
process_reg_op(static_cast<MemOperand*>(op_ptr.get())->getBase());
}
}
}