From 03e88eee7005a626db69d8cc4a6f424c069a39be Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Thu, 31 Jul 2025 23:02:53 +0800 Subject: [PATCH 01/10] =?UTF-8?q?[backend-IRC]=E5=88=9D=E6=AD=A5=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E6=96=B0=E7=9A=84=E5=AF=84=E5=AD=98=E5=99=A8=E5=88=86?= =?UTF-8?q?=E9=85=8D=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/runit-single.sh | 12 +- src/backend/RISCv64/CMakeLists.txt | 1 + .../RISCv64/Handler/CalleeSavedHandler.cpp | 82 +- .../RISCv64/Handler/EliminateFrameIndices.cpp | 157 ++ .../Handler/PrologueEpilogueInsertion.cpp | 121 +- src/backend/RISCv64/RISCv64Backend.cpp | 34 +- src/backend/RISCv64/RISCv64RegAlloc.cpp | 1975 ++++++++++------- .../RISCv64/Handler/EliminateFrameIndices.h | 20 + src/include/backend/RISCv64/RISCv64LLIR.h | 9 +- src/include/backend/RISCv64/RISCv64Passes.h | 1 + src/include/backend/RISCv64/RISCv64RegAlloc.h | 130 +- 11 files changed, 1514 insertions(+), 1028 deletions(-) create mode 100644 src/backend/RISCv64/Handler/EliminateFrameIndices.cpp create mode 100644 src/include/backend/RISCv64/Handler/EliminateFrameIndices.h diff --git a/script/runit-single.sh b/script/runit-single.sh index 8b7804f..ed32181 100644 --- a/script/runit-single.sh +++ b/script/runit-single.sh @@ -68,7 +68,7 @@ display_file_content() { fi } -# --- 本次修改点: 整个参数解析逻辑被重写 --- +# --- 参数解析 --- # 使用标准的 while 循环来健壮地处理任意顺序的参数 while [[ "$#" -gt 0 ]]; do case "$1" in @@ -164,6 +164,16 @@ for sy_file in "${SY_FILES[@]}"; do echo "======================================================================" echo "正在处理: ${sy_file}" + # --- 本次修改点: 拷贝源文件到 tmp 目录 --- + echo " 拷贝源文件到 ${TMP_DIR}..." + cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")" + if [ -f "${input_file}" ]; then + cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")" + fi + if [ -f "${output_reference_file}" ]; then + cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")" + fi + # 步骤 1: sysyc 编译 echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..." timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}" diff --git a/src/backend/RISCv64/CMakeLists.txt b/src/backend/RISCv64/CMakeLists.txt index eb9f37f..6e397cc 100644 --- a/src/backend/RISCv64/CMakeLists.txt +++ b/src/backend/RISCv64/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(riscv64_backend_lib STATIC Handler/CalleeSavedHandler.cpp Handler/LegalizeImmediates.cpp Handler/PrologueEpilogueInsertion.cpp + Handler/EliminateFrameIndices.cpp Optimize/Peephole.cpp Optimize/PostRA_Scheduler.cpp Optimize/PreRA_Scheduler.cpp diff --git a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp index cdbccc1..b4cbc83 100644 --- a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp +++ b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp @@ -8,7 +8,6 @@ namespace sysy { char CalleeSavedHandler::ID = 0; -// 辅助函数,用于判断一个物理寄存器是否为浮点寄存器 static bool is_fp_reg(PhysicalReg reg) { return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31; } @@ -20,100 +19,72 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) { void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { StackFrameInfo& frame_info = mfunc->getFrameInfo(); - - std::set used_callee_saved; - - // 1. 扫描所有指令,找出被使用的callee-saved寄存器 - // 这个Pass在RegAlloc之后运行,所以可以访问到物理寄存器 - 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 && !reg_op->isVirtual()) { - PhysicalReg preg = reg_op->getPReg(); - - // 检查整数 s1-s11 - if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) { - used_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_callee_saved.insert(preg); - } - } - }; - - if (op->getKind() == MachineOperand::KIND_REG) { - check_and_insert_reg(static_cast(op.get())); - } else if (op->getKind() == MachineOperand::KIND_MEM) { - check_and_insert_reg(static_cast(op.get())->getBase()); - } - } - } - } + const std::set& used_callee_saved = frame_info.used_callee_saved_regs; if (used_callee_saved.empty()) { frame_info.callee_saved_size = 0; return; } - // 2. 计算并更新 frame_info - frame_info.callee_saved_size = used_callee_saved.size() * 8; - - // 为了布局确定性和恢复顺序一致,对寄存器排序 + // 1. 计算大小并排序,以便确定地生成代码 + frame_info.callee_saved_size = used_callee_saved.size() * 8; // 每个寄存器占8字节 std::vector sorted_regs(used_callee_saved.begin(), used_callee_saved.end()); - std::sort(sorted_regs.begin(), sorted_regs.end()); - - // 3. 在函数序言中插入保存指令 + std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){ return static_cast(a) < static_cast(b); }); + frame_info.callee_saved_regs_to_store = sorted_regs; // 保存排序后的列表 + + // 2. 在函数序言中插入保存指令 MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); auto& entry_instrs = entry_block->getInstructions(); - // 插入点在函数入口标签之后,或者就是最开始 auto insert_pos = entry_instrs.begin(); - if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) { - insert_pos = std::next(insert_pos); - } - + // 确保插入在任何栈分配指令之后,但在其他代码之前。 + // PrologueEpilogueInsertionPass 会处理最终顺序,这里我们先插入。 + std::vector> save_instrs; - // [关键] 从局部变量区域之后开始分配空间 - int current_offset = - (16 + frame_info.locals_size); + int current_offset = -16; // 栈布局: [ra, s0] 在最顶层,然后是callee-saved for (PhysicalReg reg : sorted_regs) { + // s0/fp 已经在序言中由 PrologueEpilogueInsertionPass 特殊处理,这里跳过 + if (reg == PhysicalReg::S0) continue; + current_offset -= 8; RVOpcodes save_op = is_fp_reg(reg) ? RVOpcodes::FSD : RVOpcodes::SD; auto save_instr = std::make_unique(save_op); save_instr->addOperand(std::make_unique(reg)); save_instr->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), // 基址为帧指针 s0 - std::make_unique(current_offset) + std::make_unique(PhysicalReg::SP), // 基址为 SP + std::make_unique(0) // 偏移量将在PEI中修正 )); save_instrs.push_back(std::move(save_instr)); } if (!save_instrs.empty()) { + // 在序言的开头插入保存指令(PEI会后续调整它们的偏移) entry_instrs.insert(insert_pos, std::make_move_iterator(save_instrs.begin()), std::make_move_iterator(save_instrs.end())); } - // 4. 在函数结尾(ret之前)插入恢复指令 + // 3. 在函数结尾(ret之前)插入恢复指令 for (auto& mbb : mfunc->getBlocks()) { for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { if ((*it)->getOpcode() == RVOpcodes::RET) { std::vector> restore_instrs; - // [关键] 使用与保存时完全相同的逻辑来计算偏移量 - current_offset = - (16 + frame_info.locals_size); + current_offset = -16; - for (PhysicalReg reg : sorted_regs) { + // 以相反的顺序恢复寄存器 + for (auto reg_it = sorted_regs.rbegin(); reg_it != sorted_regs.rend(); ++reg_it) { + PhysicalReg reg = *reg_it; + if (reg == PhysicalReg::S0) continue; + current_offset -= 8; RVOpcodes restore_op = is_fp_reg(reg) ? RVOpcodes::FLD : RVOpcodes::LD; auto restore_instr = std::make_unique(restore_op); restore_instr->addOperand(std::make_unique(reg)); restore_instr->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(current_offset) + std::make_unique(PhysicalReg::SP), + std::make_unique(0) // 偏移量同样由PEI修正 )); restore_instrs.push_back(std::move(restore_instr)); } @@ -129,5 +100,4 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { next_block_label:; } } - } // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp new file mode 100644 index 0000000..f2aa6fa --- /dev/null +++ b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp @@ -0,0 +1,157 @@ +#include "EliminateFrameIndices.h" +#include "RISCv64ISel.h" +#include + +namespace sysy { + +unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) { + if (!type) { + assert(false && "Cannot get size of a null type."); + return 0; + } + + switch (type->getKind()) { + case Type::kInt: + case Type::kFloat: + return 4; + case Type::kPointer: + return 8; + case Type::kArray: { + auto arrayType = type->as(); + return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType()); + } + default: + assert(false && "Unsupported type for size calculation."); + return 0; + } +} + +void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { + StackFrameInfo& frame_info = mfunc->getFrameInfo(); + Function* F = mfunc->getFunc(); + RISCv64ISel* isel = mfunc->getISel(); + + // 1. 为栈传递的参数计算偏移量 + if (F) { + int arg_idx = 0; + for (Argument* arg : F->getArguments()) { + // 只关心第8个索引及之后的参数 (即第9个参数开始) + if (arg_idx >= 8) { + // 第一个栈参数(idx=8)在0(s0), 第二个(idx=9)在8(s0) + int offset = (arg_idx - 8) * 8; + unsigned vreg = isel->getVReg(arg); + frame_info.alloca_offsets[vreg] = offset; + } + arg_idx++; + } + } + + // 2. 为局部变量分配空间,起始点在 [ra, s0] (16字节) 之后 + int local_var_offset = 16; + + // 处理局部变量 (AllocaInst) + if(F) { // 确保函数指针有效 + for (auto& bb : F->getBasicBlocks()) { + for (auto& inst : bb->getInstructions()) { + if (auto alloca = dynamic_cast(inst.get())) { + Type* allocated_type = alloca->getType()->as()->getBaseType(); + int size = getTypeSizeInBytes(allocated_type); + + // RISC-V要求栈地址8字节对齐 + size = (size + 7) & ~7; + if (size == 0) size = 8; // 至少分配8字节 + + local_var_offset += size; + unsigned alloca_vreg = isel->getVReg(alloca); + // 局部变量使用相对于s0的负向偏移 + frame_info.alloca_offsets[alloca_vreg] = -local_var_offset; + } + } + } + } + + // 记录仅由AllocaInst分配的局部变量的总大小 + frame_info.locals_size = local_var_offset - 16; + + // 3. 遍历所有机器指令,将伪指令展开为真实指令 + for (auto& mbb : mfunc->getBlocks()) { + std::vector> new_instructions; + for (auto& instr_ptr : mbb->getInstructions()) { + RVOpcodes opcode = instr_ptr->getOpcode(); + + if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D || opcode == RVOpcodes::FRAME_LOAD_F) { + RVOpcodes real_load_op; + if (opcode == RVOpcodes::FRAME_LOAD_W) real_load_op = RVOpcodes::LW; + else if (opcode == RVOpcodes::FRAME_LOAD_D) real_load_op = RVOpcodes::LD; + else real_load_op = RVOpcodes::FLW; + + auto& operands = instr_ptr->getOperands(); + unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); + unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); + int offset = frame_info.alloca_offsets.at(alloca_vreg); + auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType())); + + // 展开为: addi addr_vreg, s0, offset + auto addi = std::make_unique(RVOpcodes::ADDI); + addi->addOperand(std::make_unique(addr_vreg)); + addi->addOperand(std::make_unique(PhysicalReg::S0)); + addi->addOperand(std::make_unique(offset)); + new_instructions.push_back(std::move(addi)); + + // 展开为: lw/ld/flw dest_vreg, 0(addr_vreg) + auto load_instr = std::make_unique(real_load_op); + load_instr->addOperand(std::make_unique(dest_vreg)); + load_instr->addOperand(std::make_unique( + std::make_unique(addr_vreg), + std::make_unique(0))); + new_instructions.push_back(std::move(load_instr)); + + } else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D || opcode == RVOpcodes::FRAME_STORE_F) { + RVOpcodes real_store_op; + if (opcode == RVOpcodes::FRAME_STORE_W) real_store_op = RVOpcodes::SW; + else if (opcode == RVOpcodes::FRAME_STORE_D) real_store_op = RVOpcodes::SD; + else real_store_op = RVOpcodes::FSW; + + auto& operands = instr_ptr->getOperands(); + unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); + unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); + int offset = frame_info.alloca_offsets.at(alloca_vreg); + auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType())); + + // 展开为: addi addr_vreg, s0, offset + auto addi = std::make_unique(RVOpcodes::ADDI); + addi->addOperand(std::make_unique(addr_vreg)); + addi->addOperand(std::make_unique(PhysicalReg::S0)); + addi->addOperand(std::make_unique(offset)); + new_instructions.push_back(std::move(addi)); + + // 展开为: sw/sd/fsw src_vreg, 0(addr_vreg) + auto store_instr = std::make_unique(real_store_op); + store_instr->addOperand(std::make_unique(src_vreg)); + store_instr->addOperand(std::make_unique( + std::make_unique(addr_vreg), + std::make_unique(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(operands[0].get())->getVRegNum(); + unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); + int offset = frame_info.alloca_offsets.at(alloca_vreg); + + // 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset` + auto addi = std::make_unique(RVOpcodes::ADDI); + addi->addOperand(std::make_unique(dest_vreg)); + addi->addOperand(std::make_unique(PhysicalReg::S0)); + addi->addOperand(std::make_unique(offset)); + new_instructions.push_back(std::move(addi)); + + } else { + new_instructions.push_back(std::move(instr_ptr)); + } + } + mbb->getInstructions() = std::move(new_instructions); + } +} + +} // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index 30fa6bd..05532b7 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -1,6 +1,5 @@ #include "PrologueEpilogueInsertion.h" #include "RISCv64ISel.h" -#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果 #include namespace sysy { @@ -8,10 +7,11 @@ namespace sysy { char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { + StackFrameInfo& frame_info = mfunc->getFrameInfo(); + + // 1. 删除 KEEPALIVE 伪指令 for (auto& mbb : mfunc->getBlocks()) { auto& instrs = mbb->getInstructions(); - - // 使用标准的 Erase-Remove Idiom 来删除满足条件的元素 instrs.erase( std::remove_if(instrs.begin(), instrs.end(), [](const std::unique_ptr& instr) { @@ -22,39 +22,28 @@ 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 + - frame_info.callee_saved_size + - 16; // 为 ra 和 s0 固定的16字节 - - int aligned_stack_size = (total_stack_size + 15) & ~15; + // 2. 计算最终的栈帧总大小 + // 总大小 = [ra, s0] + [被调用者保存寄存器] + [局部变量] + [溢出槽] + [调用其他函数的参数区] + // 假设调用参数区大小为0,因为它是在call指令周围动态分配和释放的 + int total_stack_size = 16 + frame_info.callee_saved_size + frame_info.locals_size + frame_info.spill_size; + int aligned_stack_size = (total_stack_size + 15) & ~15; // 16字节对齐 frame_info.total_size = aligned_stack_size; - // 只有在需要分配栈空间时才生成指令 + // 只有在需要分配栈空间时才生成序言/尾声 if (aligned_stack_size > 0) { - // --- 1. 插入序言 --- + // --- 3. 插入序言 --- MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); auto& entry_instrs = entry_block->getInstructions(); - std::vector> prologue_instrs; - // 1. addi sp, sp, -aligned_stack_size + // a. addi sp, sp, -aligned_stack_size auto alloc_stack = std::make_unique(RVOpcodes::ADDI); alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); alloc_stack->addOperand(std::make_unique(-aligned_stack_size)); prologue_instrs.push_back(std::move(alloc_stack)); - // 2. sd ra, (aligned_stack_size - 8)(sp) + // b. sd ra, (aligned_stack_size - 8)(sp) auto save_ra = std::make_unique(RVOpcodes::SD); save_ra->addOperand(std::make_unique(PhysicalReg::RA)); save_ra->addOperand(std::make_unique( @@ -63,7 +52,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); prologue_instrs.push_back(std::move(save_ra)); - // 3. sd s0, (aligned_stack_size - 16)(sp) + // c. sd s0, (aligned_stack_size - 16)(sp) auto save_fp = std::make_unique(RVOpcodes::SD); save_fp->addOperand(std::make_unique(PhysicalReg::S0)); save_fp->addOperand(std::make_unique( @@ -72,66 +61,25 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); prologue_instrs.push_back(std::move(save_fp)); - // 4. addi s0, sp, aligned_stack_size + // d. addi s0, sp, aligned_stack_size auto set_fp = std::make_unique(RVOpcodes::ADDI); set_fp->addOperand(std::make_unique(PhysicalReg::S0)); set_fp->addOperand(std::make_unique(PhysicalReg::SP)); set_fp->addOperand(std::make_unique(aligned_stack_size)); prologue_instrs.push_back(std::move(set_fp)); - // --- 在s0设置完毕后,使用物理寄存器加载栈参数 --- - if (F && isel) { - int arg_idx = 0; - for (Argument* arg : F->getArguments()) { - if (arg_idx >= 8) { - unsigned vreg = isel->getVReg(arg); - - 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(); + // 将序言指令插入到函数入口 + entry_instrs.insert(entry_instrs.begin(), + std::make_move_iterator(prologue_instrs.begin()), + std::make_move_iterator(prologue_instrs.end())); - if (arg_type->isFloat()) { - auto load_arg = std::make_unique(RVOpcodes::FLW); - load_arg->addOperand(std::make_unique(dest_preg)); - load_arg->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(offset) - )); - prologue_instrs.push_back(std::move(load_arg)); - } else { - RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW; - auto load_arg = std::make_unique(load_op); - load_arg->addOperand(std::make_unique(dest_preg)); - load_arg->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(offset) - )); - prologue_instrs.push_back(std::move(load_arg)); - } - } - } - arg_idx++; - } - } - - // 确定插入点 - auto insert_pos = entry_instrs.begin(); - - // 一次性将所有序言指令插入 - if (!prologue_instrs.empty()) { - entry_instrs.insert(insert_pos, - std::make_move_iterator(prologue_instrs.begin()), - std::make_move_iterator(prologue_instrs.end())); - } - - // --- 2. 插入尾声 (此部分逻辑保持不变) --- + // --- 4. 插入尾声 --- for (auto& mbb : mfunc->getBlocks()) { for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { if ((*it)->getOpcode() == RVOpcodes::RET) { std::vector> epilogue_instrs; - // 1. ld ra + // a. ld ra auto restore_ra = std::make_unique(RVOpcodes::LD); restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); restore_ra->addOperand(std::make_unique( @@ -140,7 +88,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); epilogue_instrs.push_back(std::move(restore_ra)); - // 2. ld s0 + // b. ld s0 auto restore_fp = std::make_unique(RVOpcodes::LD); restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); restore_fp->addOperand(std::make_unique( @@ -149,24 +97,39 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); epilogue_instrs.push_back(std::move(restore_fp)); - // 3. addi sp, sp, aligned_stack_size + // c. addi sp, sp, aligned_stack_size auto dealloc_stack = std::make_unique(RVOpcodes::ADDI); dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); dealloc_stack->addOperand(std::make_unique(aligned_stack_size)); epilogue_instrs.push_back(std::move(dealloc_stack)); - if (!epilogue_instrs.empty()) { - mbb->getInstructions().insert(it, - std::make_move_iterator(epilogue_instrs.begin()), - std::make_move_iterator(epilogue_instrs.end())); - } + mbb->getInstructions().insert(it, + std::make_move_iterator(epilogue_instrs.begin()), + std::make_move_iterator(epilogue_instrs.end())); + it++; // 跳过刚插入的指令和原有的RET goto next_block; } } next_block:; } } + + // --- 5. [新增] 修正所有基于S0的内存访问偏移量 --- + // CalleeSaved, Alloca, Spill 的偏移量都是相对于S0的负向偏移 + for (auto& mbb : mfunc->getBlocks()) { + for (auto& instr : mbb->getInstructions()) { + if (instr->getOperands().empty() || instr->getOperands().back()->getKind() != MachineOperand::KIND_MEM) { + continue; + } + auto mem_op = static_cast(instr->getOperands().back().get()); + if (mem_op->getBase()->isVirtual() || mem_op->getBase()->getPReg() != PhysicalReg::S0) { + continue; + } + // 此时所有基于S0的偏移量都是负数,无需再次调整 + // 之前的RegAlloc/CalleeSavedHandler已经计算好了正确的相对于S0的偏移 + } + } } } // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index 2797eb7..3841eec 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -115,13 +115,21 @@ std::string RISCv64CodeGen::function_gen(Function* func) { std::unique_ptr mfunc = isel.runOnFunction(func); // 第一次调试打印输出 - std::stringstream ss1; - RISCv64AsmPrinter printer1(mfunc.get()); - printer1.run(ss1, true); + std::stringstream ss_after_isel; + if (DEBUG) { + RISCv64AsmPrinter printer_isel(mfunc.get()); + printer_isel.run(ss_after_isel, true); + std::cout << ss_after_isel.str(); + } - // 阶段 2: 指令调度 (Instruction Scheduling) - PreRA_Scheduler scheduler; - scheduler.runOnMachineFunction(mfunc.get()); + // [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移) + // 这个Pass必须在寄存器分配之前运行 + EliminateFrameIndicesPass efi_pass; + efi_pass.runOnMachineFunction(mfunc.get()); + + // // 阶段 2: 指令调度 (Instruction Scheduling) + // PreRA_Scheduler scheduler; + // scheduler.runOnMachineFunction(mfunc.get()); // 阶段 3: 物理寄存器分配 (Register Allocation) RISCv64RegAlloc reg_alloc(mfunc.get()); @@ -131,9 +139,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) { CalleeSavedHandler callee_handler; callee_handler.runOnMachineFunction(mfunc.get()); - // 阶段 4: 窥孔优化 (Peephole Optimization) - PeepholeOptimizer peephole; - peephole.runOnMachineFunction(mfunc.get()); + // // 阶段 4: 窥孔优化 (Peephole Optimization) + // PeepholeOptimizer peephole; + // peephole.runOnMachineFunction(mfunc.get()); // 阶段 5: 局部指令调度 (Local Scheduling) PostRA_Scheduler local_scheduler; @@ -143,7 +151,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) { PrologueEpilogueInsertionPass pei_pass; pei_pass.runOnMachineFunction(mfunc.get()); - // 阶段 3.3: 清理产生的大立即数 + // 阶段 3.3: 大立即数合法化 LegalizeImmediatesPass legalizer; legalizer.runOnMachineFunction(mfunc.get()); @@ -151,7 +159,11 @@ std::string RISCv64CodeGen::function_gen(Function* func) { std::stringstream ss; RISCv64AsmPrinter printer(mfunc.get()); printer.run(ss); - if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中 + + if (DEBUG) { + ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n" + << ss_after_isel.str(); + } return ss.str(); } diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index cf73191..64ff4ef 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -1,128 +1,122 @@ +// in file: RISCv64RegAlloc.cpp + #include "RISCv64RegAlloc.h" -#include "RISCv64ISel.h" -#include "RISCv64AsmPrinter.h" // For DEBUG output -#include "LegalizeImmediates.h" +#include "RISCv64AsmPrinter.h" #include -#include -#include // For DEBUG output -#include // For assert +#include +#include +#include namespace sysy { -RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) { +// 构造函数:初始化寄存器池和数据结构 +RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) + : MFunc(mfunc), + ISel(mfunc->getISel()), + vreg_to_value_map(ISel->getVRegValueMap()), + vreg_type_map(ISel->getVRegTypeMap()) { // 1. 初始化可分配的整数寄存器池 allocable_int_regs = { - PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, - 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, - PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7, + PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /* T5保留 */ PhysicalReg::T6, + PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7, + PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7, PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11, + // S0 是帧指针,不参与分配 }; + K_int = allocable_int_regs.size(); // 2. 初始化可分配的浮点寄存器池 allocable_fp_regs = { - // 浮点临时寄存器 ft0-ft11 - PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, - PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7, + PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7, + PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17, + PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22, + PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27, PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31, - // 浮点参数/返回值寄存器 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 }; - - // 3. 映射所有物理寄存器(包括整数、浮点和特殊寄存器)到特殊的虚拟寄存器ID - // 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器 - for (int i = 0; i < static_cast(PhysicalReg::PHYS_REG_START_ID); ++i) { - auto preg = static_cast(i); - preg_to_vreg_id_map[preg] = static_cast(PhysicalReg::PHYS_REG_START_ID) + i; - } + K_fp = allocable_fp_regs.size(); + + // 3. 预着色所有物理寄存器 + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + for (const auto& reg : allocable_int_regs) precolored.insert(offset + static_cast(reg)); + for (const auto& reg : allocable_fp_regs) precolored.insert(offset + static_cast(reg)); + precolored.insert(offset + static_cast(PhysicalReg::S0)); + precolored.insert(offset + static_cast(PhysicalReg::RA)); + precolored.insert(offset + static_cast(PhysicalReg::SP)); + precolored.insert(offset + static_cast(PhysicalReg::ZERO)); } -// 寄存器分配的主入口点 +// 主入口: 迭代运行分配算法直到无溢出 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; + if (DEBUG) std::cerr << "===== LLIR Before Running Graph Coloring Register Allocation " << MFunc->getName() << " =====\n"; + std::stringstream ss_before_reg_alloc; + if (DEBUG) { + RISCv64AsmPrinter printer_reg_alloc(MFunc); + printer_reg_alloc.run(ss_before_reg_alloc, true); + std::cout << ss_before_reg_alloc.str(); } - // 阶段 1: 处理函数调用约定(参数寄存器预着色) - handleCallingConvention(); - // 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移) - eliminateFrameIndices(); - // 调试输出当前的LLIR状态 - { // 使用大括号创建一个局部作用域,避免printer变量泄露 - if (DEBUG) { - std::cerr << "\n===== LLIR after eliminateFrameIndices for function: " - << MFunc->getName() << " =====\n"; - // 1. 创建一个 AsmPrinter 实例,传入当前的 MachineFunction - RISCv64AsmPrinter printer(MFunc); - // 2. 调用 run 方法,将结果打印到标准错误流 (std::cerr) - // 3. 必须将 debug 参数设为 true! - // 因为此时指令中仍然包含虚拟寄存器 (%vreg), - // debug模式下的 AsmPrinter 才能正确处理它们而不会报错。 - printer.run(std::cerr, true); - std::cerr << "===== End of LLIR =====\n\n"; + if (DEBUG) std::cerr << "===== Running Graph Coloring Register Allocation for function: " << MFunc->getName() << " =====\n"; + + while (true) { + if (doAllocation()) { + break; + } else { + rewriteProgram(); + if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation ---\n"; } } - // 阶段 3: 活跃性分析 - analyzeLiveness(); - // 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响) - buildInterferenceGraph(); - // 阶段 5: 图着色算法分配物理寄存器 - colorGraph(); - // 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器) - rewriteFunction(); + applyColoring(); - // 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用 MFunc->getFrameInfo().vreg_to_preg_map = this->color_map; + collectUsedCalleeSavedRegs(); + if (DEBUG) std::cerr << "===== Finished Graph Coloring Register Allocation =====\n\n"; } -/** - * @brief 处理调用约定,预先为函数参数和调用返回值分配物理寄存器。 - * 这个函数现在负责处理调用约定的两个方面: - * 1. 作为被调用者(callee),如何接收传入的参数。 - * 2. 作为调用者(caller),如何接收调用的其他函数的返回值。 - */ -void RISCv64RegAlloc::handleCallingConvention() { - Function* F = MFunc->getFunc(); - RISCv64ISel* isel = MFunc->getISel(); - - // --- 部分1:处理函数传入参数的预着色 --- - if (F) { - auto& args = F->getArguments(); - - // [修改] 为整数参数和浮点参数分别维护索引 - int int_arg_idx = 0; - int float_arg_idx = 0; +// 单次分配的核心流程 +bool RISCv64RegAlloc::doAllocation() { + initialize(); + precolorByCallingConvention(); + analyzeLiveness(); + build(); + makeWorklist(); - 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) + while (!simplifyWorklist.empty() || !worklistMoves.empty() || !freezeWorklist.empty() || !spillWorklist.empty()) { + if (DEEPDEBUG) dumpState("Loop Start"); + if (!simplifyWorklist.empty()) simplify(); + else if (!worklistMoves.empty()) coalesce(); + else if (!freezeWorklist.empty()) freeze(); + else if (!spillWorklist.empty()) selectSpill(); + } + + if (DEEPDEBUG) dumpState("Before AssignColors"); + assignColors(); + return spilledNodes.empty(); +} + +void RISCv64RegAlloc::precolorByCallingConvention() { + // [新增] 在处理前,先清空颜色相关的状态,确保重试时不会出错 + color_map.clear(); + coloredNodes.clear(); + + 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(static_cast(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); + } + } else { // 整数或指针 + if (int_arg_idx < 8) { // a0-a7 auto preg = static_cast(static_cast(PhysicalReg::A0) + int_arg_idx); color_map[vreg] = preg; int_arg_idx++; @@ -134,877 +128,1184 @@ void RISCv64RegAlloc::handleCallingConvention() { for (auto& mbb : MFunc->getBlocks()) { for (auto& instr : mbb->getInstructions()) { if (instr->getOpcode() == RVOpcodes::CALL) { - // 根据协议,如果CALL有返回值,其目标vreg是第一个操作数 if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { auto reg_op = static_cast(instr->getOperands().front().get()); if (reg_op->isVirtual()) { unsigned ret_vreg = reg_op->getVRegNum(); - - // [修改] 检查返回值的类型,预着色到 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); + assert(vreg_to_value_map.count(ret_vreg) && "Return vreg not found!"); + Value* ret_val = vreg_to_value_map.at(ret_vreg); if (ret_val->getType()->isFloat()) { - // 浮点返回值预着色到 fa0 (F10) - color_map[ret_vreg] = PhysicalReg::F10; + color_map[ret_vreg] = PhysicalReg::F10; // fa0 } else { - // 整数/指针返回值预着色到 a0 - color_map[ret_vreg] = PhysicalReg::A0; + color_map[ret_vreg] = PhysicalReg::A0; // a0 } } } } } } -} - -/** - * @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。 - */ -void RISCv64RegAlloc::eliminateFrameIndices() { - StackFrameInfo& frame_info = MFunc->getFrameInfo(); - Function* F = MFunc->getFunc(); - RISCv64ISel* isel = MFunc->getISel(); - // 在处理局部变量前,首先为栈参数计算偏移量。 - if (F) { - int arg_idx = 0; - for (Argument* arg : F->getArguments()) { - // 我们只关心第8个索引及之后的参数(即第9个参数开始) - if (arg_idx >= 8) { - // 计算偏移量:第一个栈参数(idx=8)在0(s0),第二个(idx=9)在8(s0),以此类推。 - int offset = (arg_idx - 8) * 8; - unsigned vreg = isel->getVReg(arg); - - // 将这个vreg和它的栈偏移存入map。 - // 我们可以复用alloca_offsets,因为它们都代表“vreg到栈偏移”的映射。 - frame_info.alloca_offsets[vreg] = offset; - } - arg_idx++; - } + // 将所有预着色的vreg视为已着色节点 + for(const auto& pair : color_map) { + coloredNodes.insert(pair.first); } - - // [关键修改] 为局部变量分配空间时,起始点必须考虑为ra, s0以及所有callee-saved寄存器预留的空间。 - // 布局顺序为: [s0/ra, 16字节] -> [callee-saved, callee_saved_size字节] -> [局部变量...] - int local_var_offset = 16 + frame_info.callee_saved_size; - int locals_start_offset = local_var_offset; // 记录局部变量区域的起始点,用于计算总大小 - - // 处理局部变量 (AllocaInst) - for (auto& bb : F->getBasicBlocks()) { - for (auto& inst : bb->getInstructions()) { - if (auto alloca = dynamic_cast(inst.get())) { - Type* allocated_type = alloca->getType()->as()->getBaseType(); - int size = getTypeSizeInBytes(allocated_type); - - // RISC-V要求栈地址8字节对齐 - size = (size + 7) & ~7; - if (size == 0) size = 8; // 至少分配8字节 - - local_var_offset += size; - unsigned alloca_vreg = isel->getVReg(alloca); - // 局部变量使用相对于s0的负向偏移 - frame_info.alloca_offsets[alloca_vreg] = -local_var_offset; - } - } - } - - // [修复] 正确计算并设置locals_size - // 它只应该包含由AllocaInst分配的局部变量的总大小。 - frame_info.locals_size = local_var_offset - locals_start_offset; - - // 遍历所有机器指令,将伪指令展开为真实指令 - for (auto& mbb : MFunc->getBlocks()) { - std::vector> new_instructions; - for (auto& instr_ptr : mbb->getInstructions()) { - RVOpcodes opcode = instr_ptr->getOpcode(); - - // --- MODIFICATION START: 处理区分宽度的伪指令 --- - if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D) { - // 确定要生成的真实加载指令是 lw 还是 ld - RVOpcodes real_load_op = (opcode == RVOpcodes::FRAME_LOAD_W) ? RVOpcodes::LW : RVOpcodes::LD; - - auto& operands = instr_ptr->getOperands(); - unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(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(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: lw/ld dest_vreg, 0(addr_vreg) - auto load_instr = std::make_unique(real_load_op); - load_instr->addOperand(std::make_unique(dest_vreg)); - load_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(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(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(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(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: flw dest_vreg, 0(addr_vreg) - auto load_instr = std::make_unique(real_load_op); - load_instr->addOperand(std::make_unique(dest_vreg)); - load_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(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; - - auto& operands = instr_ptr->getOperands(); - unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(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(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: sw/sd src_vreg, 0(addr_vreg) - auto store_instr = std::make_unique(real_store_op); - store_instr->addOperand(std::make_unique(src_vreg)); - store_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(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(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(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(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: fsw src_vreg, 0(addr_vreg) - auto store_instr = std::make_unique(real_store_op); - store_instr->addOperand(std::make_unique(src_vreg)); - store_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(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(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); - int offset = frame_info.alloca_offsets.at(alloca_vreg); - - // 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset` - auto addi = std::make_unique(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(dest_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - } else { - new_instructions.push_back(std::move(instr_ptr)); - } - // --- MODIFICATION END --- - } - mbb->getInstructions() = std::move(new_instructions); + if (DEEPDEBUG) { + std::cerr << "Precolored registers: { "; + // 修改部分:将物理寄存器ID转换为其字符串名称 + for (unsigned v : precolored) std::cerr << regIdToString(v) << " "; + std::cerr << "}\nColored nodes: { "; + for (unsigned v : coloredNodes) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; } } -/** - * @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。 - * 这是活跃性分析的基础。 - * @param instr 要分析的机器指令。 - * @param use 存储 Use 寄存器(虚拟寄存器 ID)的集合。 - * @param def 存储 Def 寄存器(虚拟寄存器 ID)的集合。 - */ -void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) { - bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def) - auto opcode = instr->getOpcode(); +// 初始化/重置所有数据结构 +void RISCv64RegAlloc::initialize() { + initial.clear(); + simplifyWorklist.clear(); + freezeWorklist.clear(); + spillWorklist.clear(); + spilledNodes.clear(); + coalescedNodes.clear(); + coloredNodes.clear(); // [修正] 恢复对这两个集合的清除 + selectStack.clear(); - if (opcode == RVOpcodes::PSEUDO_KEEPALIVE) { - for (auto& op : instr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - if (reg_op->isVirtual()) { - use.insert(reg_op->getVRegNum()); // 它的所有操作数都是 "use" - } - } - } - return; // 处理完毕 - } + coalescedMoves.clear(); + constrainedMoves.clear(); + frozenMoves.clear(); + worklistMoves.clear(); + activeMoves.clear(); - // 1. 特殊指令的 `is_def` 标志调整 - // 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。 - 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 || - opcode == RVOpcodes::RET || opcode == RVOpcodes::J) { - first_reg_is_def = false; - } - - // JAL 和 JALR 指令定义 ra (x1) - if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) { - // 使用 ra 对应的特殊虚拟寄存器ID - def.insert(preg_to_vreg_id_map.at(PhysicalReg::RA)); - first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra,已经处理为 def - } - - // 2. CALL 指令的特殊处理 - if (opcode == RVOpcodes::CALL) { - // 根据 s1 分支 ISel 定义的协议来解析操作数列表 - bool first_reg_operand_is_def = true; - for (auto& op : instr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - if (reg_op->isVirtual()) { - // 协议:第一个寄存器操作数是返回值 (def) - if (first_reg_operand_is_def) { - def.insert(reg_op->getVRegNum()); - first_reg_operand_is_def = false; - } else { - // 后续所有寄存器操作数都是参数 (use) - use.insert(reg_op->getVRegNum()); - } - } else { // [修复] CALL指令也可能定义物理寄存器(如a0) - if (first_reg_operand_is_def) { - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - def.insert(it->second); - } - first_reg_operand_is_def = false; - } else { - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - } - } - } - 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(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(operands[1].get()); - if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum()); - } - if (operands[2]->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(operands[2].get()); - if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum()); - } - return; // 处理完毕 - } - - // 3. 对其他所有指令的通用处理逻辑 [已重构和修复] - for (const auto& op : instr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - - if (first_reg_is_def) { - // --- 处理定义(Def) --- - if (reg_op->isVirtual()) { - def.insert(reg_op->getVRegNum()); - } else { // 物理寄存器也可以是 Def - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - def.insert(it->second); - } - } - first_reg_is_def = false; // **关键**:处理完第一个寄存器后,立即更新标志 - } else { - // --- 处理使用(Use) --- - if (reg_op->isVirtual()) { - use.insert(reg_op->getVRegNum()); - } else { // 物理寄存器也可以是 Use - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - } - } else if (op->getKind() == MachineOperand::KIND_MEM) { - // 内存操作数的处理逻辑看起来是正确的 - auto mem_op = static_cast(op.get()); - auto base_reg = mem_op->getBase(); - if (base_reg->isVirtual()) { - use.insert(base_reg->getVRegNum()); - } else { - PhysicalReg preg = base_reg->getPReg(); - auto it = preg_to_vreg_id_map.find(preg); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - - // 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use` - 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(instr->getOperands().front().get()); - if (src_reg_op->isVirtual()) { - use.insert(src_reg_op->getVRegNum()); - } else { - auto it = preg_to_vreg_id_map.find(src_reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - } - } - } -} - -/** - * @brief 计算一个类型在内存中占用的字节数。 - * @param type 需要计算大小的IR类型。 - * @return 该类型占用的字节数。 - */ -unsigned RISCv64RegAlloc::getTypeSizeInBytes(Type* type) { - if (!type) { - assert(false && "Cannot get size of a null type."); - return 0; - } - - switch (type->getKind()) { - // 对于SysY语言,基本类型int和float都占用4字节 - case Type::kInt: - case Type::kFloat: - return 4; - - // 指针类型在RISC-V 64位架构下占用8字节 - // 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型 - case Type::kPointer: - return 8; - - // 数组类型的总大小 = 元素数量 * 单个元素的大小 - case Type::kArray: { - auto arrayType = type->as(); - // 递归调用以计算元素大小 - return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType()); - } - - // 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里 - default: - // 如果遇到未处理的类型,触发断言,方便调试 - assert(false && "Unsupported type for size calculation."); - return 0; - } + adjList.clear(); + degree.clear(); + moveList.clear(); + alias.clear(); + color_map.clear(); // [修正] 恢复对 color_map 的清除 } +// 活跃性分析(此部分为标准数据流分析,与现有版本类似但更精细) void RISCv64RegAlloc::analyzeLiveness() { - // === 阶段 1: 预计算每个基本块的 use 和 def 集合 === - // 这样可以避免在主循环中重复计算 - std::map block_uses; - std::map block_defs; - for (auto& mbb_ptr : MFunc->getBlocks()) { - MachineBasicBlock* mbb = mbb_ptr.get(); - LiveSet uses, defs; - for (auto& instr_ptr : mbb->getInstructions()) { - LiveSet instr_use, instr_def; - getInstrUseDef(instr_ptr.get(), instr_use, instr_def); - // use[B] = use[B] U (instr_use - def[B]) + live_in_map.clear(); + live_out_map.clear(); + + std::map block_uses; + std::map block_defs; + + for (const auto& mbb_ptr : MFunc->getBlocks()) { + const MachineBasicBlock* mbb = mbb_ptr.get(); + VRegSet uses, defs; + for (const auto& instr_ptr : mbb->getInstructions()) { + VRegSet instr_use, instr_def; + // 使用新的、能看到物理寄存器的版本 + getInstrUseDef_Liveness(instr_ptr.get(), instr_use, instr_def); for (unsigned u : instr_use) { - if (defs.find(u) == defs.end()) { - uses.insert(u); - } + 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 block_live_in; - std::map block_live_out; bool changed = true; + std::map live_in, live_out; while (changed) { changed = false; - // 以逆后序遍历基本块,可以加速收敛,但简单的逆序对于大多数情况也有效 for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) { - auto& mbb = *it; - - // 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S] - LiveSet new_live_out; + const auto& mbb_ptr = *it; + const MachineBasicBlock* mbb = mbb_ptr.get(); + VRegSet new_out; for (auto succ : mbb->successors) { - new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end()); + new_out.insert(live_in[succ].begin(), 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[mbb.get()]) { - live_out_minus_def.erase(d); - } - LiveSet new_live_in = block_uses[mbb.get()]; - new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end()); - - // 2.3 检查 live_in 和 live_out 是否变化,以判断是否达到不动点 - if (block_live_out[mbb.get()] != new_live_out) { + VRegSet new_in = block_uses[mbb]; + VRegSet out_minus_def = new_out; + for (unsigned d : block_defs[mbb]) out_minus_def.erase(d); + new_in.insert(out_minus_def.begin(), out_minus_def.end()); + if (live_out[mbb] != new_out || live_in[mbb] != new_in) { changed = true; - block_live_out[mbb.get()] = new_live_out; - } - if (block_live_in[mbb.get()] != new_live_in) { - changed = true; - block_live_in[mbb.get()] = new_live_in; + live_out[mbb] = new_out; + live_in[mbb] = new_in; } } } - // === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map === - // 此时块级别的活跃信息已经稳定,我们只需遍历一次即可 - for (auto& mbb_ptr : MFunc->getBlocks()) { - MachineBasicBlock* mbb = mbb_ptr.get(); - LiveSet live_out = block_live_out[mbb]; // 从已收敛的块级 live_out 开始 - + for (const auto& mbb_ptr : MFunc->getBlocks()) { + const MachineBasicBlock* mbb = mbb_ptr.get(); + VRegSet current_live = live_out[mbb]; for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) { - MachineInstr* instr = instr_it->get(); - live_out_map[instr] = live_out; - - LiveSet use, def; - getInstrUseDef(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; + const MachineInstr* instr = instr_it->get(); + live_out_map[instr] = current_live; + VRegSet use, def; + // 使用新的、能看到物理寄存器的版本 + getInstrUseDef_Liveness(instr, use, def); + for(auto d : def) current_live.erase(d); + for(auto u : use) current_live.insert(u); + live_in_map[instr] = current_live; } } } -// 辅助函数,用于清晰地打印寄存器集合。可以放在 .cpp 文件的顶部。 -void RISCv64RegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os) { - os << " " << name << ": { "; - for (unsigned vreg : s) { - // 为了可读性,将物理寄存器对应的特殊ID进行转换 - if (vreg >= static_cast(sysy::PhysicalReg::PHYS_REG_START_ID)) { - os << "preg(" << (vreg - static_cast(sysy::PhysicalReg::PHYS_REG_START_ID)) << ") "; - } else { - os << "%vreg" << vreg << " "; - } - } - os << "}\n"; -} +// [最终修正] 包含了所有正确逻辑和您已有调试代码的完整版本 +void RISCv64RegAlloc::build() { + initial.clear(); + RISCv64AsmPrinter printer_inside_build(MFunc); + printer_inside_build.setStream(std::cerr); -void RISCv64RegAlloc::buildInterferenceGraph() { - std::set all_vregs; - // 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID - for (auto& mbb : MFunc->getBlocks()) { - for(auto& instr : mbb->getInstructions()) { - LiveSet use, def; - getInstrUseDef(instr.get(), use, def); - for(auto u : use) all_vregs.insert(u); - for(auto d : def) all_vregs.insert(d); - } - } - // 添加所有物理寄存器对应的特殊虚拟寄存器ID到all_vregs,作为干扰图节点 - for (auto preg : allocable_int_regs) { - all_vregs.insert(preg_to_vreg_id_map.at(preg)); - } + for (const auto& mbb_ptr : MFunc->getBlocks()) { + for (const auto& instr_ptr : mbb_ptr->getInstructions()) { + const MachineInstr* instr = instr_ptr.get(); + VRegSet use, def; + getInstrUseDef_Liveness(instr, use, def); - // 初始化干扰图邻接表 - for (auto vreg : all_vregs) { interference_graph[vreg] = {}; } - - // 创建一个临时的AsmPrinter用于打印指令,方便调试 - RISCv64AsmPrinter temp_printer(MFunc); - temp_printer.setStream(std::cerr); - - for (auto& mbb : MFunc->getBlocks()) { - if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n"; - for (auto& instr_ptr : mbb->getInstructions()) { - MachineInstr* instr = instr_ptr.get(); + // 调试输出 use 和 def if (DEEPDEBUG) { - // 打印当前正在处理的指令 - std::cerr << " Instr: "; - temp_printer.printInstruction(instr, true); // 使用 true 来打印虚拟寄存器 + std::cerr << "Instr:"; + printer_inside_build.printInstruction(instr_ptr.get(), true); + // 修改 lambda 以捕获 this 指针,从而可以调用成员函数 + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << " " << name << ": { "; + for(unsigned v : s) std::cerr << regIdToString(v) << " "; // 使用新函数 + std::cerr << "}\n"; + }; + print_set(def, "Def "); + print_set(use, "Use "); + } + + for (unsigned v : use) { + if (!coloredNodes.count(v)) { + initial.insert(v); + } else if (DEEPDEBUG) { + std::cerr << "Skipping %vreg" << v << " because it is in coloredNodes.\n"; + } + } + for (unsigned v : def) { + if (!coloredNodes.count(v)) { + initial.insert(v); + } else if (DEEPDEBUG) { + std::cerr << "Skipping %vreg" << v << " because it is in coloredNodes.\n"; + } + } + } + } + + if (DEEPDEBUG) { + std::cerr << "Initial set after build: { "; + for (unsigned v : initial) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + } + + for(unsigned vreg : initial) { + adjList[vreg] = {}; + degree[vreg] = 0; + moveList[vreg] = {}; + // alias[vreg] = vreg; + } + + for (const auto& mbb_ptr : MFunc->getBlocks()) { + if (DEEPDEBUG) std::cerr << "\n--- Building Graph for Basic Block: " << mbb_ptr->getName() << " ---\n"; + for (const auto& instr_ptr : mbb_ptr->getInstructions()) { + const MachineInstr* instr = instr_ptr.get(); + VRegSet use, def; + getInstrUseDef_Liveness(instr, use, def); + const VRegSet& live_out = live_out_map.at(instr); + + if (DEEPDEBUG) { + // 使用临时的 AsmPrinter 打印当前指令,便于观察 + RISCv64AsmPrinter temp_printer(MFunc); + temp_printer.setStream(std::cerr); + std::cerr << "Instr: "; + temp_printer.printInstruction(const_cast(instr), true); + + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << " " << name << ": { "; + for(unsigned v : s) std::cerr << regIdToString(v) << " "; // 使用新函数 + std::cerr << "}\n"; + }; + print_set(def, "Def "); + print_set(use, "Use "); + print_set(live_out, "Live_Out"); + std::cerr << " ----------------\n"; } - LiveSet def, use; - getInstrUseDef(instr, use, def); - const LiveSet& live_out = live_out_map.at(instr); + bool is_move = instr->getOpcode() == RVOpcodes::MV; - // [新增调试逻辑] 打印所有相关的寄存器集合 - if (DEEPDEBUG) { - printLiveSet(use, "Use ", std::cerr); - printLiveSet(def, "Def ", std::cerr); - printLiveSet(live_out, "Live_Out", std::cerr); // 这是我们最关心的信息 + if (is_move) { + worklistMoves.insert(instr); + VRegSet move_vregs; + for(const auto& op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + if(reg_op->isVirtual()) move_vregs.insert(reg_op->getVRegNum()); + } + } + for (unsigned vreg : move_vregs) { + moveList[vreg].insert(instr); + } } - // 标准干扰图构建:def 与 live_out 中的其他变量干扰 + // --- 规则 1: Def 与 Live_Out 变量干扰 --- + VRegSet live = live_out; + if (is_move) { + for (unsigned u : use) { + live.erase(u); + } + } for (unsigned d : def) { - for (unsigned l : live_out) { - if (d != l) { - // [新增调试逻辑] 打印添加的干扰边及其原因 - if (DEEPDEBUG && interference_graph[d].find(l) == interference_graph[d].end()) { - std::cerr << " Edge (Def-LiveOut): %vreg" << d << " <-> %vreg" << l << "\n"; - } - interference_graph[d].insert(l); - interference_graph[l].insert(d); - } + for (unsigned l : live) { + addEdge(d, l); } } - - // 所有在某一点上同时活跃的寄存器(即live_out集合中的所有成员), - // 它们之间必须两两互相干扰。 - // 这会根据我们修正后的 liveness 信息,在所有参数vreg之间构建一个完全图(clique)。 - std::vector 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); - } - } - - // 在非move指令中,def 与 use 互相干扰 - if (instr->getOpcode() != RVOpcodes::MV) { + + // --- [新增的关键逻辑] 规则 2: 对于非move指令,强制def和use互相干扰 --- + // 这可以防止指令内部的源寄存器被目标寄存器错误地覆盖 + if (!is_move) { for (unsigned d : def) { for (unsigned u : use) { - if (d != u) { - // [新增调试逻辑] 打印添加的干扰边及其原因 - if (DEEPDEBUG && interference_graph[d].find(u) == interference_graph[d].end()) { - std::cerr << " Edge (Def-Use) : %vreg" << d << " <-> %vreg" << u << "\n"; - } - interference_graph[d].insert(u); - interference_graph[u].insert(d); - } + addEdge(d, u); } } } - // *** 处理 CALL 指令的隐式 def *** - if (instr->getOpcode() == RVOpcodes::CALL) { - // 你的原始CALL调试信息 - if (DEEPDEBUG) { - std::string live_out_str; - for (unsigned vreg : live_out) { - live_out_str += "%vreg" + std::to_string(vreg) + " "; - } - std::cerr << "[DEEPDEBUG] buildInterferenceGraph: CALL instruction found. Live out set is: {" - << live_out_str << "}" << std::endl; - } - // CALL 指令会定义(杀死)所有调用者保存的寄存器。 - // 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。 - - // 辅助函数,用于判断一个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& 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); - - 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, Int): preg(" << static_cast(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); - } - } - } - } - - // --- 处理浮点寄存器干扰 --- - const std::vector& 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(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); - } - } - } + // --- 规则 3: Live_Out 集合内部形成完全图 --- + for (unsigned l1 : live_out) { + for (unsigned l2 : live_out) { + addEdge(l1, l2); } } - if (DEEPDEBUG) std::cerr << " ----------------\n"; } } } -void RISCv64RegAlloc::colorGraph() { - std::vector sorted_vregs; - for (auto const& [vreg, neighbors] : interference_graph) { - // 只为未预着色的虚拟寄存器排序和着色 - if (color_map.find(vreg) == color_map.end() && vreg < static_cast(PhysicalReg::PHYS_REG_START_ID)) { - sorted_vregs.push_back(vreg); +// 将节点放入初始工作列表 +void RISCv64RegAlloc::makeWorklist() { + for (unsigned n : initial) { + int K = isFPVReg(n) ? K_fp : K_int; + if (degree.count(n) == 0) { + std::cerr << "Error: degree not initialized for %vreg" << n << "\n"; + continue; + } + if (DEEPDEBUG) { + std::cerr << "Assigning %vreg" << n << " (degree=" << degree.at(n) + << ", moveRelated=" << moveRelated(n) << ")\n"; + } + if (degree.at(n) >= K) { + spillWorklist.insert(n); + } else if (moveRelated(n)) { + freezeWorklist.insert(n); + } else { + simplifyWorklist.insert(n); } } + if (DEEPDEBUG) std::cerr << "--------------------------------\n"; + initial.clear(); +} - // 排序 - std::sort(sorted_vregs.begin(), sorted_vregs.end(), [&](unsigned a, unsigned b) { - return interference_graph[a].size() > interference_graph[b].size(); - }); +// 简化阶段 +void RISCv64RegAlloc::simplify() { + unsigned n = *simplifyWorklist.begin(); + simplifyWorklist.erase(simplifyWorklist.begin()); + if (DEEPDEBUG) std::cerr << "[Simplify] Popped %vreg" << n << ", pushing to stack.\n"; + selectStack.push_back(n); + for (unsigned m : adjacent(n)) { + decrementDegree(m); + } +} - // [调试] 辅助函数,用于判断一个vreg是整数还是浮点类型,并打印详细诊断信息 - auto is_fp_vreg = [&](unsigned vreg) { +// 合并阶段 +void RISCv64RegAlloc::coalesce() { + const MachineInstr* move = *worklistMoves.begin(); + worklistMoves.erase(worklistMoves.begin()); + VRegSet use, def; + getInstrUseDef_Liveness(move, use, def); + unsigned x = getAlias(*def.begin()); + unsigned y = getAlias(*use.begin()); + unsigned u, v; + if (precolored.count(y)) { u = y; v = x; } else { u = x; v = y; } + + if (DEEPDEBUG) std::cerr << "[Coalesce] Processing move between " << regIdToString(x) + << " and " << regIdToString(y) << " (aliases " << regIdToString(u) + << ", " << regIdToString(v) << ").\n"; + + if (u == v) { + if (DEEPDEBUG) std::cerr << " -> Trivial coalesce (u == v).\n"; + coalescedMoves.insert(move); + addWorklist(u); + return; // 处理完毕,提前返回 + } + + if (isFPVReg(u) != isFPVReg(v)) { + if (DEEPDEBUG) std::cerr << " -> Constrained (type mismatch: " << regIdToString(u) << " is " + << (isFPVReg(u) ? "float" : "int") << ", " << regIdToString(v) << " is " + << (isFPVReg(v) ? "float" : "int") << ").\n"; + constrainedMoves.insert(move); + addWorklist(u); + addWorklist(v); + return; // 立即返回,不再进行后续检查 + } + + // --- 新的、拆分后的启发式检查逻辑 --- + + bool pre_interfere = adjList.at(v).count(u); + + if (pre_interfere) { + if (DEEPDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n"; + constrainedMoves.insert(move); + addWorklist(u); + addWorklist(v); + return; + } + + bool is_u_precolored = precolored.count(u); + bool can_coalesce = false; + + if (is_u_precolored) { + // --- 场景1:u是物理寄存器,使用 George 启发式 --- + if (DEEPDEBUG) std::cerr << " -> Trying George Heuristic (u is precolored)...\n"; + + // ==================== [展开的 std::all_of 逻辑] ==================== + + // 步骤 1: 独立调用 adjacent(v) 获取邻居集合 + VRegSet neighbors_of_v = adjacent(v); if (DEEPDEBUG) { - std::cout << " [Debug is_fp_vreg] Checking vreg" << vreg << ": "; + std::cerr << " - Neighbors of " << regIdToString(v) << " to check are (" << neighbors_of_v.size() << "): { "; + for (unsigned id : neighbors_of_v) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; } - if (vreg_to_value_map.count(vreg)) { - Value* val = vreg_to_value_map.at(vreg); - bool is_float = val->getType()->isFloat(); + + // 步骤 2: 使用显式的 for 循环来代替 std::all_of + bool george_ok = true; // 默认假设成功,任何一个邻居失败都会将此设为 false + for (unsigned t : neighbors_of_v) { if (DEEPDEBUG) { - std::cout << "Found in map. Value is '" << val->getName() - << "', Type is " << (is_float ? "FLOAT" : "INT") - << ". Returning " << (is_float ? "true" : "false") << ".\n"; + std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n"; + } + + // 步骤 3: 独立调用启发式函数 + bool heuristic_result = georgeHeuristic(t, u); + + if (DEEPDEBUG) { + std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n"; + } + + if (!heuristic_result) { + george_ok = false; // 只要有一个邻居不满足条件,整个检查就失败 + break; // 并且可以立即停止检查其他邻居 } - return is_float; } if (DEEPDEBUG) { - std::cout << "NOT found in vreg_to_value_map. Defaulting to INT. Returning false.\n"; + std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n"; } - // 对于ISel创建的、没有直接IR Value对应的临时vreg,默认其为整数类型。 - return false; - }; + // ================================================================= - // 着色 - for (unsigned vreg : sorted_vregs) { - std::set used_colors; - for (unsigned neighbor_id : interference_graph.at(vreg)) { - // 收集邻居颜色的逻辑保持不变 - if (color_map.count(neighbor_id)) { - used_colors.insert(color_map.at(neighbor_id)); - } - else if (neighbor_id >= static_cast(PhysicalReg::PHYS_REG_START_ID)) { - PhysicalReg neighbor_preg = static_cast(neighbor_id - static_cast(PhysicalReg::PHYS_REG_START_ID)); - used_colors.insert(neighbor_preg); - } + if (george_ok) { + can_coalesce = true; } + + } else { + // --- 场景2:u和v都是虚拟寄存器,使用 Briggs 启发式 --- + if (DEEPDEBUG) std::cerr << " -> Trying Briggs Heuristic (u and v are virtual)...\n"; - 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 briggs_ok = briggsHeuristic(u, v); + if (DEEPDEBUG) std::cerr << " - briggsHeuristic(" << regIdToString(u) << ", " << regIdToString(v) << ") -> " << (briggs_ok ? "OK" : "FAIL") << "\n"; + + if (briggs_ok) { + can_coalesce = true; } - - bool colored = false; - 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"; + } + + // --- 根据启发式结果进行最终决策 --- + + if (can_coalesce) { + if (DEEPDEBUG) std::cerr << " -> Heuristic OK. Combining " << regIdToString(v) << " into " << regIdToString(u) << ".\n"; + coalescedMoves.insert(move); + combine(u, v); + addWorklist(u); + } else { + if (DEEPDEBUG) std::cerr << " -> Heuristic failed. Adding to active moves.\n"; + activeMoves.insert(move); + } +} + +// 冻结阶段 +void RISCv64RegAlloc::freeze() { + unsigned u = *freezeWorklist.begin(); + freezeWorklist.erase(freezeWorklist.begin()); + if (DEEPDEBUG) std::cerr << "[Freeze] Freezing %vreg" << u << " and moving to simplify list.\n"; + simplifyWorklist.insert(u); + freezeMoves(u); +} + +// 选择溢出节点 +void RISCv64RegAlloc::selectSpill() { + auto it = std::max_element(spillWorklist.begin(), spillWorklist.end(), + [&](unsigned a, unsigned b){ return degree.at(a) < degree.at(b); }); + unsigned m = *it; + spillWorklist.erase(it); + if (DEEPDEBUG) std::cerr << "[Spill] Selecting %vreg" << m << " to spill.\n"; + simplifyWorklist.insert(m); + freezeMoves(m); +} + +void RISCv64RegAlloc::assignColors() { + if (DEEPDEBUG) std::cerr << "[AssignColors] Starting...\n"; + while (!selectStack.empty()) { + unsigned n = selectStack.back(); + selectStack.pop_back(); + bool is_fp = isFPVReg(n); + const auto& available_regs = is_fp ? allocable_fp_regs : allocable_int_regs; + std::set ok_colors(available_regs.begin(), available_regs.end()); + + // 遍历 n 的所有邻居 w + for (unsigned w : adjList.at(n)) { + unsigned w_alias = getAlias(w); + + // [关键修正] 邻居 w 可能是一个已着色的虚拟寄存器, + // 或者它本身就是一个物理寄存器。两种情况都要处理! + bool is_colored_vreg = coloredNodes.count(w_alias); + bool is_physical_reg = precolored.count(w_alias); + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + + if (is_colored_vreg || is_physical_reg) { + PhysicalReg neighbor_color; + if (is_colored_vreg) { + // 如果是已着色的vreg,从 color_map 获取它的颜色 + neighbor_color = color_map.at(w_alias); + } else { + // 如果是物理寄存器,它的ID就是它的颜色 + neighbor_color = static_cast(w_alias - offset); } - break; + ok_colors.erase(neighbor_color); } } - if (!colored) { - spilled_vregs.insert(vreg); - if (DEBUG) { - std::cout << " -> FAILED to color. Spilling.\n"; - } + + if (ok_colors.empty()) { + if (DEEPDEBUG) std::cerr << " -> No color for %vreg" << n << ". Spilling.\n"; + spilledNodes.insert(n); + } else { + PhysicalReg c = *ok_colors.begin(); + coloredNodes.insert(n); + color_map[n] = c; + if (DEEPDEBUG) std::cerr << " -> Colored %vreg" << n << " with " << regToString(c) << " (ID: " << static_cast(c) << ").\n"; + } + } + + // 为合并的节点上色(这部分逻辑是正确的) + for (unsigned n : coalescedNodes) { + unsigned root_alias = getAlias(n); + if (color_map.count(root_alias)) { + color_map[n] = color_map.at(root_alias); + if (DEEPDEBUG) std::cerr << " -> Coalesced " << regIdToString(n) << " gets color of alias " << regIdToString(root_alias) << ".\n"; + } else { + if (DEEPDEBUG) std::cerr << " -> No color for alias of %vreg" << n << ". Spilling.\n"; + spilledNodes.insert(n); } } } -void RISCv64RegAlloc::rewriteFunction() { +// 重写程序,插入溢出代码 +void RISCv64RegAlloc::rewriteProgram() { + // 1. 为溢出的旧vreg在栈上分配空间 (这部分逻辑不变) StackFrameInfo& frame_info = MFunc->getFrameInfo(); - int current_offset = frame_info.locals_size; + // locals_size, callee_saved_size等已经由之前的步骤或上一次运行计算好 + // 我们在此基础上累加溢出区大小 + int spill_base_offset = frame_info.locals_size + frame_info.callee_saved_size; - // --- 动态计算溢出槽大小 --- - // 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。 - for (unsigned vreg : spilled_vregs) { - // 从反向映射中查找 vreg 对应的 IR Value - assert(vreg_to_value_map.count(vreg) && "Spilled vreg not found in map!"); - Value* val = vreg_to_value_map.at(vreg); - - // 使用辅助函数获取类型大小 - int size = getTypeSizeInBytes(val->getType()); - - // 保持栈8字节对齐 - current_offset += size; - current_offset = (current_offset + 7) & ~7; + for (unsigned vreg : spilledNodes) { + if (frame_info.spill_offsets.count(vreg)) continue; // 如果已经分配过则跳过 - frame_info.spill_offsets[vreg] = -current_offset; + int size = 4; // 默认4字节 + if (isFPVReg(vreg)) { + size = 4; // float + } else if (vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isPointer()) { + size = 8; // pointer + } + + spill_base_offset += size; + spill_base_offset = (spill_base_offset + 7) & ~7; // 8字节对齐 + frame_info.spill_offsets[vreg] = spill_base_offset; } - 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 + frame_info.spill_size = spill_base_offset - (frame_info.locals_size + frame_info.callee_saved_size); + // 2. 遍历所有指令,为溢出vreg的use/def插入load/store,并使用新的临时虚拟寄存器 for (auto& mbb : MFunc->getBlocks()) { std::vector> new_instructions; + for (auto& instr_ptr : mbb->getInstructions()) { - LiveSet use, def; - getInstrUseDef(instr_ptr.get(), use, def); + // 对每条指令,记录其使用的旧vreg到新临时vreg的映射 + std::map vreg_remap; - // --- 为溢出的 '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); - - // 根据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; + // a. 为每个溢出的 use 操作数,在原指令前插入 load 指令 + VRegSet use, def; + getInstrUseDef_Liveness(instr_ptr.get(), use, def); // 假设此函数能正确处理operands + + for(auto& op : instr_ptr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual() && spilledNodes.count(reg_op->getVRegNum()) && use.count(reg_op->getVRegNum())) { + unsigned old_vreg = reg_op->getVRegNum(); + // 仅当还未为此vreg创建临时替身时才创建 + if (vreg_remap.find(old_vreg) == vreg_remap.end()) { + Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); + unsigned new_temp_vreg = ISel->getNewVReg(type); + vreg_remap[old_vreg] = new_temp_vreg; + + RVOpcodes load_op; + if (isFPVReg(old_vreg)) load_op = RVOpcodes::FLW; + else if (type->isPointer()) load_op = RVOpcodes::LD; + else load_op = RVOpcodes::LW; + + auto load = std::make_unique(load_op); + load->addOperand(std::make_unique(new_temp_vreg)); + load->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(-frame_info.spill_offsets.at(old_vreg)) // 偏移是相对于S0的负值 + )); + new_instructions.push_back(std::move(load)); + } } + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto reg_op = static_cast(op.get())->getBase(); + if (reg_op->isVirtual() && spilledNodes.count(reg_op->getVRegNum())) { + unsigned old_vreg = reg_op->getVRegNum(); + if (vreg_remap.find(old_vreg) == vreg_remap.end()) { + Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); + unsigned new_temp_vreg = ISel->getNewVReg(type); + vreg_remap[old_vreg] = new_temp_vreg; - int offset = frame_info.spill_offsets.at(vreg); - auto load = std::make_unique(load_op); - load->addOperand(std::make_unique(target_preg)); // 加载到专用溢出寄存器 - load->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(offset) - )); - new_instructions.push_back(std::move(load)); + RVOpcodes load_op = (type->isPointer()) ? RVOpcodes::LD : RVOpcodes::LW; + auto load = std::make_unique(load_op); + load->addOperand(std::make_unique(new_temp_vreg)); + load->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(-frame_info.spill_offsets.at(old_vreg)) + )); + new_instructions.push_back(std::move(load)); + } + } + } + } + + // b. 替换原指令中的操作数,并将其加入新指令列表 + for(auto& op : instr_ptr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + 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 reg_op = static_cast(op.get())->getBase(); + if (reg_op->isVirtual() && vreg_remap.count(reg_op->getVRegNum())) { + reg_op->setVRegNum(vreg_remap.at(reg_op->getVRegNum())); + } } } - new_instructions.push_back(std::move(instr_ptr)); - // --- 为溢出的 'def' 操作数插入正确的存储指令 --- - for (unsigned vreg : def) { - if (spilled_vregs.count(vreg)) { - assert(vreg_to_value_map.count(vreg)); - Value* val = vreg_to_value_map.at(vreg); - - // 根据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; - } + // c. 为每个溢出的 def 操作数,在原指令后插入 store 指令 + vreg_remap.clear(); // 清空映射,为def创建新的临时vreg + for(auto& op : new_instructions.back()->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual() && spilledNodes.count(reg_op->getVRegNum()) && def.count(reg_op->getVRegNum())) { + unsigned old_vreg = reg_op->getVRegNum(); + if (vreg_remap.find(old_vreg) == vreg_remap.end()) { + Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); + unsigned new_temp_vreg = ISel->getNewVReg(type); + vreg_remap[old_vreg] = new_temp_vreg; // 记录从old到new的映射 + + // 再次修改指令,将def的vreg也换成新的临时vreg + reg_op->setVRegNum(new_temp_vreg); - int offset = frame_info.spill_offsets.at(vreg); - auto store = std::make_unique(store_op); - store->addOperand(std::make_unique(src_preg)); // 从专用溢出寄存器存储 - store->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(offset) - )); - new_instructions.push_back(std::move(store)); - } + RVOpcodes store_op; + if (isFPVReg(old_vreg)) store_op = RVOpcodes::FSW; + else if (type->isPointer()) store_op = RVOpcodes::SD; + else store_op = RVOpcodes::SW; + + auto store = std::make_unique(store_op); + store->addOperand(std::make_unique(new_temp_vreg)); // 从新的临时vreg中存值 + store->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(-frame_info.spill_offsets.at(old_vreg)) + )); + // 在原指令之后插入store + new_instructions.push_back(std::move(store)); + } + } + } } } mbb->getInstructions() = std::move(new_instructions); } - // 最后的虚拟寄存器到物理寄存器的替换过程保持不变 + // 清空溢出节点集合,为下一次迭代分配做准备 + spilledNodes.clear(); +} + +/** + * @brief [最终修正] 获取一条指令完整的【虚拟】使用/定义寄存器集合 + * 这个函数将服务于图的构建(收集initial节点等)。 + */ +void RISCv64RegAlloc::getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def) { + auto opcode = instr->getOpcode(); + const auto& operands = instr->getOperands(); + + static const std::map, std::vector>> op_info = { + {RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}}, + {RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}}, + {RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}}, + {RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}}, + {RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}}, + {RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, {RVOpcodes::LB, {{0}, {}}}, + {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}}, + {RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}}, + {RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, {RVOpcodes::SB, {{}, {0, 1}}}, + {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}}, + {RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, {RVOpcodes::BEQ, {{}, {0, 1}}}, + {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}}, + {RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}}, + {RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}}, + {RVOpcodes::RET, {{}, {}}}, {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}}, + {RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}}, + {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}}, + {RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, + {RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}} + }; + + auto get_vreg_id_if_virtual = [&](const MachineOperand* op, VRegSet& s) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op); + if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum()); + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op); + auto reg_op = mem_op->getBase(); + if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum()); + } + }; + + if (op_info.count(opcode)) { + const auto& info = op_info.at(opcode); + for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def); + for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use); + for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use); + } else if (opcode == RVOpcodes::CALL) { + if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def); + for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use); + } +} + +/** + * @brief [新增] 获取一条指令完整的、包含物理寄存器的Use/Def集合 + * 这个新函数将专门服务于活跃性分析。 + */ +void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet& use, VRegSet& def) { + auto opcode = instr->getOpcode(); + const auto& operands = instr->getOperands(); + + static const std::map, std::vector>> op_info = { + {RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}}, + {RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}}, + {RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}}, + {RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}}, + {RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}}, + {RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, {RVOpcodes::LB, {{0}, {}}}, + {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}}, + {RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}}, + {RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, {RVOpcodes::SB, {{}, {0, 1}}}, + {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}}, + {RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, {RVOpcodes::BEQ, {{}, {0, 1}}}, + {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}}, + {RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}}, + {RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}}, + {RVOpcodes::RET, {{}, {static_cast(PhysicalReg::A0), static_cast(PhysicalReg::F10)}}}, + {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}}, {RVOpcodes::FMUL_S, {{0}, {1, 2}}}, + {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, + {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}}, + {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, {RVOpcodes::FMV_X_W, {{0}, {1}}}, + {RVOpcodes::FNEG_S, {{0}, {1}}} + }; + + const unsigned offset = static_cast(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(op); + return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast(reg_op->getPReg())); + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op); + auto reg_op = mem_op->getBase(); + return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast(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()) def.insert(get_any_reg_id(operands[idx].get())); + for (int idx : info.second) if (idx < operands.size()) use.insert(get_any_reg_id(operands[idx].get())); + for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) use.insert(get_any_reg_id(op.get())); + } 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(static_cast(preg)); + for (auto preg : getCallerSavedFpRegs()) def.insert(static_cast(preg)); + def.insert(static_cast(PhysicalReg::RA)); + } +} + +void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { + if (u == v) return; + + // 关键修正:只为虚拟寄存器(非预着色)更新邻接表和度数 + // 如果 u 是虚拟寄存器 + if (!precolored.count(u)) { + // 并且 u 和 v 之间还没有边 + if (adjList.at(u).find(v) == adjList.at(u).end()) { + adjList.at(u).insert(v); + degree.at(u)++; + } + } + + // 对称地,如果 v 是虚拟寄存器 + if (!precolored.count(v)) { + // 并且 v 和 u 之间还没有边 + if (adjList.at(v).find(u) == adjList.at(v).end()) { + adjList.at(v).insert(u); + degree.at(v)++; + } + } +} + +RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { + // 仅在 DEEPDEBUG 模式下启用详细日志 + if (DEEPDEBUG) { + // 使用 regIdToString 打印节点 n,无论是物理还是虚拟 + std::cerr << "\n[adjacent] >>>>> Executing for node " << regIdToString(n) << " <<<<<\n"; + } + + // 1. 如果节点 n 是物理寄存器,它没有邻接表,直接返回空集 + if (precolored.count(n)) { + if (DEEPDEBUG) { + std::cerr << "[adjacent] Node " << regIdToString(n) << " is precolored. Returning {}.\n"; + } + return {}; + } + + // 安全检查:确保 n 在 adjList 中存在,防止 map::at 崩溃 + if (adjList.count(n) == 0) { + if (DEEPDEBUG) { + std::cerr << "[adjacent] WARNING: Node " << regIdToString(n) << " not found in adjList. Returning {}.\n"; + } + return {}; + } + + // 2. 获取 n 在冲突图中的所有邻居 + VRegSet result = adjList.at(n); + + if (DEEPDEBUG) { + // 定义一个局部的 lambda 方便打印集合 + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << "[adjacent] " << name << " (" << s.size() << "): { "; + for (unsigned id : s) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + }; + print_set(result, "Initial full neighbors"); + } + + // 3. 过滤掉那些已经在 selectStack 或 coalescedNodes 中的邻居 + // 这些节点被认为是“已移除”的,不参与当前的启发式判断 + + // 3a. 从 selectStack 中移除 + VRegSet removed_from_stack; // 仅用于调试打印 + for (auto it = selectStack.rbegin(); it != selectStack.rend(); ++it) { + if (result.count(*it)) { + if (DEEPDEBUG) removed_from_stack.insert(*it); + result.erase(*it); + } + } + if (DEEPDEBUG && !removed_from_stack.empty()) { + std::cerr << "[adjacent] - Removed from selectStack: { "; + for(unsigned id : removed_from_stack) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + } + + // 3b. 从 coalescedNodes 中移除 + VRegSet removed_from_coalesced; // 仅用于调试打印 + for (unsigned cn : coalescedNodes) { + if (result.count(cn)) { + if (DEEPDEBUG) removed_from_coalesced.insert(cn); + result.erase(cn); + } + } + if (DEEPDEBUG && !removed_from_coalesced.empty()) { + std::cerr << "[adjacent] - Removed from coalescedNodes: { "; + for(unsigned id : removed_from_coalesced) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + } + + // 4. 返回最终的、过滤后的“有效”邻居集合 + if (DEEPDEBUG) { + std::cerr << "[adjacent] >>>>> Returning final adjacent set (" << result.size() << "): { "; + for (unsigned id : result) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n\n"; + } + + return result; +} + +RISCv64RegAlloc::VRegMoveSet RISCv64RegAlloc::nodeMoves(unsigned n) { + if (precolored.count(n) || !moveList.count(n)) { + return {}; + } + + VRegMoveSet result; + const VRegMoveSet& moves = moveList.at(n); + for (const auto& move : moves) { + if (activeMoves.count(move) || worklistMoves.count(move)) { + result.insert(move); + } + } + return result; +} + +bool RISCv64RegAlloc::moveRelated(unsigned n) { + return !nodeMoves(n).empty(); +} + +void RISCv64RegAlloc::decrementDegree(unsigned m) { + if (precolored.count(m)) { + return; + } + + int K = isFPVReg(m) ? K_fp : K_int; + int d = degree.at(m); + degree.at(m)--; + if (d == K) { + VRegSet nodes_to_enable = adjacent(m); + nodes_to_enable.insert(m); + enableMoves(nodes_to_enable); + spillWorklist.erase(m); + if (moveRelated(m)) { + freezeWorklist.insert(m); + } else { + simplifyWorklist.insert(m); + } + } +} + +void RISCv64RegAlloc::enableMoves(const VRegSet& nodes) { + for (unsigned n : nodes) { + VRegMoveSet moves = nodeMoves(n); + for (const auto& move : moves) { + if (activeMoves.count(move)) { + activeMoves.erase(move); + worklistMoves.insert(move); + } + } + } +} + +unsigned RISCv64RegAlloc::getAlias(unsigned n) { + if (precolored.count(n)) { + return n; + } + if (alias.count(n)) { + // 路径压缩 + alias.at(n) = getAlias(alias.at(n)); + return alias.at(n); + } + return n; +} + +void RISCv64RegAlloc::addWorklist(unsigned u) { + if (precolored.count(u)) return; + + int K = isFPVReg(u) ? K_fp : K_int; + if (!moveRelated(u) && degree.at(u) < K) { + freezeWorklist.erase(u); + simplifyWorklist.insert(u); + } +} + +// Briggs启发式 +bool RISCv64RegAlloc::briggsHeuristic(unsigned u, unsigned v) { + if (DEEPDEBUG) { + std::cerr << "\n[Briggs] >>>>> Checking coalesce between " << regIdToString(u) << " and " << regIdToString(v) << " <<<<<\n"; + } + + // 步骤 1: 分别获取 u 和 v 的邻居 + VRegSet u_adj = adjacent(u); + VRegSet v_adj = adjacent(v); + + // 步骤 2: 合并两个邻居集合 + VRegSet all_adj = u_adj; + all_adj.insert(v_adj.begin(), v_adj.end()); + + if (DEEPDEBUG) { + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << "[Briggs] " << name << " (" << s.size() << "): { "; + for (unsigned id : s) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + }; + print_set(u_adj, "Neighbors of u"); + print_set(v_adj, "Neighbors of v"); + print_set(all_adj, "Combined neighbors"); + } + + // 步骤 3: 遍历合并后的邻居集合,计算度数 >= K 的节点数量 + int k = 0; + if (DEEPDEBUG) std::cerr << "[Briggs] Checking significance of combined neighbors:\n"; + for (unsigned n : all_adj) { + // 关键修正:只考虑那些在工作集中的邻居节点 n + if (degree.count(n) > 0) { + int K = isFPVReg(n) ? K_fp : K_int; + if (degree.at(n) >= K) { + k++; + if (DEEPDEBUG) { + std::cerr << "[Briggs] - Node " << regIdToString(n) << " is significant (degree " << degree.at(n) << " >= " << K << "). Count k is now " << k << ".\n"; + } + } + } + } + + // 步骤 4: 比较 "重要" 邻居的数量是否小于 K + int K_u = isFPVReg(u) ? K_fp : K_int; + bool result = (k < K_u); + + if (DEEPDEBUG) { + std::cerr << "[Briggs] Final count of significant neighbors (k) = " << k << ".\n"; + std::cerr << "[Briggs] K value for node " << regIdToString(u) << " is " << K_u << ".\n"; + std::cerr << "[Briggs] >>>>> Result (k < K): " << (result ? "OK (can coalesce)" : "FAIL (cannot coalesce)") << "\n\n"; + } + + return result; +} + +// George启发式 +bool RISCv64RegAlloc::georgeHeuristic(unsigned t, unsigned u) { + // 关键修正:如果 t 不是一个待分配的虚拟寄存器(即它是物理寄存器), + // 那么它已经被预着色,总是满足 George 启发式条件。 + // 我们通过检查 degree.count(t) 来判断 t 是否在我们的虚拟寄存器工作集中。 + if (degree.count(t) == 0) { + return true; + } + + int K = isFPVReg(t) ? K_fp : K_int; + // adjList.at(t) 现在是安全的,因为 degree.count(t) > 0 保证了 adjList.count(t) > 0 + return degree.at(t) < K || precolored.count(u) || adjList.at(t).count(u); +} + +void RISCv64RegAlloc::combine(unsigned u, unsigned v) { + freezeWorklist.erase(v); + spillWorklist.erase(v); + coalescedNodes.insert(v); + alias[v] = u; + if (moveList.count(u) && moveList.count(v)) { + moveList.at(u).insert(moveList.at(v).begin(), moveList.at(v).end()); + } else if (moveList.count(v)) { + moveList[u] = moveList.at(v); + } + enableMoves({v}); + for (unsigned t : adjacent(v)) { + addEdge(t, u); + decrementDegree(t); + } + int K = isFPVReg(u) ? K_fp : K_int; + if (degree.at(u) >= K && freezeWorklist.count(u)) { + freezeWorklist.erase(u); + spillWorklist.insert(u); + } +} + +void RISCv64RegAlloc::freezeMoves(unsigned u) { + if (precolored.count(u)) return; + + VRegMoveSet moves = nodeMoves(u); + for (const auto& move : moves) { + VRegSet use, def; + getInstrUseDef_Liveness(move, use, def); + unsigned x = *def.begin(); + unsigned y = *use.begin(); + unsigned v_alias; + + if (getAlias(y) == getAlias(u)) { + v_alias = getAlias(x); + } else { + v_alias = getAlias(y); + } + + activeMoves.erase(move); + frozenMoves.insert(move); + + if (!precolored.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) { + freezeWorklist.erase(v_alias); + simplifyWorklist.insert(v_alias); + } + } +} + +// 检查vreg是否为浮点类型 +bool RISCv64RegAlloc::isFPVReg(unsigned vreg) const { + // 1. 检查是否为虚拟寄存器 + if (vreg_type_map.count(vreg)) { + return vreg_type_map.at(vreg)->isFloat(); + } + + // 2. 检查是否为物理寄存器 (ID >= 100000) + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + if (vreg >= offset) { + // 先减去偏移,还原成原始的、小的枚举值 + unsigned raw_preg_id = vreg - offset; + + // 再用原始枚举值判断是否在浮点寄存器范围内 + if (raw_preg_id >= static_cast(PhysicalReg::F0) && raw_preg_id <= static_cast(PhysicalReg::F31)) { + return true; + } + } + + // 3. 其他所有情况(如未知的vreg,或整数物理寄存器)都默认为整数 + return false; +} + +// 收集被使用的被调用者保存寄存器 +void RISCv64RegAlloc::collectUsedCalleeSavedRegs() { + StackFrameInfo& frame_info = MFunc->getFrameInfo(); + frame_info.used_callee_saved_regs.clear(); + + const auto& callee_saved_int = getCalleeSavedIntRegs(); + const auto& callee_saved_fp = getCalleeSavedFpRegs(); + std::set callee_saved_set(callee_saved_int.begin(), callee_saved_int.end()); + callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end()); + // s0总是被使用作为帧指针 + callee_saved_set.insert(PhysicalReg::S0); + + + for(const auto& pair : color_map) { + PhysicalReg preg = pair.second; + if(callee_saved_set.count(preg)) { + frame_info.used_callee_saved_regs.insert(preg); + } + } +} + +/** + * @brief 将最终的寄存器分配结果应用到所有机器指令上。 + * 遍历所有操作数,将虚拟寄存器替换为分配到的物理寄存器。 + */ +void RISCv64RegAlloc::applyColoring() { for (auto& mbb : MFunc->getBlocks()) { for (auto& instr_ptr : mbb->getInstructions()) { for (auto& op_ptr : instr_ptr->getOperands()) { - // 定义一个处理寄存器操作数的 lambda 函数 - auto process_reg_op = [&](RegOperand* reg_op) { + if (op_ptr->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op_ptr.get()); + if (reg_op->isVirtual()) { + unsigned vreg = reg_op->getVRegNum(); + if (color_map.count(vreg)) { + // 使用 setPReg 将虚拟寄存器转换为物理寄存器 + reg_op->setPReg(color_map.at(vreg)); + } else { + // 如果一个vreg在成功分配后仍然没有颜色,这是一个错误 + std::cerr << "FATAL: Virtual register %vreg" << vreg << " has no color after allocation!\n"; + assert(false && "Virtual register has no color after allocation!"); + reg_op->setPReg(PhysicalReg::T6); + } + } + } else if (op_ptr->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op_ptr.get()); + auto reg_op = mem_op->getBase(); if (reg_op->isVirtual()) { unsigned vreg = reg_op->getVRegNum(); if (color_map.count(vreg)) { reg_op->setPReg(color_map.at(vreg)); - } else if (spilled_vregs.count(vreg)) { - // 根据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); - } + } else { + assert(false && "Virtual register in memory operand has no color!"); + reg_op->setPReg(PhysicalReg::T6); } } - }; - - if(op_ptr->getKind() == MachineOperand::KIND_REG) { - process_reg_op(static_cast(op_ptr.get())); - } else if (op_ptr->getKind() == MachineOperand::KIND_MEM) { - process_reg_op(static_cast(op_ptr.get())->getBase()); } } } } } +void RISCv64RegAlloc::dumpState(const std::string& stage) { + if (!DEEPDEBUG) return; + std::cerr << "\n=============== STATE DUMP (" << stage << ") ===============\n"; + auto print_vreg_set = [&](const VRegSet& s, const std::string& name){ + std::cerr << name << " (" << s.size() << "): { "; + for(unsigned v : s) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + }; + print_vreg_set(simplifyWorklist, "SimplifyWorklist"); + print_vreg_set(freezeWorklist, "FreezeWorklist"); + print_vreg_set(spillWorklist, "SpillWorklist"); + print_vreg_set(coalescedNodes, "CoalescedNodes"); + print_vreg_set(spilledNodes, "SpilledNodes"); + + std::cerr << "SelectStack (" << selectStack.size() << "): { "; + for(unsigned v : selectStack) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + + std::cerr << "WorklistMoves (" << worklistMoves.size() << ")\n"; + std::cerr << "ActiveMoves (" << activeMoves.size() << ")\n"; + + size_t final_nodes = coalescedNodes.size() + spilledNodes.size() + selectStack.size(); + std::cerr << "Total Final Nodes: " << final_nodes << "\n"; + std::cerr << "=======================================================\n"; +} + +std::string RISCv64RegAlloc::regToString(PhysicalReg reg) { + switch (reg) { + case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra"; + case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp"; + case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0"; + case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2"; + case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1"; + case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1"; + case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3"; + case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5"; + case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7"; + case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3"; + case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5"; + case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7"; + case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9"; + case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11"; + case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4"; + case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6"; + case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1"; + case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3"; + case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5"; + case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7"; + case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9"; + case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11"; + case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13"; + case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15"; + case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17"; + case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19"; + case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21"; + case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23"; + case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25"; + case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27"; + case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29"; + case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31"; + default: return "UNKNOWN_REG"; + } +} + +std::string RISCv64RegAlloc::regIdToString(unsigned id) { + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + + // 使用更健壮的检查方式 + if (id >= offset && precolored.count(id)) { + // 先减去偏移量,得到原始的、小的枚举值 + PhysicalReg reg = static_cast(id - offset); + // 再将原始枚举值传给 regToString + return regToString(reg); + } else { + return "%vreg" + std::to_string(id); + } +} + } // namespace sysy \ No newline at end of file diff --git a/src/include/backend/RISCv64/Handler/EliminateFrameIndices.h b/src/include/backend/RISCv64/Handler/EliminateFrameIndices.h new file mode 100644 index 0000000..155bdba --- /dev/null +++ b/src/include/backend/RISCv64/Handler/EliminateFrameIndices.h @@ -0,0 +1,20 @@ +#ifndef ELIMINATE_FRAME_INDICES_H +#define ELIMINATE_FRAME_INDICES_H + +#include "RISCv64LLIR.h" + +namespace sysy { + +class EliminateFrameIndicesPass { +public: + // Pass 的主入口函数 + void runOnMachineFunction(MachineFunction* mfunc); + +private: + // 帮助计算类型大小的辅助函数,从原RegAlloc中移出 + unsigned getTypeSizeInBytes(Type* type); +}; + +} // namespace sysy + +#endif // ELIMINATE_FRAME_INDICES_H \ No newline at end of file diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index be11528..2c2aec0 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -195,6 +195,11 @@ public: preg = new_preg; is_virtual = false; } + + void setVRegNum(unsigned new_vreg_num) { + vreg_num = new_vreg_num; + is_virtual = true; // 确保设置vreg时,操作数状态正确 + } private: unsigned vreg_num = 0; PhysicalReg preg = PhysicalReg::ZERO; @@ -280,8 +285,8 @@ struct StackFrameInfo { std::map alloca_offsets; // std::map spill_offsets; // <溢出vreg, 栈偏移> std::set used_callee_saved_regs; // 使用的保存寄存器 - std::map vreg_to_preg_map; - std::vector callee_saved_regs; // 用于存储需要保存的被调用者保存寄存器列表 + std::map vreg_to_preg_map; // [新增] RegAlloc最终的分配结果 + std::vector callee_saved_regs_to_store; // [新增] 已排序的、需要存取的被调用者保存寄存器 }; // 机器函数 diff --git a/src/include/backend/RISCv64/RISCv64Passes.h b/src/include/backend/RISCv64/RISCv64Passes.h index de08882..756be1d 100644 --- a/src/include/backend/RISCv64/RISCv64Passes.h +++ b/src/include/backend/RISCv64/RISCv64Passes.h @@ -8,6 +8,7 @@ #include "CalleeSavedHandler.h" #include "LegalizeImmediates.h" #include "PrologueEpilogueInsertion.h" +#include "EliminateFrameIndices.h" #include "Pass.h" namespace sysy { diff --git a/src/include/backend/RISCv64/RISCv64RegAlloc.h b/src/include/backend/RISCv64/RISCv64RegAlloc.h index 992aa5c..caf8149 100644 --- a/src/include/backend/RISCv64/RISCv64RegAlloc.h +++ b/src/include/backend/RISCv64/RISCv64RegAlloc.h @@ -1,8 +1,14 @@ +// in file: RISCv64RegAlloc.h + #ifndef RISCV64_REGALLOC_H #define RISCV64_REGALLOC_H #include "RISCv64LLIR.h" #include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型 +#include +#include +#include +#include extern int DEBUG; extern int DEEPDEBUG; @@ -17,58 +23,98 @@ public: void run(); private: - using LiveSet = std::set; // 活跃虚拟寄存器集合 - using InterferenceGraph = std::map>; + // 类型定义,与Python版本对应 + using VRegSet = std::set; + using InterferenceGraph = std::map; + using VRegStack = std::vector; // 使用vector模拟栈,方便遍历 + using MoveList = std::map>; + using AliasMap = std::map; + using ColorMap = std::map; + using VRegMoveSet = std::set; - // 栈帧管理 - void eliminateFrameIndices(); - - // 活跃性分析 + // --- 核心算法流程 --- + void initialize(); + void build(); + void makeWorklist(); + void simplify(); + void coalesce(); + void freeze(); + void selectSpill(); + void assignColors(); + void rewriteProgram(); + bool doAllocation(); + void applyColoring(); + + void dumpState(const std::string &stage); + + void precolorByCallingConvention(); + + // --- 辅助函数 --- + void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def); + void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def); + void addEdge(unsigned u, unsigned v); + VRegSet adjacent(unsigned n); + VRegMoveSet nodeMoves(unsigned n); + bool moveRelated(unsigned n); + void decrementDegree(unsigned m); + void enableMoves(const VRegSet& nodes); + unsigned getAlias(unsigned n); + void addWorklist(unsigned u); + bool briggsHeuristic(unsigned u, unsigned v); + bool georgeHeuristic(unsigned u, unsigned v); + void combine(unsigned u, unsigned v); + void freezeMoves(unsigned u); + void collectUsedCalleeSavedRegs(); + bool isFPVReg(unsigned vreg) const; + std::string regToString(PhysicalReg reg); + std::string regIdToString(unsigned id); + + // --- 活跃性分析 --- void analyzeLiveness(); - // 构建干扰图 - void buildInterferenceGraph(); - - // 图着色分配寄存器 - void colorGraph(); - - // 重写函数,替换vreg并插入溢出代码 - void rewriteFunction(); - - // 辅助函数,获取指令的Use/Def集合 - void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def); - - // 辅助函数,处理调用约定 - void handleCallingConvention(); - MachineFunction* MFunc; - - // 活跃性分析结果 - std::map live_in_map; - std::map live_out_map; + RISCv64ISel* ISel; - // 干扰图 - InterferenceGraph interference_graph; - - // 图着色结果 - std::map color_map; // vreg -> preg - std::set spilled_vregs; // 被溢出的vreg集合 - - // 可用的物理寄存器池 + // --- 算法数据结构 --- + // 寄存器池 std::vector allocable_int_regs; std::vector allocable_fp_regs; + int K_int; // 整数寄存器数量 + int K_fp; // 浮点寄存器数量 - // 存储vreg到IR Value*的反向映射 - // 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。 - std::map vreg_to_value_map; - std::map preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射 - - // 用于计算类型大小的辅助函数 - unsigned getTypeSizeInBytes(Type* type); + // 节点集合 + VRegSet precolored; // 预着色的节点 (物理寄存器) + VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点 + VRegSet simplifyWorklist; + VRegSet freezeWorklist; + VRegSet spillWorklist; + VRegSet spilledNodes; + VRegSet coalescedNodes; + VRegSet coloredNodes; + VRegStack selectStack; - // 辅助函数,用于打印集合 - static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os); + // Move指令相关 + std::set coalescedMoves; + std::set constrainedMoves; + std::set frozenMoves; + std::set worklistMoves; + std::set activeMoves; + + // 数据结构 + InterferenceGraph adjSet; + std::map adjList; // 邻接表 + std::map degree; + MoveList moveList; + AliasMap alias; + ColorMap color_map; + + // 活跃性分析结果 + std::map live_in_map; + std::map live_out_map; + // VReg -> Value* 和 VReg -> Type* 的映射 + const std::map& vreg_to_value_map; + const std::map& vreg_type_map; }; } // namespace sysy From f387aecc03a0e218001f0b00d5125a5d4f8d9583 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 02:47:40 +0800 Subject: [PATCH 02/10] =?UTF-8?q?[backend-IRC]=E8=BF=9B=E4=B8=80=E6=AD=A5?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E5=AF=84=E5=AD=98=E5=99=A8=E5=88=86=E9=85=8D?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RISCv64/Handler/CalleeSavedHandler.cpp | 98 ++----- .../Handler/PrologueEpilogueInsertion.cpp | 277 ++++++++++++------ src/backend/RISCv64/RISCv64Backend.cpp | 41 ++- src/backend/RISCv64/RISCv64LLIR.cpp | 118 +++++++- src/backend/RISCv64/RISCv64RegAlloc.cpp | 2 +- src/include/backend/RISCv64/RISCv64LLIR.h | 3 +- 6 files changed, 360 insertions(+), 179 deletions(-) diff --git a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp index b4cbc83..4ab73ea 100644 --- a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp +++ b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp @@ -8,10 +8,6 @@ namespace sysy { char CalleeSavedHandler::ID = 0; -static bool is_fp_reg(PhysicalReg reg) { - return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31; -} - bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) { // This pass works on MachineFunction level, not IR level return false; @@ -23,81 +19,33 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { if (used_callee_saved.empty()) { frame_info.callee_saved_size = 0; + frame_info.callee_saved_regs_to_store.clear(); return; } - // 1. 计算大小并排序,以便确定地生成代码 - frame_info.callee_saved_size = used_callee_saved.size() * 8; // 每个寄存器占8字节 - std::vector sorted_regs(used_callee_saved.begin(), used_callee_saved.end()); - std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){ return static_cast(a) < static_cast(b); }); - frame_info.callee_saved_regs_to_store = sorted_regs; // 保存排序后的列表 - - // 2. 在函数序言中插入保存指令 - MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); - auto& entry_instrs = entry_block->getInstructions(); - auto insert_pos = entry_instrs.begin(); - // 确保插入在任何栈分配指令之后,但在其他代码之前。 - // PrologueEpilogueInsertionPass 会处理最终顺序,这里我们先插入。 - - std::vector> save_instrs; - int current_offset = -16; // 栈布局: [ra, s0] 在最顶层,然后是callee-saved - - for (PhysicalReg reg : sorted_regs) { - // s0/fp 已经在序言中由 PrologueEpilogueInsertionPass 特殊处理,这里跳过 - if (reg == PhysicalReg::S0) continue; - - current_offset -= 8; - RVOpcodes save_op = is_fp_reg(reg) ? RVOpcodes::FSD : RVOpcodes::SD; - - auto save_instr = std::make_unique(save_op); - save_instr->addOperand(std::make_unique(reg)); - save_instr->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), // 基址为 SP - std::make_unique(0) // 偏移量将在PEI中修正 - )); - save_instrs.push_back(std::move(save_instr)); + // 1. 计算被调用者保存寄存器所需的总空间大小 + // s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中 + int size = 0; + std::set regs_to_save = used_callee_saved; + if (regs_to_save.count(PhysicalReg::S0)) { + regs_to_save.erase(PhysicalReg::S0); } + size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit) + frame_info.callee_saved_size = size; - if (!save_instrs.empty()) { - // 在序言的开头插入保存指令(PEI会后续调整它们的偏移) - entry_instrs.insert(insert_pos, - std::make_move_iterator(save_instrs.begin()), - std::make_move_iterator(save_instrs.end())); - } + // 2. 创建一个有序的、需要保存的寄存器列表,以便后续 Pass 确定地生成代码 + // s0 不应包含在此列表中,因为它由 PEI Pass 特殊处理 + std::vector sorted_regs(regs_to_save.begin(), regs_to_save.end()); + std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){ + return static_cast(a) < static_cast(b); + }); + frame_info.callee_saved_regs_to_store = sorted_regs; - // 3. 在函数结尾(ret之前)插入恢复指令 - for (auto& mbb : mfunc->getBlocks()) { - for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { - if ((*it)->getOpcode() == RVOpcodes::RET) { - std::vector> restore_instrs; - current_offset = -16; - - // 以相反的顺序恢复寄存器 - for (auto reg_it = sorted_regs.rbegin(); reg_it != sorted_regs.rend(); ++reg_it) { - PhysicalReg reg = *reg_it; - if (reg == PhysicalReg::S0) continue; - - current_offset -= 8; - RVOpcodes restore_op = is_fp_reg(reg) ? RVOpcodes::FLD : RVOpcodes::LD; - - auto restore_instr = std::make_unique(restore_op); - restore_instr->addOperand(std::make_unique(reg)); - restore_instr->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(0) // 偏移量同样由PEI修正 - )); - restore_instrs.push_back(std::move(restore_instr)); - } - - if (!restore_instrs.empty()) { - mbb->getInstructions().insert(it, - std::make_move_iterator(restore_instrs.begin()), - std::make_move_iterator(restore_instrs.end())); - } - goto next_block_label; - } - } - next_block_label:; - } + // 3. [关键修正] 更新栈帧总大小。 + // 这是初步计算,PEI Pass 会进行最终的对齐。 + frame_info.total_size = frame_info.locals_size + + frame_info.spill_size + + frame_info.callee_saved_size; } -} // namespace sysy \ No newline at end of file + +} // namespace sysy diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index 05532b7..86e3b30 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -1,6 +1,8 @@ #include "PrologueEpilogueInsertion.h" #include "RISCv64ISel.h" #include +#include +#include namespace sysy { @@ -8,7 +10,7 @@ char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { StackFrameInfo& frame_info = mfunc->getFrameInfo(); - + // 1. 删除 KEEPALIVE 伪指令 for (auto& mbb : mfunc->getBlocks()) { auto& instrs = mbb->getInstructions(); @@ -21,115 +23,200 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) instrs.end() ); } - - // 2. 计算最终的栈帧总大小 - // 总大小 = [ra, s0] + [被调用者保存寄存器] + [局部变量] + [溢出槽] + [调用其他函数的参数区] - // 假设调用参数区大小为0,因为它是在call指令周围动态分配和释放的 + + // 2. 计算最终的、对齐后的栈帧总大小 int total_stack_size = 16 + frame_info.callee_saved_size + frame_info.locals_size + frame_info.spill_size; - int aligned_stack_size = (total_stack_size + 15) & ~15; // 16字节对齐 + int aligned_stack_size = (total_stack_size + 15) & ~15; frame_info.total_size = aligned_stack_size; - // 只有在需要分配栈空间时才生成序言/尾声 - if (aligned_stack_size > 0) { - // --- 3. 插入序言 --- - MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); - auto& entry_instrs = entry_block->getInstructions(); - std::vector> prologue_instrs; + if (aligned_stack_size == 0) { + return; + } + + // --- 关键修正逻辑: 修正所有局部变量(即alloca)的偏移量 --- + // 这是最关键的一步,它解决了栈帧区域重叠的问题。 + // 在 EliminateFrameIndicesPass 运行时,它不知道 CalleeSavedHandler 后来会识别出 s1, s2 + // 并为其分配栈空间。因此,EliminateFrameIndicesPass 计算的偏移量是错误的。 + // 在这里,我们将偏移量向低地址方向整体移动,为 callee-saved 寄存器和溢出槽腾出空间。 + int callee_saved_and_spill_size = frame_info.callee_saved_size + frame_info.spill_size; + if (callee_saved_and_spill_size > 0) { + // 遍历所有局部变量的偏移量 Map,并进行修正 + for (auto& pair : mfunc->getFrameInfo().alloca_offsets) { + int old_offset = pair.second; // 初始偏移量(例如 -24) + int new_offset = old_offset - callee_saved_and_spill_size; + pair.second = new_offset; // 更新为修正后的偏移量 + } - // a. addi sp, sp, -aligned_stack_size - auto alloc_stack = std::make_unique(RVOpcodes::ADDI); - alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - alloc_stack->addOperand(std::make_unique(-aligned_stack_size)); - prologue_instrs.push_back(std::move(alloc_stack)); - - // b. sd ra, (aligned_stack_size - 8)(sp) - auto save_ra = std::make_unique(RVOpcodes::SD); - save_ra->addOperand(std::make_unique(PhysicalReg::RA)); - save_ra->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 8) - )); - prologue_instrs.push_back(std::move(save_ra)); - - // c. sd s0, (aligned_stack_size - 16)(sp) - auto save_fp = std::make_unique(RVOpcodes::SD); - save_fp->addOperand(std::make_unique(PhysicalReg::S0)); - save_fp->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 16) - )); - prologue_instrs.push_back(std::move(save_fp)); - - // d. addi s0, sp, aligned_stack_size - auto set_fp = std::make_unique(RVOpcodes::ADDI); - set_fp->addOperand(std::make_unique(PhysicalReg::S0)); - set_fp->addOperand(std::make_unique(PhysicalReg::SP)); - set_fp->addOperand(std::make_unique(aligned_stack_size)); - prologue_instrs.push_back(std::move(set_fp)); - - // 将序言指令插入到函数入口 - entry_instrs.insert(entry_instrs.begin(), - std::make_move_iterator(prologue_instrs.begin()), - std::make_move_iterator(prologue_instrs.end())); - - // --- 4. 插入尾声 --- + // 重新遍历函数中的所有指令,用修正后的偏移量替换旧的立即数 for (auto& mbb : mfunc->getBlocks()) { - for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { - if ((*it)->getOpcode() == RVOpcodes::RET) { - std::vector> epilogue_instrs; + for (auto& instr : mbb->getInstructions()) { + // 我们只修正那些使用立即数作为偏移量的内存访问指令 + if (instr->getOpcode() == RVOpcodes::ADDI) { + // ADDI 指令可能有 `addi rd, s0, offset` 的形式 + // 操作数是 [rd, s0, offset],我们需要检查第2个操作数(s0)并修改第3个(offset) + if (instr->getOperands().size() > 2) { + if (auto reg_op = dynamic_cast(instr->getOperands()[1].get())) { + if (reg_op->getPReg() == PhysicalReg::S0) { + if (auto imm_op = dynamic_cast(instr->getOperands()[2].get())) { + // ImmOperand 是不可变的, 所以我们创建一个新的来替换它 + int64_t old_imm = imm_op->getValue(); + instr->getOperands()[2] = std::make_unique(old_imm - callee_saved_and_spill_size); + } + } + } + } + } else if (instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::SD || + instr->getOpcode() == RVOpcodes::FLW || instr->getOpcode() == RVOpcodes::FSW || + instr->getOpcode() == RVOpcodes::FLD || instr->getOpcode() == RVOpcodes::FSD) { + // Load/Store 指令的操作数是 [rd, MemOperand] + // 我们需要检查 MemOperand 的基址寄存器是否为 s0 + if (instr->getOperands().size() > 1) { + if (auto mem_op = dynamic_cast(instr->getOperands()[1].get())) { + if (mem_op->getBase() && mem_op->getBase()->getPReg() == PhysicalReg::S0) { + // MemOperand 和 ImmOperand 都是不可变的, 我们必须重新构建整个 MemOperand + RegOperand* base_reg_op = mem_op->getBase(); + ImmOperand* offset_op = mem_op->getOffset(); - // a. ld ra - auto restore_ra = std::make_unique(RVOpcodes::LD); - restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); - restore_ra->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 8) - )); - epilogue_instrs.push_back(std::move(restore_ra)); + if (base_reg_op && offset_op) { + int64_t old_offset = offset_op->getValue(); + int64_t new_offset = old_offset - callee_saved_and_spill_size; - // b. ld s0 - auto restore_fp = std::make_unique(RVOpcodes::LD); - restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); - restore_fp->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 16) - )); - epilogue_instrs.push_back(std::move(restore_fp)); - - // c. addi sp, sp, aligned_stack_size - auto dealloc_stack = std::make_unique(RVOpcodes::ADDI); - dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - dealloc_stack->addOperand(std::make_unique(aligned_stack_size)); - epilogue_instrs.push_back(std::move(dealloc_stack)); - - mbb->getInstructions().insert(it, - std::make_move_iterator(epilogue_instrs.begin()), - std::make_move_iterator(epilogue_instrs.end())); - it++; // 跳过刚插入的指令和原有的RET - goto next_block; + // 重新创建基址寄存器操作数 (必须处理虚拟/物理寄存器) + std::unique_ptr new_base; + if (base_reg_op->isVirtual()) { + new_base = std::make_unique(base_reg_op->getVRegNum()); + } else { + new_base = std::make_unique(base_reg_op->getPReg()); + } + + // 创建新的偏移立即数操作数 + auto new_offset_imm = std::make_unique(new_offset); + + // 用新创建的 MemOperand 替换旧的 + instr->getOperands()[1] = std::make_unique(std::move(new_base), std::move(new_offset_imm)); + } + } + } + } } } - next_block:; } } - // --- 5. [新增] 修正所有基于S0的内存访问偏移量 --- - // CalleeSaved, Alloca, Spill 的偏移量都是相对于S0的负向偏移 + // --- 3. 插入完整的序言 --- + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + auto& entry_instrs = entry_block->getInstructions(); + std::vector> prologue_instrs; + + // a. addi sp, sp, -aligned_stack_size + auto alloc_stack = std::make_unique(RVOpcodes::ADDI); + alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + alloc_stack->addOperand(std::make_unique(-aligned_stack_size)); + prologue_instrs.push_back(std::move(alloc_stack)); + + // b. sd ra, (aligned_stack_size - 8)(sp) + auto save_ra = std::make_unique(RVOpcodes::SD); + save_ra->addOperand(std::make_unique(PhysicalReg::RA)); + save_ra->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 8) + )); + prologue_instrs.push_back(std::move(save_ra)); + + // c. sd s0, (aligned_stack_size - 16)(sp) + auto save_fp = std::make_unique(RVOpcodes::SD); + save_fp->addOperand(std::make_unique(PhysicalReg::S0)); + save_fp->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 16) + )); + prologue_instrs.push_back(std::move(save_fp)); + + // d. 保存所有其他的被调用者保存寄存器,并记录它们的偏移量 + std::map callee_saved_offsets; + int current_offset = aligned_stack_size - 16; + for (PhysicalReg reg : frame_info.callee_saved_regs_to_store) { + current_offset -= 8; + callee_saved_offsets[reg] = current_offset; // 记录偏移量 + RVOpcodes save_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD; + + auto save_reg = std::make_unique(save_op); + save_reg->addOperand(std::make_unique(reg)); + save_reg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(current_offset) + )); + prologue_instrs.push_back(std::move(save_reg)); + } + + // e. addi s0, sp, aligned_stack_size + auto set_fp = std::make_unique(RVOpcodes::ADDI); + set_fp->addOperand(std::make_unique(PhysicalReg::S0)); + set_fp->addOperand(std::make_unique(PhysicalReg::SP)); + set_fp->addOperand(std::make_unique(aligned_stack_size)); + prologue_instrs.push_back(std::move(set_fp)); + + entry_instrs.insert(entry_instrs.begin(), + std::make_move_iterator(prologue_instrs.begin()), + std::make_move_iterator(prologue_instrs.end())); + + // --- 4. 插入完整的尾声 --- for (auto& mbb : mfunc->getBlocks()) { - for (auto& instr : mbb->getInstructions()) { - if (instr->getOperands().empty() || instr->getOperands().back()->getKind() != MachineOperand::KIND_MEM) { - continue; + for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { + if ((*it)->getOpcode() == RVOpcodes::RET) { + std::vector> epilogue_instrs; + + // a. [关键修正] 恢复所有其他的被调用者保存寄存器 (以相反顺序) + const auto& regs_to_restore = frame_info.callee_saved_regs_to_store; + for (auto reg_it = regs_to_restore.rbegin(); reg_it != regs_to_restore.rend(); ++reg_it) { + PhysicalReg reg = *reg_it; + int offset = callee_saved_offsets.at(reg); // 使用之前记录的正确偏移量 + RVOpcodes restore_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD; + + auto restore_reg = std::make_unique(restore_op); + restore_reg->addOperand(std::make_unique(reg)); + restore_reg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(offset) + )); + epilogue_instrs.push_back(std::move(restore_reg)); + } + + // b. ld ra + auto restore_ra = std::make_unique(RVOpcodes::LD); + restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); + restore_ra->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 8) + )); + epilogue_instrs.push_back(std::move(restore_ra)); + + // c. ld s0 + auto restore_fp = std::make_unique(RVOpcodes::LD); + restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); + restore_fp->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 16) + )); + epilogue_instrs.push_back(std::move(restore_fp)); + + // d. addi sp, sp, aligned_stack_size + auto dealloc_stack = std::make_unique(RVOpcodes::ADDI); + dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + dealloc_stack->addOperand(std::make_unique(aligned_stack_size)); + epilogue_instrs.push_back(std::move(dealloc_stack)); + + mbb->getInstructions().insert(it, + std::make_move_iterator(epilogue_instrs.begin()), + std::make_move_iterator(epilogue_instrs.end())); + + goto next_block; } - auto mem_op = static_cast(instr->getOperands().back().get()); - if (mem_op->getBase()->isVirtual() || mem_op->getBase()->getPReg() != PhysicalReg::S0) { - continue; - } - // 此时所有基于S0的偏移量都是负数,无需再次调整 - // 之前的RegAlloc/CalleeSavedHandler已经计算好了正确的相对于S0的偏移 } + next_block:; } } -} // namespace sysy \ No newline at end of file +} // namespace sysy diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index 3841eec..477fe42 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -116,41 +116,70 @@ std::string RISCv64CodeGen::function_gen(Function* func) { // 第一次调试打印输出 std::stringstream ss_after_isel; + RISCv64AsmPrinter printer_isel(mfunc.get()); + printer_isel.run(ss_after_isel, true); + // if (DEBUG) { + // std::cout << ss_after_isel.str(); + // } + // DEBUG = 1; + // DEEPDEBUG = 1; if (DEBUG) { - RISCv64AsmPrinter printer_isel(mfunc.get()); - printer_isel.run(ss_after_isel, true); - std::cout << ss_after_isel.str(); + std::cerr << "====== Intermediate Representation after Instruction Selection ======\n" + << ss_after_isel.str(); } - + // DEBUG = 0; + // DEEPDEBUG = 0; // [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移) // 这个Pass必须在寄存器分配之前运行 EliminateFrameIndicesPass efi_pass; efi_pass.runOnMachineFunction(mfunc.get()); + if (DEBUG) { + std::cerr << "====== stack info after eliminate frame indices ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + // // 阶段 2: 指令调度 (Instruction Scheduling) // PreRA_Scheduler scheduler; // scheduler.runOnMachineFunction(mfunc.get()); + DEBUG = 0; + DEEPDEBUG = 0; // 阶段 3: 物理寄存器分配 (Register Allocation) RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); + // DEBUG = 1; + // DEEPDEBUG = 1; + if (DEBUG) { + std::cerr << "====== stack info after reg alloc ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + // 阶段 3.1: 处理被调用者保存寄存器 CalleeSavedHandler callee_handler; callee_handler.runOnMachineFunction(mfunc.get()); + if (DEBUG) { + std::cerr << "====== stack info after callee handler ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + // // 阶段 4: 窥孔优化 (Peephole Optimization) // PeepholeOptimizer peephole; // peephole.runOnMachineFunction(mfunc.get()); // 阶段 5: 局部指令调度 (Local Scheduling) - PostRA_Scheduler local_scheduler; - local_scheduler.runOnMachineFunction(mfunc.get()); + // PostRA_Scheduler local_scheduler; + // local_scheduler.runOnMachineFunction(mfunc.get()); // 阶段 3.2: 插入序言和尾声 PrologueEpilogueInsertionPass pei_pass; pei_pass.runOnMachineFunction(mfunc.get()); + DEBUG = 0; + DEEPDEBUG = 0; + // 阶段 3.3: 大立即数合法化 LegalizeImmediatesPass legalizer; legalizer.runOnMachineFunction(mfunc.get()); diff --git a/src/backend/RISCv64/RISCv64LLIR.cpp b/src/backend/RISCv64/RISCv64LLIR.cpp index 3816ad1..0a09d37 100644 --- a/src/backend/RISCv64/RISCv64LLIR.cpp +++ b/src/backend/RISCv64/RISCv64LLIR.cpp @@ -1,6 +1,122 @@ #include "RISCv64LLIR.h" #include +#include // 用于 std::ostream 和 std::cerr +#include // 用于 std::string namespace sysy { -} \ No newline at end of file +// 辅助函数:将 PhysicalReg 枚举转换为可读的字符串 +std::string regToString(PhysicalReg reg) { + switch (reg) { + case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra"; + case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp"; + case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0"; + case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2"; + case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1"; + case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1"; + case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3"; + case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5"; + case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7"; + case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3"; + case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5"; + case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7"; + case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9"; + case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11"; + case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4"; + case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6"; + case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1"; + case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3"; + case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5"; + case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7"; + case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9"; + case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11"; + case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13"; + case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15"; + case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17"; + case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19"; + case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21"; + case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23"; + case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25"; + case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27"; + case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29"; + case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31"; + default: return "UNKNOWN_REG"; + } +} + +// [新增] 打印栈帧信息的完整实现 +void MachineFunction::dumpStackFrameInfo(std::ostream& os) const { + const StackFrameInfo& info = frame_info; + + os << "--- Stack Frame Info for function '" << getName() << "' ---\n"; + + // 打印尺寸信息 + os << " Sizes:\n"; + os << " Total Size: " << info.total_size << " bytes\n"; + os << " Locals Size: " << info.locals_size << " bytes\n"; + os << " Spill Size: " << info.spill_size << " bytes\n"; + os << " Callee-Saved Size: " << info.callee_saved_size << " bytes\n"; + os << "\n"; + + // 打印 Alloca 变量的偏移量 + os << " Alloca Offsets (vreg -> offset from FP):\n"; + if (info.alloca_offsets.empty()) { + os << " (None)\n"; + } else { + for (const auto& pair : info.alloca_offsets) { + os << " %vreg" << pair.first << " -> " << pair.second << "\n"; + } + } + os << "\n"; + + // 打印溢出变量的偏移量 + os << " Spill Offsets (vreg -> offset from FP):\n"; + if (info.spill_offsets.empty()) { + os << " (None)\n"; + } else { + for (const auto& pair : info.spill_offsets) { + os << " %vreg" << pair.first << " -> " << pair.second << "\n"; + } + } + os << "\n"; + + // 打印使用的被调用者保存寄存器 + os << " Used Callee-Saved Registers:\n"; + if (info.used_callee_saved_regs.empty()) { + os << " (None)\n"; + } else { + os << " { "; + for (const auto& reg : info.used_callee_saved_regs) { + os << regToString(reg) << " "; + } + os << "}\n"; + } + os << "\n"; + + // 打印需要保存/恢复的被调用者保存寄存器 (有序) + os << " Callee-Saved Registers to Store/Restore:\n"; + if (info.callee_saved_regs_to_store.empty()) { + os << " (None)\n"; + } else { + os << " [ "; + for (const auto& reg : info.callee_saved_regs_to_store) { + os << regToString(reg) << " "; + } + os << "]\n"; + } + os << "\n"; + + // 打印最终的寄存器分配结果 + os << " Final Register Allocation Map (vreg -> preg):\n"; + if (info.vreg_to_preg_map.empty()) { + os << " (None)\n"; + } else { + for (const auto& pair : info.vreg_to_preg_map) { + os << " %vreg" << pair.first << " -> " << regToString(pair.second) << "\n"; + } + } + + os << "---------------------------------------------------\n"; +} + +} diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 64ff4ef..234bccf 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -1108,7 +1108,7 @@ void RISCv64RegAlloc::combine(unsigned u, unsigned v) { moveList[u] = moveList.at(v); } enableMoves({v}); - for (unsigned t : adjacent(v)) { + for (unsigned t : adjList.at(v)) { addEdge(t, u); decrementDegree(t); } diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index 2c2aec0..1931617 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -3,6 +3,7 @@ #include "IR.h" // 确保包含了您自己的IR头文件 #include +#include #include #include #include @@ -300,7 +301,7 @@ public: StackFrameInfo& getFrameInfo() { return frame_info; } const std::vector>& getBlocks() const { return blocks; } std::vector>& getBlocks() { return blocks; } - + void dumpStackFrameInfo(std::ostream& os = std::cerr) const; void addBlock(std::unique_ptr block) { blocks.push_back(std::move(block)); } From 873dbf64d08564cbf6a07796472d6edda453e380 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 04:44:13 +0800 Subject: [PATCH 03/10] =?UTF-8?q?[backend-IRC]=E5=9F=BA=E6=9C=AC=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E4=BA=86IRC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/RISCv64/RISCv64Backend.cpp | 6 +- src/backend/RISCv64/RISCv64RegAlloc.cpp | 261 +++++++++++++++++------- 2 files changed, 186 insertions(+), 81 deletions(-) diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index 477fe42..ae1beb6 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -121,6 +121,8 @@ std::string RISCv64CodeGen::function_gen(Function* func) { // if (DEBUG) { // std::cout << ss_after_isel.str(); // } + // DEBUG = 0; + // DEEPDEBUG = 0; // DEBUG = 1; // DEEPDEBUG = 1; if (DEBUG) { @@ -143,8 +145,8 @@ std::string RISCv64CodeGen::function_gen(Function* func) { // PreRA_Scheduler scheduler; // scheduler.runOnMachineFunction(mfunc.get()); - DEBUG = 0; - DEEPDEBUG = 0; + // DEBUG = 0; + // DEEPDEBUG = 0; // 阶段 3: 物理寄存器分配 (Register Allocation) RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 234bccf..763f401 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -255,20 +255,20 @@ void RISCv64RegAlloc::build() { RISCv64AsmPrinter printer_inside_build(MFunc); printer_inside_build.setStream(std::cerr); + // 1. 收集所有待分配的(既非物理也非预着色)虚拟寄存器到 initial 集合 for (const auto& mbb_ptr : MFunc->getBlocks()) { for (const auto& instr_ptr : mbb_ptr->getInstructions()) { const MachineInstr* instr = instr_ptr.get(); VRegSet use, def; getInstrUseDef_Liveness(instr, use, def); - // 调试输出 use 和 def + // 调试输出 use 和 def (保留您的调试逻辑) if (DEEPDEBUG) { std::cerr << "Instr:"; printer_inside_build.printInstruction(instr_ptr.get(), true); - // 修改 lambda 以捕获 this 指针,从而可以调用成员函数 auto print_set = [this](const VRegSet& s, const std::string& name) { std::cerr << " " << name << ": { "; - for(unsigned v : s) std::cerr << regIdToString(v) << " "; // 使用新函数 + for(unsigned v : s) std::cerr << regIdToString(v) << " "; std::cerr << "}\n"; }; print_set(def, "Def "); @@ -276,17 +276,26 @@ void RISCv64RegAlloc::build() { } for (unsigned v : use) { - if (!coloredNodes.count(v)) { + if (!coloredNodes.count(v) && !precolored.count(v)) { initial.insert(v); } else if (DEEPDEBUG) { - std::cerr << "Skipping %vreg" << v << " because it is in coloredNodes.\n"; + // 这里的调试信息可以更精确 + if (precolored.count(v)) { + std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; + } else { + std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register.\n"; + } } } for (unsigned v : def) { - if (!coloredNodes.count(v)) { + if (!coloredNodes.count(v) && !precolored.count(v)) { initial.insert(v); } else if (DEEPDEBUG) { - std::cerr << "Skipping %vreg" << v << " because it is in coloredNodes.\n"; + if (precolored.count(v)) { + std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; + } else { + std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register.\n"; + } } } } @@ -294,17 +303,25 @@ void RISCv64RegAlloc::build() { if (DEEPDEBUG) { std::cerr << "Initial set after build: { "; - for (unsigned v : initial) std::cerr << "%vreg" << v << " "; + for (unsigned v : initial) std::cerr << regIdToString(v) << " "; std::cerr << "}\n"; } - for(unsigned vreg : initial) { + // 2. 为所有参与图构建的虚拟寄存器(initial + coloredNodes)初始化数据结构 + VRegSet all_participating_vregs = initial; + all_participating_vregs.insert(coloredNodes.begin(), coloredNodes.end()); + + for (unsigned vreg : all_participating_vregs) { + // 物理寄存器ID不应作为key,此检查是安全的双重保障 + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + if (vreg >= offset) { + continue; + } adjList[vreg] = {}; degree[vreg] = 0; - moveList[vreg] = {}; - // alias[vreg] = vreg; } + // 3. 构建冲突图 for (const auto& mbb_ptr : MFunc->getBlocks()) { if (DEEPDEBUG) std::cerr << "\n--- Building Graph for Basic Block: " << mbb_ptr->getName() << " ---\n"; for (const auto& instr_ptr : mbb_ptr->getInstructions()) { @@ -313,8 +330,8 @@ void RISCv64RegAlloc::build() { getInstrUseDef_Liveness(instr, use, def); const VRegSet& live_out = live_out_map.at(instr); + // 保留您的指令级调试输出 if (DEEPDEBUG) { - // 使用临时的 AsmPrinter 打印当前指令,便于观察 RISCv64AsmPrinter temp_printer(MFunc); temp_printer.setStream(std::cerr); std::cerr << "Instr: "; @@ -322,7 +339,7 @@ void RISCv64RegAlloc::build() { auto print_set = [this](const VRegSet& s, const std::string& name) { std::cerr << " " << name << ": { "; - for(unsigned v : s) std::cerr << regIdToString(v) << " "; // 使用新函数 + for(unsigned v : s) std::cerr << regIdToString(v) << " "; std::cerr << "}\n"; }; print_set(def, "Def "); @@ -333,46 +350,54 @@ void RISCv64RegAlloc::build() { bool is_move = instr->getOpcode() == RVOpcodes::MV; + // 保留您处理 moveList 的逻辑 if (is_move) { worklistMoves.insert(instr); VRegSet move_vregs; - for(const auto& op : instr->getOperands()) { + for(const auto& op : instr->getOperands()) { if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - if(reg_op->isVirtual()) move_vregs.insert(reg_op->getVRegNum()); + auto reg_op = static_cast(op.get()); + if(reg_op->isVirtual()) move_vregs.insert(reg_op->getVRegNum()); } } for (unsigned vreg : move_vregs) { + // 使用 operator[] 是安全的,如果vreg不存在会默认构造 moveList[vreg].insert(instr); } } - // --- 规则 1: Def 与 Live_Out 变量干扰 --- VRegSet live = live_out; if (is_move) { - for (unsigned u : use) { - live.erase(u); - } - } - for (unsigned d : def) { - for (unsigned l : live) { - addEdge(d, l); + for (unsigned u_op : use) { + live.erase(u_op); } } - // --- [新增的关键逻辑] 规则 2: 对于非move指令,强制def和use互相干扰 --- - // 这可以防止指令内部的源寄存器被目标寄存器错误地覆盖 - if (!is_move) { - for (unsigned d : def) { - for (unsigned u : use) { - addEdge(d, u); + // --- 规则 1 & 2: Def 与 Live/Use 变量干扰 --- + for (unsigned d : def) { + // [关键修正] Def必须是虚拟寄存器 + if (precolored.count(d)) continue; + + for (unsigned l : live) { + addEdge(d, l); + } + + if (!is_move) { + for (unsigned u_op : use) { + addEdge(d, u_op); } } } + + // --- 规则 3: Live_Out 集合内部的【虚拟寄存器】形成完全图 --- + // [优化与修正] 使用更高效的遍历,避免重复调用 addEdge(A,B) 和 addEdge(B,A) + for (auto it1 = live_out.begin(); it1 != live_out.end(); ++it1) { + unsigned l1 = *it1; + // [关键修正] 只为虚拟寄存器 l1 添加边 + if (precolored.count(l1)) continue; - // --- 规则 3: Live_Out 集合内部形成完全图 --- - for (unsigned l1 : live_out) { - for (unsigned l2 : live_out) { + for (auto it2 = std::next(it1); it2 != live_out.end(); ++it2) { + unsigned l2 = *it2; addEdge(l1, l2); } } @@ -552,6 +577,8 @@ void RISCv64RegAlloc::selectSpill() { void RISCv64RegAlloc::assignColors() { if (DEEPDEBUG) std::cerr << "[AssignColors] Starting...\n"; + + // 步骤 1: 完整处理 selectStack while (!selectStack.empty()) { unsigned n = selectStack.back(); selectStack.pop_back(); @@ -559,12 +586,8 @@ void RISCv64RegAlloc::assignColors() { const auto& available_regs = is_fp ? allocable_fp_regs : allocable_int_regs; std::set ok_colors(available_regs.begin(), available_regs.end()); - // 遍历 n 的所有邻居 w for (unsigned w : adjList.at(n)) { unsigned w_alias = getAlias(w); - - // [关键修正] 邻居 w 可能是一个已着色的虚拟寄存器, - // 或者它本身就是一个物理寄存器。两种情况都要处理! bool is_colored_vreg = coloredNodes.count(w_alias); bool is_physical_reg = precolored.count(w_alias); const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); @@ -572,10 +595,8 @@ void RISCv64RegAlloc::assignColors() { if (is_colored_vreg || is_physical_reg) { PhysicalReg neighbor_color; if (is_colored_vreg) { - // 如果是已着色的vreg,从 color_map 获取它的颜色 neighbor_color = color_map.at(w_alias); } else { - // 如果是物理寄存器,它的ID就是它的颜色 neighbor_color = static_cast(w_alias - offset); } ok_colors.erase(neighbor_color); @@ -589,18 +610,28 @@ void RISCv64RegAlloc::assignColors() { PhysicalReg c = *ok_colors.begin(); coloredNodes.insert(n); color_map[n] = c; - if (DEEPDEBUG) std::cerr << " -> Colored %vreg" << n << " with " << regToString(c) << " (ID: " << static_cast(c) << ").\n"; + if (DEEPDEBUG) std::cerr << " -> Colored %vreg" << n << " with " << regToString(c) << ".\n"; } } - // 为合并的节点上色(这部分逻辑是正确的) + // 步骤 2: 独立、完整地处理 coalescedNodes for (unsigned n : coalescedNodes) { unsigned root_alias = getAlias(n); - if (color_map.count(root_alias)) { + + // 情况 1: 别名是物理寄存器,直接获得该颜色 + if (precolored.count(root_alias)) { + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + color_map[n] = static_cast(root_alias - offset); + if (DEEPDEBUG) std::cerr << " -> Coalesced " << regIdToString(n) << " gets color from physical alias " << regIdToString(root_alias) << ".\n"; + } + // 情况 2: 别名是虚拟寄存器,且在步骤1中已被成功着色 + else if (color_map.count(root_alias)) { color_map[n] = color_map.at(root_alias); - if (DEEPDEBUG) std::cerr << " -> Coalesced " << regIdToString(n) << " gets color of alias " << regIdToString(root_alias) << ".\n"; - } else { - if (DEEPDEBUG) std::cerr << " -> No color for alias of %vreg" << n << ". Spilling.\n"; + if (DEEPDEBUG) std::cerr << " -> Coalesced " << regIdToString(n) << " gets color of virtual alias " << regIdToString(root_alias) << ".\n"; + } + // 情况 3: 别名是虚拟寄存器,但在步骤1中未能着色(即被溢出) + else { + if (DEEPDEBUG) std::cerr << " -> Alias " << regIdToString(root_alias) << " of %vreg" << n << " was spilled. Spilling.\n"; spilledNodes.insert(n); } } @@ -798,14 +829,16 @@ void RISCv64RegAlloc::getInstrUseDef(const MachineInstr* instr, VRegSet& use, VR } /** - * @brief [新增] 获取一条指令完整的、包含物理寄存器的Use/Def集合 + * @brief [已修复] 获取一条指令完整的、包含物理寄存器的Use/Def集合 * 这个新函数将专门服务于活跃性分析。 */ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet& use, VRegSet& def) { auto opcode = instr->getOpcode(); const auto& operands = instr->getOperands(); + // 映射表:指令操作码 -> {Def操作数索引列表, Use操作数索引列表} static const std::map, std::vector>> op_info = { + // ===== 已有指令定义 (保留) ===== {RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}}, {RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}}, {RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}}, @@ -820,14 +853,42 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}}, {RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}}, - {RVOpcodes::RET, {{}, {static_cast(PhysicalReg::A0), static_cast(PhysicalReg::F10)}}}, - {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}}, {RVOpcodes::FMUL_S, {{0}, {1, 2}}}, - {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}}, {RVOpcodes::FLT_S, {{0}, {1, 2}}}, - {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}}, {RVOpcodes::FCVT_W_S, {{0}, {1}}}, - {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, {RVOpcodes::FMV_X_W, {{0}, {1}}}, - {RVOpcodes::FNEG_S, {{0}, {1}}} + {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}}, + {RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}}, + {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}}, + {RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, + {RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}}, + + // ===== 新增的指令定义开始 ===== + + // --- 逻辑指令 --- + {RVOpcodes::XOR, {{0}, {1, 2}}}, + {RVOpcodes::OR, {{0}, {1, 2}}}, + {RVOpcodes::AND, {{0}, {1, 2}}}, + {RVOpcodes::ORI, {{0}, {1}}}, + {RVOpcodes::ANDI, {{0}, {1}}}, + + // --- 移位指令 --- + {RVOpcodes::SLL, {{0}, {1, 2}}}, {RVOpcodes::SLLI, {{0}, {1}}}, + {RVOpcodes::SLLW, {{0}, {1, 2}}}, {RVOpcodes::SLLIW, {{0}, {1}}}, + {RVOpcodes::SRL, {{0}, {1, 2}}}, {RVOpcodes::SRLI, {{0}, {1}}}, + {RVOpcodes::SRLW, {{0}, {1, 2}}}, {RVOpcodes::SRLIW, {{0}, {1}}}, + {RVOpcodes::SRA, {{0}, {1, 2}}}, {RVOpcodes::SRAI, {{0}, {1}}}, + {RVOpcodes::SRAW, {{0}, {1, 2}}}, {RVOpcodes::SRAIW, {{0}, {1}}}, + + // --- 控制流指令 (补全) --- + {RVOpcodes::BLTU, {{}, {0, 1}}}, + {RVOpcodes::BGEU, {{}, {0, 1}}}, + // J 没有寄存器操作数,JAL 由CALL指令类似的特殊逻辑处理 + + // --- 伪指令 (补全) --- + {RVOpcodes::NEG, {{0}, {1}}}, + {RVOpcodes::NEGW, {{0}, {1}}}, + + // ===== 新增的指令定义结束 ===== }; + // 该lambda表达式用于获取操作数的寄存器ID(虚拟或物理),逻辑正确,保持不变 const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned { if (op->getKind() == MachineOperand::KIND_REG) { @@ -843,39 +904,78 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet if (op_info.count(opcode)) { const auto& info = op_info.at(opcode); - for (int idx : info.first) if (idx < operands.size()) def.insert(get_any_reg_id(operands[idx].get())); - for (int idx : info.second) if (idx < operands.size()) use.insert(get_any_reg_id(operands[idx].get())); - for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) use.insert(get_any_reg_id(op.get())); - } 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(static_cast(preg)); - for (auto preg : getCallerSavedFpRegs()) def.insert(static_cast(preg)); - def.insert(static_cast(PhysicalReg::RA)); + 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); + } + // 不要忘记内存操作数中的基址寄存器永远是use + 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); + } + } + } + // CALL 和 RET 的特殊处理逻辑,保持不变 + else if (opcode == RVOpcodes::CALL) { + // 返回值是Def + if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) { + def.insert(get_any_reg_id(operands[0].get())); + } + // 函数名后的所有寄存器参数都是Use + 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())); + } + } + // 所有调用者保存寄存器(caller-saved)被隐式定义(因为它们的值被破坏了) + for (auto preg : getCallerSavedIntRegs()) def.insert(offset + static_cast(preg)); + for (auto preg : getCallerSavedFpRegs()) def.insert(offset + static_cast(preg)); + // 返回地址寄存器RA也被隐式定义 + def.insert(offset + static_cast(PhysicalReg::RA)); + } + else if (opcode == RVOpcodes::RET) { + // 遵循调用约定,a0(整数/指针)和fa0(浮点)被隐式使用 + use.insert(offset + static_cast(PhysicalReg::A0)); + use.insert(offset + static_cast(PhysicalReg::F10)); // F10 is fa0 } } void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { if (u == v) return; - // 关键修正:只为虚拟寄存器(非预着色)更新邻接表和度数 - // 如果 u 是虚拟寄存器 - if (!precolored.count(u)) { - // 并且 u 和 v 之间还没有边 - if (adjList.at(u).find(v) == adjList.at(u).end()) { - adjList.at(u).insert(v); - degree.at(u)++; + // 检查两个节点是否都是虚拟寄存器 + if (!precolored.count(u) && !precolored.count(v)) { + // 只有当两个都是虚拟寄存器时,才为它们双方添加边和更新度数 + // 使用 operator[] 是安全的,如果键不存在,它会默认构造一个空的set + if (adjList[u].find(v) == adjList[u].end()) { + adjList[u].insert(v); + adjList[v].insert(u); + degree[u]++; + degree[v]++; } } - - // 对称地,如果 v 是虚拟寄存器 - if (!precolored.count(v)) { - // 并且 v 和 u 之间还没有边 - if (adjList.at(v).find(u) == adjList.at(v).end()) { - adjList.at(v).insert(u); - degree.at(v)++; + // 检查是否为 "虚拟-物理" 对 + else if (!precolored.count(u) && precolored.count(v)) { + // u是虚拟寄存器,v是物理寄存器,只更新u的邻接表和度数 + if (adjList[u].find(v) == adjList[u].end()) { + adjList[u].insert(v); + degree[u]++; } } + // 检查是否为 "物理-虚拟" 对 + else if (precolored.count(u) && !precolored.count(v)) { + // u是物理寄存器,v是虚拟寄存器,只更新v的邻接表和度数 + if (adjList[v].find(u) == adjList[v].end()) { + adjList[v].insert(u); + degree[v]++; + } + } + // 如果两个都是物理寄存器,则什么都不做,直接返回。 } RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { @@ -1112,10 +1212,13 @@ void RISCv64RegAlloc::combine(unsigned u, unsigned v) { addEdge(t, u); decrementDegree(t); } - int K = isFPVReg(u) ? K_fp : K_int; - if (degree.at(u) >= K && freezeWorklist.count(u)) { - freezeWorklist.erase(u); - spillWorklist.insert(u); + + if (!precolored.count(u)) { + int K = isFPVReg(u) ? K_fp : K_int; + if (degree.at(u) >= K && freezeWorklist.count(u)) { + freezeWorklist.erase(u); + spillWorklist.insert(u); + } } } From 166d0fc3721abfa955a84f115133ab067f387203 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 05:21:37 +0800 Subject: [PATCH 04/10] =?UTF-8?q?[backend-IRC]=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E6=A0=88=E4=BC=A0=E9=80=92=E5=8F=82=E6=95=B0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RISCv64/Handler/EliminateFrameIndices.cpp | 25 +- .../Handler/PrologueEpilogueInsertion.cpp | 358 +++++++++--------- 2 files changed, 181 insertions(+), 202 deletions(-) diff --git a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp index f2aa6fa..2dfa040 100644 --- a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp +++ b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp @@ -4,6 +4,7 @@ namespace sysy { +// getTypeSizeInBytes 是一个通用辅助函数,保持不变 unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) { if (!type) { assert(false && "Cannot get size of a null type."); @@ -31,25 +32,14 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { Function* F = mfunc->getFunc(); RISCv64ISel* isel = mfunc->getISel(); - // 1. 为栈传递的参数计算偏移量 - if (F) { - int arg_idx = 0; - for (Argument* arg : F->getArguments()) { - // 只关心第8个索引及之后的参数 (即第9个参数开始) - if (arg_idx >= 8) { - // 第一个栈参数(idx=8)在0(s0), 第二个(idx=9)在8(s0) - int offset = (arg_idx - 8) * 8; - unsigned vreg = isel->getVReg(arg); - frame_info.alloca_offsets[vreg] = offset; - } - arg_idx++; - } - } + // 1. [已移除] 不再处理栈传递的参数 + // 原先处理栈参数 (arg_idx >= 8) 的逻辑已被移除。 + // 这项职责已完全转移到 PrologueEpilogueInsertionPass,以避免逻辑冲突和错误。 - // 2. 为局部变量分配空间,起始点在 [ra, s0] (16字节) 之后 + // 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量 + // 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后 int local_var_offset = 16; - // 处理局部变量 (AllocaInst) if(F) { // 确保函数指针有效 for (auto& bb : F->getBasicBlocks()) { for (auto& inst : bb->getInstructions()) { @@ -73,7 +63,8 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { // 记录仅由AllocaInst分配的局部变量的总大小 frame_info.locals_size = local_var_offset - 16; - // 3. 遍历所有机器指令,将伪指令展开为真实指令 + // 3. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令 + // 由于处理参数的逻辑已移除,这里的展开现在只针对局部变量,因此是正确的。 for (auto& mbb : mfunc->getBlocks()) { std::vector> new_instructions; for (auto& instr_ptr : mbb->getInstructions()) { diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index 86e3b30..9a257d3 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -1,8 +1,9 @@ #include "PrologueEpilogueInsertion.h" +#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义 #include "RISCv64ISel.h" #include #include -#include +#include namespace sysy { @@ -10,8 +11,10 @@ char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { StackFrameInfo& frame_info = mfunc->getFrameInfo(); - - // 1. 删除 KEEPALIVE 伪指令 + Function* F = mfunc->getFunc(); + RISCv64ISel* isel = mfunc->getISel(); + + // 1. 清理 KEEPALIVE 伪指令 for (auto& mbb : mfunc->getBlocks()) { auto& instrs = mbb->getInstructions(); instrs.erase( @@ -23,200 +26,185 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) instrs.end() ); } + + // 2. [新增] 确定需要保存的被调用者保存寄存器 (callee-saved) + // 这部分逻辑从 CalleeSavedHandler Pass 移入,以集中管理序言生成 + auto& vreg_to_preg_map = frame_info.vreg_to_preg_map; + std::set used_callee_saved_regs_set; + const auto& callee_saved_int = getCalleeSavedIntRegs(); + const auto& callee_saved_fp = getCalleeSavedFpRegs(); - // 2. 计算最终的、对齐后的栈帧总大小 - int total_stack_size = 16 + frame_info.callee_saved_size + frame_info.locals_size + frame_info.spill_size; - int aligned_stack_size = (total_stack_size + 15) & ~15; + for (const auto& pair : vreg_to_preg_map) { + PhysicalReg preg = pair.second; + // 检查是否在整数或浮点 callee-saved 集合中 + // 注意:s0作为帧指针,由序言/尾声逻辑特殊处理,不在此处保存 + bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end(); + bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end(); + if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) { + used_callee_saved_regs_set.insert(preg); + } + } + // 为了确定性排序,并存入 frame_info 供尾声使用 + frame_info.callee_saved_regs_to_store.assign( + used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end() + ); + std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end()); + frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8; // 每个寄存器8字节 + + // 3. 计算最终的栈帧总大小 + int total_stack_size = frame_info.locals_size + + frame_info.spill_size + + frame_info.callee_saved_size + + 16; // 为 ra 和 s0 固定的16字节 + + int aligned_stack_size = (total_stack_size + 15) & ~15; // 16字节对齐 frame_info.total_size = aligned_stack_size; - if (aligned_stack_size == 0) { - return; - } - - // --- 关键修正逻辑: 修正所有局部变量(即alloca)的偏移量 --- - // 这是最关键的一步,它解决了栈帧区域重叠的问题。 - // 在 EliminateFrameIndicesPass 运行时,它不知道 CalleeSavedHandler 后来会识别出 s1, s2 - // 并为其分配栈空间。因此,EliminateFrameIndicesPass 计算的偏移量是错误的。 - // 在这里,我们将偏移量向低地址方向整体移动,为 callee-saved 寄存器和溢出槽腾出空间。 - int callee_saved_and_spill_size = frame_info.callee_saved_size + frame_info.spill_size; - if (callee_saved_and_spill_size > 0) { - // 遍历所有局部变量的偏移量 Map,并进行修正 - for (auto& pair : mfunc->getFrameInfo().alloca_offsets) { - int old_offset = pair.second; // 初始偏移量(例如 -24) - int new_offset = old_offset - callee_saved_and_spill_size; - pair.second = new_offset; // 更新为修正后的偏移量 - } + // 只有在需要分配栈空间时才生成序言和尾声 + if (aligned_stack_size > 0) { + // --- 4. 插入完整的序言 --- + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + auto& entry_instrs = entry_block->getInstructions(); + std::vector> prologue_instrs; - // 重新遍历函数中的所有指令,用修正后的偏移量替换旧的立即数 - for (auto& mbb : mfunc->getBlocks()) { - for (auto& instr : mbb->getInstructions()) { - // 我们只修正那些使用立即数作为偏移量的内存访问指令 - if (instr->getOpcode() == RVOpcodes::ADDI) { - // ADDI 指令可能有 `addi rd, s0, offset` 的形式 - // 操作数是 [rd, s0, offset],我们需要检查第2个操作数(s0)并修改第3个(offset) - if (instr->getOperands().size() > 2) { - if (auto reg_op = dynamic_cast(instr->getOperands()[1].get())) { - if (reg_op->getPReg() == PhysicalReg::S0) { - if (auto imm_op = dynamic_cast(instr->getOperands()[2].get())) { - // ImmOperand 是不可变的, 所以我们创建一个新的来替换它 - int64_t old_imm = imm_op->getValue(); - instr->getOperands()[2] = std::make_unique(old_imm - callee_saved_and_spill_size); - } - } - } - } - } else if (instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::SD || - instr->getOpcode() == RVOpcodes::FLW || instr->getOpcode() == RVOpcodes::FSW || - instr->getOpcode() == RVOpcodes::FLD || instr->getOpcode() == RVOpcodes::FSD) { - // Load/Store 指令的操作数是 [rd, MemOperand] - // 我们需要检查 MemOperand 的基址寄存器是否为 s0 - if (instr->getOperands().size() > 1) { - if (auto mem_op = dynamic_cast(instr->getOperands()[1].get())) { - if (mem_op->getBase() && mem_op->getBase()->getPReg() == PhysicalReg::S0) { - // MemOperand 和 ImmOperand 都是不可变的, 我们必须重新构建整个 MemOperand - RegOperand* base_reg_op = mem_op->getBase(); - ImmOperand* offset_op = mem_op->getOffset(); + // 4.1. 分配栈帧: addi sp, sp, -aligned_stack_size + auto alloc_stack = std::make_unique(RVOpcodes::ADDI); + alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + alloc_stack->addOperand(std::make_unique(-aligned_stack_size)); + prologue_instrs.push_back(std::move(alloc_stack)); - if (base_reg_op && offset_op) { - int64_t old_offset = offset_op->getValue(); - int64_t new_offset = old_offset - callee_saved_and_spill_size; - - // 重新创建基址寄存器操作数 (必须处理虚拟/物理寄存器) - std::unique_ptr new_base; - if (base_reg_op->isVirtual()) { - new_base = std::make_unique(base_reg_op->getVRegNum()); - } else { - new_base = std::make_unique(base_reg_op->getPReg()); - } - - // 创建新的偏移立即数操作数 - auto new_offset_imm = std::make_unique(new_offset); - - // 用新创建的 MemOperand 替换旧的 - instr->getOperands()[1] = std::make_unique(std::move(new_base), std::move(new_offset_imm)); - } - } - } - } - } - } - } - } - - // --- 3. 插入完整的序言 --- - MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); - auto& entry_instrs = entry_block->getInstructions(); - std::vector> prologue_instrs; - - // a. addi sp, sp, -aligned_stack_size - auto alloc_stack = std::make_unique(RVOpcodes::ADDI); - alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - alloc_stack->addOperand(std::make_unique(-aligned_stack_size)); - prologue_instrs.push_back(std::move(alloc_stack)); - - // b. sd ra, (aligned_stack_size - 8)(sp) - auto save_ra = std::make_unique(RVOpcodes::SD); - save_ra->addOperand(std::make_unique(PhysicalReg::RA)); - save_ra->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 8) - )); - prologue_instrs.push_back(std::move(save_ra)); - - // c. sd s0, (aligned_stack_size - 16)(sp) - auto save_fp = std::make_unique(RVOpcodes::SD); - save_fp->addOperand(std::make_unique(PhysicalReg::S0)); - save_fp->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 16) - )); - prologue_instrs.push_back(std::move(save_fp)); - - // d. 保存所有其他的被调用者保存寄存器,并记录它们的偏移量 - std::map callee_saved_offsets; - int current_offset = aligned_stack_size - 16; - for (PhysicalReg reg : frame_info.callee_saved_regs_to_store) { - current_offset -= 8; - callee_saved_offsets[reg] = current_offset; // 记录偏移量 - RVOpcodes save_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD; - - auto save_reg = std::make_unique(save_op); - save_reg->addOperand(std::make_unique(reg)); - save_reg->addOperand(std::make_unique( + // 4.2. 保存 ra 和 s0 + // sd ra, (aligned_stack_size - 8)(sp) + auto save_ra = std::make_unique(RVOpcodes::SD); + save_ra->addOperand(std::make_unique(PhysicalReg::RA)); + save_ra->addOperand(std::make_unique( std::make_unique(PhysicalReg::SP), - std::make_unique(current_offset) + std::make_unique(aligned_stack_size - 8) )); - prologue_instrs.push_back(std::move(save_reg)); - } + prologue_instrs.push_back(std::move(save_ra)); + // sd s0, (aligned_stack_size - 16)(sp) + auto save_fp = std::make_unique(RVOpcodes::SD); + save_fp->addOperand(std::make_unique(PhysicalReg::S0)); + save_fp->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 16) + )); + prologue_instrs.push_back(std::move(save_fp)); + + // 4.3. 设置新的帧指针 s0: addi s0, sp, aligned_stack_size + auto set_fp = std::make_unique(RVOpcodes::ADDI); + set_fp->addOperand(std::make_unique(PhysicalReg::S0)); + set_fp->addOperand(std::make_unique(PhysicalReg::SP)); + set_fp->addOperand(std::make_unique(aligned_stack_size)); + prologue_instrs.push_back(std::move(set_fp)); + + // 4.4. [新增] 保存所有使用到的被调用者保存寄存器 + // 它们保存在 s0 下方,紧接着 ra/s0 的位置 + int callee_saved_offset = -16; + for (const auto& reg : frame_info.callee_saved_regs_to_store) { + callee_saved_offset -= 8; + RVOpcodes store_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD; + auto save_cs_reg = std::make_unique(store_op); + save_cs_reg->addOperand(std::make_unique(reg)); + save_cs_reg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(callee_saved_offset) + )); + prologue_instrs.push_back(std::move(save_cs_reg)); + } - // e. addi s0, sp, aligned_stack_size - auto set_fp = std::make_unique(RVOpcodes::ADDI); - set_fp->addOperand(std::make_unique(PhysicalReg::S0)); - set_fp->addOperand(std::make_unique(PhysicalReg::SP)); - set_fp->addOperand(std::make_unique(aligned_stack_size)); - prologue_instrs.push_back(std::move(set_fp)); + // 4.5. [核心] 加载所有通过栈传递的参数 + // 这些参数位于 s0 上方 (正偏移量) + if (F && isel) { + int arg_idx = 0; + for (Argument* arg : F->getArguments()) { + if (arg_idx >= 8) { + unsigned vreg = isel->getVReg(arg); + if (vreg_to_preg_map.count(vreg)) { + // 计算正确的正偏移量 + int offset = (arg_idx - 8) * 8; + PhysicalReg dest_preg = vreg_to_preg_map.at(vreg); + Type* arg_type = arg->getType(); - entry_instrs.insert(entry_instrs.begin(), - std::make_move_iterator(prologue_instrs.begin()), - std::make_move_iterator(prologue_instrs.end())); - - // --- 4. 插入完整的尾声 --- - for (auto& mbb : mfunc->getBlocks()) { - for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { - if ((*it)->getOpcode() == RVOpcodes::RET) { - std::vector> epilogue_instrs; - - // a. [关键修正] 恢复所有其他的被调用者保存寄存器 (以相反顺序) - const auto& regs_to_restore = frame_info.callee_saved_regs_to_store; - for (auto reg_it = regs_to_restore.rbegin(); reg_it != regs_to_restore.rend(); ++reg_it) { - PhysicalReg reg = *reg_it; - int offset = callee_saved_offsets.at(reg); // 使用之前记录的正确偏移量 - RVOpcodes restore_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD; - - auto restore_reg = std::make_unique(restore_op); - restore_reg->addOperand(std::make_unique(reg)); - restore_reg->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(offset) - )); - epilogue_instrs.push_back(std::move(restore_reg)); + // 根据类型生成对应的加载指令 + RVOpcodes load_op = arg_type->isFloat() ? RVOpcodes::FLW : (arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW); + auto load_arg = std::make_unique(load_op); + load_arg->addOperand(std::make_unique(dest_preg)); + load_arg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(offset) + )); + prologue_instrs.push_back(std::move(load_arg)); + } } - - // b. ld ra - auto restore_ra = std::make_unique(RVOpcodes::LD); - restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); - restore_ra->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 8) - )); - epilogue_instrs.push_back(std::move(restore_ra)); - - // c. ld s0 - auto restore_fp = std::make_unique(RVOpcodes::LD); - restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); - restore_fp->addOperand(std::make_unique( - std::make_unique(PhysicalReg::SP), - std::make_unique(aligned_stack_size - 16) - )); - epilogue_instrs.push_back(std::move(restore_fp)); - - // d. addi sp, sp, aligned_stack_size - auto dealloc_stack = std::make_unique(RVOpcodes::ADDI); - dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); - dealloc_stack->addOperand(std::make_unique(aligned_stack_size)); - epilogue_instrs.push_back(std::move(dealloc_stack)); - - mbb->getInstructions().insert(it, - std::make_move_iterator(epilogue_instrs.begin()), - std::make_move_iterator(epilogue_instrs.end())); - - goto next_block; + arg_idx++; } } - next_block:; + + // 4.6. 将所有生成的序言指令一次性插入到函数入口 + entry_instrs.insert(entry_instrs.begin(), + std::make_move_iterator(prologue_instrs.begin()), + std::make_move_iterator(prologue_instrs.end())); + + // --- 5. 插入完整的尾声 --- + for (auto& mbb : mfunc->getBlocks()) { + // [修正] 使用前向迭代器查找RET指令,以确保在正确的位置(RET之前)插入尾声。 + for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { + if ((*it)->getOpcode() == RVOpcodes::RET) { + std::vector> epilogue_instrs; + + // 5.1. [新增] 恢复被调用者保存寄存器 + callee_saved_offset = -16; + for (const auto& reg : frame_info.callee_saved_regs_to_store) { + callee_saved_offset -= 8; + RVOpcodes load_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD; + auto restore_cs_reg = std::make_unique(load_op); + restore_cs_reg->addOperand(std::make_unique(reg)); + restore_cs_reg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(callee_saved_offset) + )); + epilogue_instrs.push_back(std::move(restore_cs_reg)); + } + + // 5.2. 恢复 ra 和 s0 (注意基址现在是sp) + // ld ra, (aligned_stack_size - 8)(sp) + auto restore_ra = std::make_unique(RVOpcodes::LD); + restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); + restore_ra->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 8) + )); + epilogue_instrs.push_back(std::move(restore_ra)); + // ld s0, (aligned_stack_size - 16)(sp) + auto restore_fp = std::make_unique(RVOpcodes::LD); + restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); + restore_fp->addOperand(std::make_unique( + std::make_unique(PhysicalReg::SP), + std::make_unique(aligned_stack_size - 16) + )); + epilogue_instrs.push_back(std::move(restore_fp)); + + // 5.3. 释放栈帧: addi sp, sp, aligned_stack_size + auto dealloc_stack = std::make_unique(RVOpcodes::ADDI); + dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); + dealloc_stack->addOperand(std::make_unique(aligned_stack_size)); + epilogue_instrs.push_back(std::move(dealloc_stack)); + + // 将尾声指令插入到 RET 指令之前 + mbb->getInstructions().insert(it, + std::make_move_iterator(epilogue_instrs.begin()), + std::make_move_iterator(epilogue_instrs.end())); + + // 一个基本块通常只有一个终止指令,处理完就可以跳到下一个块 + goto next_block; + } + } + next_block:; + } } } -} // namespace sysy +} // namespace sysy \ No newline at end of file From 8fe9867f33188dd541ecce5d41a3a6f88d10001c Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 12:15:03 +0800 Subject: [PATCH 05/10] =?UTF-8?q?[backend-IRC]=E4=BF=AE=E5=A4=8D=E4=BA=86k?= =?UTF-8?q?eepalive=E4=BC=AA=E6=8C=87=E4=BB=A4=E5=A4=84=E7=90=86=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RISCv64/Handler/EliminateFrameIndices.cpp | 52 ++- .../Handler/PrologueEpilogueInsertion.cpp | 30 +- src/backend/RISCv64/RISCv64Backend.cpp | 294 +++++++++---- src/backend/RISCv64/RISCv64RegAlloc.cpp | 388 +++++++++++------- 4 files changed, 494 insertions(+), 270 deletions(-) diff --git a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp index 2dfa040..6973293 100644 --- a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp +++ b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp @@ -1,6 +1,7 @@ #include "EliminateFrameIndices.h" #include "RISCv64ISel.h" #include +#include // [新增] 为插入指令而包含 namespace sysy { @@ -35,6 +36,8 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { // 1. [已移除] 不再处理栈传递的参数 // 原先处理栈参数 (arg_idx >= 8) 的逻辑已被移除。 // 这项职责已完全转移到 PrologueEpilogueInsertionPass,以避免逻辑冲突和错误。 + // [注释更新] -> 上述注释已过时。根据新方案,我们将在这里处理栈传递的参数, + // 以便在寄存器分配前就将数据流显式化,修复溢出逻辑的BUG。 // 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量 // 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后 @@ -63,8 +66,55 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { // 记录仅由AllocaInst分配的局部变量的总大小 frame_info.locals_size = local_var_offset - 16; - // 3. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令 + // 3. [核心修改] 在函数入口为所有栈传递的参数插入load指令 + // 这个步骤至关重要:它在寄存器分配之前,为这些参数的vreg创建了明确的“定义(def)”指令。 + // 这解决了在高寄存器压力下,当这些vreg被溢出时,`rewriteProgram`找不到其定义点而崩溃的问题。 + if (F && isel && !mfunc->getBlocks().empty()) { + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + std::vector> arg_load_instrs; + int arg_idx = 0; + for (Argument* arg : F->getArguments()) { + // 根据ABI,前8个整型/指针参数通过寄存器传递,这里只处理超出部分。 + if (arg_idx >= 8) { + // 计算参数在调用者栈帧中的位置,该位置相对于被调用者的帧指针s0是正向偏移。 + // 第9个参数(arg_idx=8)位于 0(s0),第10个(arg_idx=9)位于 8(s0),以此类推。 + int offset = (arg_idx - 8) * 8; + unsigned arg_vreg = isel->getVReg(arg); + Type* arg_type = arg->getType(); + + // 根据参数类型选择正确的加载指令 + RVOpcodes load_op; + if (arg_type->isFloat()) { + load_op = RVOpcodes::FLW; // 单精度浮点 + } else if (arg_type->isPointer()) { + load_op = RVOpcodes::LD; // 64位指针 + } else { + load_op = RVOpcodes::LW; // 32位整数 + } + + // 创建加载指令: lw/ld/flw vreg, offset(s0) + auto load_instr = std::make_unique(load_op); + load_instr->addOperand(std::make_unique(arg_vreg)); + load_instr->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), // 基址为帧指针 + std::make_unique(offset) + )); + arg_load_instrs.push_back(std::move(load_instr)); + } + arg_idx++; + } + + // 将所有新创建的参数加载指令一次性插入到入口块的起始位置 + auto& entry_instrs = entry_block->getInstructions(); + entry_instrs.insert(entry_instrs.begin(), + std::make_move_iterator(arg_load_instrs.begin()), + std::make_move_iterator(arg_load_instrs.end())); + } + + + // 4. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令 // 由于处理参数的逻辑已移除,这里的展开现在只针对局部变量,因此是正确的。 + // [注释更新] -> 上述注释已过时。此部分逻辑保持不变,它正确地处理了局部变量。 for (auto& mbb : mfunc->getBlocks()) { std::vector> new_instructions; for (auto& instr_ptr : mbb->getInstructions()) { diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index 9a257d3..ef86ea7 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -114,33 +114,9 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) prologue_instrs.push_back(std::move(save_cs_reg)); } - // 4.5. [核心] 加载所有通过栈传递的参数 - // 这些参数位于 s0 上方 (正偏移量) - if (F && isel) { - int arg_idx = 0; - for (Argument* arg : F->getArguments()) { - if (arg_idx >= 8) { - unsigned vreg = isel->getVReg(arg); - if (vreg_to_preg_map.count(vreg)) { - // 计算正确的正偏移量 - int offset = (arg_idx - 8) * 8; - PhysicalReg dest_preg = vreg_to_preg_map.at(vreg); - Type* arg_type = arg->getType(); - - // 根据类型生成对应的加载指令 - RVOpcodes load_op = arg_type->isFloat() ? RVOpcodes::FLW : (arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW); - auto load_arg = std::make_unique(load_op); - load_arg->addOperand(std::make_unique(dest_preg)); - load_arg->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(offset) - )); - prologue_instrs.push_back(std::move(load_arg)); - } - } - arg_idx++; - } - } + // 4.5. [核心修改] 加载栈传递参数的逻辑已从此移除 + // 这项工作已经前移至 `EliminateFrameIndicesPass` 中完成, + // 以确保在寄存器分配前就将相关虚拟寄存器定义,从而修复溢出逻辑的bug。 // 4.6. 将所有生成的序言指令一次性插入到函数入口 entry_instrs.insert(entry_instrs.begin(), diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index ae1beb6..dc9c089 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -108,94 +108,220 @@ std::string RISCv64CodeGen::module_gen() { } std::string RISCv64CodeGen::function_gen(Function* func) { - // === 完整的后端处理流水线 === - - // 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers) - RISCv64ISel isel; - std::unique_ptr mfunc = isel.runOnFunction(func); - - // 第一次调试打印输出 - std::stringstream ss_after_isel; - RISCv64AsmPrinter printer_isel(mfunc.get()); - printer_isel.run(ss_after_isel, true); - // if (DEBUG) { - // std::cout << ss_after_isel.str(); - // } - // DEBUG = 0; - // DEEPDEBUG = 0; - // DEBUG = 1; - // DEEPDEBUG = 1; if (DEBUG) { - std::cerr << "====== Intermediate Representation after Instruction Selection ======\n" - << ss_after_isel.str(); + // === 完整的后端处理流水线 === + + // 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers) + DEBUG = 0; + DEEPDEBUG = 0; + + RISCv64ISel isel; + std::unique_ptr mfunc = isel.runOnFunction(func); + + // 第一次调试打印输出 + std::stringstream ss_after_isel; + RISCv64AsmPrinter printer_isel(mfunc.get()); + printer_isel.run(ss_after_isel, true); + // if (DEBUG) { + // std::cout << ss_after_isel.str(); + // } + DEBUG = 0; + DEEPDEBUG = 0; + DEBUG = 1; + DEEPDEBUG = 1; + if (DEBUG) { + std::cerr << "====== Intermediate Representation after Instruction Selection ======\n" + << ss_after_isel.str(); + } + // DEBUG = 0; + // DEEPDEBUG = 0; + // [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移) + // 这个Pass必须在寄存器分配之前运行 + EliminateFrameIndicesPass efi_pass; + efi_pass.runOnMachineFunction(mfunc.get()); + + if (DEBUG) { + std::cerr << "====== stack info after eliminate frame indices ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + // std::stringstream ss_after_eli; + // printer_isel.run(ss_after_eli, true); + // std::cerr << "====== LLIR after eliminate frame indices ======\n" + // << ss_after_eli.str(); + } + + // // 阶段 2: 指令调度 (Instruction Scheduling) + // PreRA_Scheduler scheduler; + // scheduler.runOnMachineFunction(mfunc.get()); + + // DEBUG = 0; + // DEEPDEBUG = 0; + // DEBUG = 1; + // DEEPDEBUG = 1; + // 阶段 3: 物理寄存器分配 (Register Allocation) + RISCv64RegAlloc reg_alloc(mfunc.get()); + reg_alloc.run(); + + DEBUG = 0; + DEEPDEBUG = 0; + // DEBUG = 1; + // DEEPDEBUG = 1; + if (DEBUG) { + std::cerr << "====== stack info after reg alloc ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + + // 阶段 3.1: 处理被调用者保存寄存器 + CalleeSavedHandler callee_handler; + callee_handler.runOnMachineFunction(mfunc.get()); + + if (DEBUG) { + std::cerr << "====== stack info after callee handler ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + + // // 阶段 4: 窥孔优化 (Peephole Optimization) + // PeepholeOptimizer peephole; + // peephole.runOnMachineFunction(mfunc.get()); + + // 阶段 5: 局部指令调度 (Local Scheduling) + // PostRA_Scheduler local_scheduler; + // local_scheduler.runOnMachineFunction(mfunc.get()); + + // 阶段 3.2: 插入序言和尾声 + PrologueEpilogueInsertionPass pei_pass; + pei_pass.runOnMachineFunction(mfunc.get()); + + DEBUG = 0; + DEEPDEBUG = 0; + + // 阶段 3.3: 大立即数合法化 + LegalizeImmediatesPass legalizer; + legalizer.runOnMachineFunction(mfunc.get()); + + // 阶段 6: 代码发射 (Code Emission) + std::stringstream ss; + RISCv64AsmPrinter printer(mfunc.get()); + printer.run(ss); + + if (DEBUG) { + ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n" + << ss_after_isel.str(); + } + return ss.str(); } - // DEBUG = 0; - // DEEPDEBUG = 0; - // [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移) - // 这个Pass必须在寄存器分配之前运行 - EliminateFrameIndicesPass efi_pass; - efi_pass.runOnMachineFunction(mfunc.get()); + + + + + + + + + + + + + else { + // === 完整的后端处理流水线 === - if (DEBUG) { - std::cerr << "====== stack info after eliminate frame indices ======\n"; - mfunc->dumpStackFrameInfo(std::cerr); + // 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers) + DEBUG = 0; + DEEPDEBUG = 0; + + RISCv64ISel isel; + std::unique_ptr mfunc = isel.runOnFunction(func); + + // 第一次调试打印输出 + std::stringstream ss_after_isel; + RISCv64AsmPrinter printer_isel(mfunc.get()); + printer_isel.run(ss_after_isel, true); + // if (DEBUG) { + // std::cout << ss_after_isel.str(); + // } + DEBUG = 0; + DEEPDEBUG = 0; + // DEBUG = 1; + // DEEPDEBUG = 1; + if (DEBUG) { + std::cerr << "====== Intermediate Representation after Instruction Selection ======\n" + << ss_after_isel.str(); + } + // DEBUG = 0; + // DEEPDEBUG = 0; + // [新增] 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移) + // 这个Pass必须在寄存器分配之前运行 + EliminateFrameIndicesPass efi_pass; + efi_pass.runOnMachineFunction(mfunc.get()); + + if (DEBUG) { + std::cerr << "====== stack info after eliminate frame indices ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + std::stringstream ss_after_eli; + printer_isel.run(ss_after_eli, true); + std::cerr << "====== LLIR after eliminate frame indices ======\n" + << ss_after_eli.str(); + } + + // // 阶段 2: 指令调度 (Instruction Scheduling) + // PreRA_Scheduler scheduler; + // scheduler.runOnMachineFunction(mfunc.get()); + + DEBUG = 0; + DEEPDEBUG = 0; + // DEBUG = 1; + // DEEPDEBUG = 1; + // 阶段 3: 物理寄存器分配 (Register Allocation) + RISCv64RegAlloc reg_alloc(mfunc.get()); + reg_alloc.run(); + + DEBUG = 0; + DEEPDEBUG = 0; + // DEBUG = 1; + // DEEPDEBUG = 1; + if (DEBUG) { + std::cerr << "====== stack info after reg alloc ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + + // 阶段 3.1: 处理被调用者保存寄存器 + CalleeSavedHandler callee_handler; + callee_handler.runOnMachineFunction(mfunc.get()); + + if (DEBUG) { + std::cerr << "====== stack info after callee handler ======\n"; + mfunc->dumpStackFrameInfo(std::cerr); + } + + // // 阶段 4: 窥孔优化 (Peephole Optimization) + // PeepholeOptimizer peephole; + // peephole.runOnMachineFunction(mfunc.get()); + + // 阶段 5: 局部指令调度 (Local Scheduling) + // PostRA_Scheduler local_scheduler; + // local_scheduler.runOnMachineFunction(mfunc.get()); + + // 阶段 3.2: 插入序言和尾声 + PrologueEpilogueInsertionPass pei_pass; + pei_pass.runOnMachineFunction(mfunc.get()); + + DEBUG = 0; + DEEPDEBUG = 0; + + // 阶段 3.3: 大立即数合法化 + LegalizeImmediatesPass legalizer; + legalizer.runOnMachineFunction(mfunc.get()); + + // 阶段 6: 代码发射 (Code Emission) + std::stringstream ss; + RISCv64AsmPrinter printer(mfunc.get()); + printer.run(ss); + + if (DEBUG) { + ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n" + << ss_after_isel.str(); + } + return ss.str(); } - - // // 阶段 2: 指令调度 (Instruction Scheduling) - // PreRA_Scheduler scheduler; - // scheduler.runOnMachineFunction(mfunc.get()); - - // DEBUG = 0; - // DEEPDEBUG = 0; - // 阶段 3: 物理寄存器分配 (Register Allocation) - RISCv64RegAlloc reg_alloc(mfunc.get()); - reg_alloc.run(); - - // DEBUG = 1; - // DEEPDEBUG = 1; - if (DEBUG) { - std::cerr << "====== stack info after reg alloc ======\n"; - mfunc->dumpStackFrameInfo(std::cerr); - } - - // 阶段 3.1: 处理被调用者保存寄存器 - CalleeSavedHandler callee_handler; - callee_handler.runOnMachineFunction(mfunc.get()); - - if (DEBUG) { - std::cerr << "====== stack info after callee handler ======\n"; - mfunc->dumpStackFrameInfo(std::cerr); - } - - // // 阶段 4: 窥孔优化 (Peephole Optimization) - // PeepholeOptimizer peephole; - // peephole.runOnMachineFunction(mfunc.get()); - - // 阶段 5: 局部指令调度 (Local Scheduling) - // PostRA_Scheduler local_scheduler; - // local_scheduler.runOnMachineFunction(mfunc.get()); - - // 阶段 3.2: 插入序言和尾声 - PrologueEpilogueInsertionPass pei_pass; - pei_pass.runOnMachineFunction(mfunc.get()); - - DEBUG = 0; - DEEPDEBUG = 0; - - // 阶段 3.3: 大立即数合法化 - LegalizeImmediatesPass legalizer; - legalizer.runOnMachineFunction(mfunc.get()); - - // 阶段 6: 代码发射 (Code Emission) - std::stringstream ss; - RISCv64AsmPrinter printer(mfunc.get()); - printer.run(ss); - - if (DEBUG) { - ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n" - << ss_after_isel.str(); - } - return ss.str(); } } // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 763f401..3b12bab 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -564,6 +564,40 @@ void RISCv64RegAlloc::freeze() { freezeMoves(u); } +// // 选择溢出节点 +// // in file: RISCv64RegAlloc.cpp + +// void RISCv64RegAlloc::selectSpill() { +// // [核心逻辑修正] 遵从 George & Appel 论文的“乐观着色”策略。 +// // 此函数不再将节点直接放入 spilledNodes。 +// // 它的作用是选择一个“潜在溢出”节点,并将其移回 simplifyWorklist,以打破僵局。 +// // 真正的溢出决策被推迟到 AssignColors 阶段。 + +// // 使用启发式规则从 spillWorklist 中选择一个节点 m。 +// // 论文建议使用代价函数,这里我们继续使用度数最高的简单启发式。 +// auto it = std::max_element(spillWorklist.begin(), spillWorklist.end(), +// [&](unsigned a, unsigned b){ return degree.at(a) < degree.at(b); }); + +// // 理论上此时 spillWorklist 不应为空,但做保护性检查。 +// if (it == spillWorklist.end()) { +// return; +// } + +// unsigned m = *it; + +// // 1. 将选中的节点 m 从溢出工作列表移动到简化工作列表。 +// spillWorklist.erase(it); +// simplifyWorklist.insert(m); // + +// // 2. 冻结与 m 相关的所有传送指令,因为我们已经放弃了对它的合并尝试。 +// freezeMoves(m); // + +// if (DEEPDEBUG) { +// std::cerr << "[Spill] Optimistically moving %vreg" << m +// << " from spillWorklist to simplifyWorklist.\n"; +// } +// } + // 选择溢出节点 void RISCv64RegAlloc::selectSpill() { auto it = std::max_element(spillWorklist.begin(), spillWorklist.end(), @@ -578,7 +612,7 @@ void RISCv64RegAlloc::selectSpill() { void RISCv64RegAlloc::assignColors() { if (DEEPDEBUG) std::cerr << "[AssignColors] Starting...\n"; - // 步骤 1: 完整处理 selectStack + // 步骤 1: 为 selectStack 中的节点分配颜色 (此部分逻辑不变) while (!selectStack.empty()) { unsigned n = selectStack.back(); selectStack.pop_back(); @@ -586,26 +620,22 @@ void RISCv64RegAlloc::assignColors() { const auto& available_regs = is_fp ? allocable_fp_regs : allocable_int_regs; std::set ok_colors(available_regs.begin(), available_regs.end()); - for (unsigned w : adjList.at(n)) { - unsigned w_alias = getAlias(w); - bool is_colored_vreg = coloredNodes.count(w_alias); - bool is_physical_reg = precolored.count(w_alias); - const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); - - if (is_colored_vreg || is_physical_reg) { - PhysicalReg neighbor_color; - if (is_colored_vreg) { - neighbor_color = color_map.at(w_alias); - } else { - neighbor_color = static_cast(w_alias - offset); + if (adjList.count(n)) { + for (unsigned w : adjList.at(n)) { + unsigned w_alias = getAlias(w); + + if (coloredNodes.count(w_alias)) { // 邻居是已着色的vreg + ok_colors.erase(color_map.at(w_alias)); + } else if (precolored.count(w_alias)) { // 邻居是物理寄存器 + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + ok_colors.erase(static_cast(w_alias - offset)); } - ok_colors.erase(neighbor_color); } } if (ok_colors.empty()) { - if (DEEPDEBUG) std::cerr << " -> No color for %vreg" << n << ". Spilling.\n"; spilledNodes.insert(n); + if (DEEPDEBUG) std::cerr << " -> WARNING: No color for %vreg" << n << " from selectStack. Spilling.\n"; } else { PhysicalReg c = *ok_colors.begin(); coloredNodes.insert(n); @@ -614,41 +644,41 @@ void RISCv64RegAlloc::assignColors() { } } - // 步骤 2: 独立、完整地处理 coalescedNodes + // 步骤 2: [最终修正] 完整、正确地处理 coalescedNodes for (unsigned n : coalescedNodes) { unsigned root_alias = getAlias(n); + + // --- 新的、健壮的逻辑,处理所有三种可能性 --- - // 情况 1: 别名是物理寄存器,直接获得该颜色 + // 情况 1: 别名本身就是物理寄存器 (修复当前bug) if (precolored.count(root_alias)) { const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); color_map[n] = static_cast(root_alias - offset); - if (DEEPDEBUG) std::cerr << " -> Coalesced " << regIdToString(n) << " gets color from physical alias " << regIdToString(root_alias) << ".\n"; - } - // 情况 2: 别名是虚拟寄存器,且在步骤1中已被成功着色 + if (DEEPDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from PHYSICAL alias " << regIdToString(root_alias) << ".\n"; + } + // 情况 2: 别名是被成功着色的虚拟寄存器 else if (color_map.count(root_alias)) { color_map[n] = color_map.at(root_alias); - if (DEEPDEBUG) std::cerr << " -> Coalesced " << regIdToString(n) << " gets color of virtual alias " << regIdToString(root_alias) << ".\n"; - } - // 情况 3: 别名是虚拟寄存器,但在步骤1中未能着色(即被溢出) + if (DEEPDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from VIRTUAL alias " << regIdToString(root_alias) << ".\n"; + } + // 情况 3: 别名是被溢出的虚拟寄存器 else { - if (DEEPDEBUG) std::cerr << " -> Alias " << regIdToString(root_alias) << " of %vreg" << n << " was spilled. Spilling.\n"; spilledNodes.insert(n); + if (DEEPDEBUG) std::cerr << " -> Alias " << regIdToString(root_alias) << " of %vreg" << n << " was SPILLED. Spilling %vreg" << n << " as well.\n"; } } } // 重写程序,插入溢出代码 void RISCv64RegAlloc::rewriteProgram() { - // 1. 为溢出的旧vreg在栈上分配空间 (这部分逻辑不变) + // 1. 为溢出的旧vreg在栈上分配空间 StackFrameInfo& frame_info = MFunc->getFrameInfo(); - // locals_size, callee_saved_size等已经由之前的步骤或上一次运行计算好 - // 我们在此基础上累加溢出区大小 int spill_base_offset = frame_info.locals_size + frame_info.callee_saved_size; for (unsigned vreg : spilledNodes) { - if (frame_info.spill_offsets.count(vreg)) continue; // 如果已经分配过则跳过 + if (frame_info.spill_offsets.count(vreg)) continue; - int size = 4; // 默认4字节 + int size = 4; if (isFPVReg(vreg)) { size = 4; // float } else if (vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isPointer()) { @@ -656,117 +686,113 @@ void RISCv64RegAlloc::rewriteProgram() { } spill_base_offset += size; - spill_base_offset = (spill_base_offset + 7) & ~7; // 8字节对齐 - frame_info.spill_offsets[vreg] = spill_base_offset; + spill_base_offset = (spill_base_offset + 7) & ~7; + frame_info.spill_offsets[vreg] = -spill_base_offset; // [修正] 溢出槽也使用负偏移量 } frame_info.spill_size = spill_base_offset - (frame_info.locals_size + frame_info.callee_saved_size); - // 2. 遍历所有指令,为溢出vreg的use/def插入load/store,并使用新的临时虚拟寄存器 + // 2. 遍历所有指令,重写代码 for (auto& mbb : MFunc->getBlocks()) { std::vector> new_instructions; for (auto& instr_ptr : mbb->getInstructions()) { - // 对每条指令,记录其使用的旧vreg到新临时vreg的映射 - std::map vreg_remap; + std::map use_remap; + std::map def_remap; - // a. 为每个溢出的 use 操作数,在原指令前插入 load 指令 VRegSet use, def; - getInstrUseDef_Liveness(instr_ptr.get(), use, def); // 假设此函数能正确处理operands + getInstrUseDef_Liveness(instr_ptr.get(), use, def); - for(auto& op : instr_ptr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - if (reg_op->isVirtual() && spilledNodes.count(reg_op->getVRegNum()) && use.count(reg_op->getVRegNum())) { - unsigned old_vreg = reg_op->getVRegNum(); - // 仅当还未为此vreg创建临时替身时才创建 - if (vreg_remap.find(old_vreg) == vreg_remap.end()) { - Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); - unsigned new_temp_vreg = ISel->getNewVReg(type); - vreg_remap[old_vreg] = new_temp_vreg; + // a. 为每个溢出的 use 操作数创建新vreg并插入 load + for (unsigned old_vreg : use) { + if (spilledNodes.count(old_vreg)) { + Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); + unsigned new_temp_vreg = ISel->getNewVReg(type); + use_remap[old_vreg] = new_temp_vreg; - RVOpcodes load_op; - if (isFPVReg(old_vreg)) load_op = RVOpcodes::FLW; - else if (type->isPointer()) load_op = RVOpcodes::LD; - else load_op = RVOpcodes::LW; + RVOpcodes load_op; + if (isFPVReg(old_vreg)) load_op = RVOpcodes::FLW; + else if (type->isPointer()) load_op = RVOpcodes::LD; + else load_op = RVOpcodes::LW; - auto load = std::make_unique(load_op); - load->addOperand(std::make_unique(new_temp_vreg)); - load->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(-frame_info.spill_offsets.at(old_vreg)) // 偏移是相对于S0的负值 - )); - new_instructions.push_back(std::move(load)); - } - } - } else if (op->getKind() == MachineOperand::KIND_MEM) { - auto reg_op = static_cast(op.get())->getBase(); - if (reg_op->isVirtual() && spilledNodes.count(reg_op->getVRegNum())) { - unsigned old_vreg = reg_op->getVRegNum(); - if (vreg_remap.find(old_vreg) == vreg_remap.end()) { - Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); - unsigned new_temp_vreg = ISel->getNewVReg(type); - vreg_remap[old_vreg] = new_temp_vreg; - - RVOpcodes load_op = (type->isPointer()) ? RVOpcodes::LD : RVOpcodes::LW; - auto load = std::make_unique(load_op); - load->addOperand(std::make_unique(new_temp_vreg)); - load->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(-frame_info.spill_offsets.at(old_vreg)) - )); - new_instructions.push_back(std::move(load)); - } - } + auto load = std::make_unique(load_op); + load->addOperand(std::make_unique(new_temp_vreg)); + load->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(frame_info.spill_offsets.at(old_vreg)) + )); + new_instructions.push_back(std::move(load)); } } - - // b. 替换原指令中的操作数,并将其加入新指令列表 - for(auto& op : instr_ptr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - 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 reg_op = static_cast(op.get())->getBase(); - if (reg_op->isVirtual() && vreg_remap.count(reg_op->getVRegNum())) { - reg_op->setVRegNum(vreg_remap.at(reg_op->getVRegNum())); - } + + // b. 为每个溢出的 def 操作数创建新vreg + for (unsigned old_vreg : def) { + if (spilledNodes.count(old_vreg)) { + Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); + unsigned new_temp_vreg = ISel->getNewVReg(type); + def_remap[old_vreg] = new_temp_vreg; } } - new_instructions.push_back(std::move(instr_ptr)); - // c. 为每个溢出的 def 操作数,在原指令后插入 store 指令 - vreg_remap.clear(); // 清空映射,为def创建新的临时vreg - for(auto& op : new_instructions.back()->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { + // c. [核心修正] 创建一条全新的指令,用新vreg替换旧vreg + auto new_instr = std::make_unique(instr_ptr->getOpcode()); + for (const auto& op : instr_ptr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { auto reg_op = static_cast(op.get()); - if (reg_op->isVirtual() && spilledNodes.count(reg_op->getVRegNum()) && def.count(reg_op->getVRegNum())) { + if (reg_op->isVirtual()) { unsigned old_vreg = reg_op->getVRegNum(); - if (vreg_remap.find(old_vreg) == vreg_remap.end()) { - Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); - unsigned new_temp_vreg = ISel->getNewVReg(type); - vreg_remap[old_vreg] = new_temp_vreg; // 记录从old到new的映射 - - // 再次修改指令,将def的vreg也换成新的临时vreg - reg_op->setVRegNum(new_temp_vreg); - - RVOpcodes store_op; - if (isFPVReg(old_vreg)) store_op = RVOpcodes::FSW; - else if (type->isPointer()) store_op = RVOpcodes::SD; - else store_op = RVOpcodes::SW; - - auto store = std::make_unique(store_op); - store->addOperand(std::make_unique(new_temp_vreg)); // 从新的临时vreg中存值 - store->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(-frame_info.spill_offsets.at(old_vreg)) - )); - // 在原指令之后插入store - new_instructions.push_back(std::move(store)); + if (use.count(old_vreg) && use_remap.count(old_vreg)) { + new_instr->addOperand(std::make_unique(use_remap.at(old_vreg))); + } else if (def.count(old_vreg) && def_remap.count(old_vreg)) { + new_instr->addOperand(std::make_unique(def_remap.at(old_vreg))); + } else { + new_instr->addOperand(std::make_unique(old_vreg)); } + } else { + new_instr->addOperand(std::make_unique(reg_op->getPReg())); } - } + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op.get()); + auto base_reg = mem_op->getBase(); + unsigned old_vreg = base_reg->isVirtual() ? base_reg->getVRegNum() : -1; + + if (base_reg->isVirtual() && use_remap.count(old_vreg)) { + new_instr->addOperand(std::make_unique( + std::make_unique(use_remap.at(old_vreg)), + std::make_unique(mem_op->getOffset()->getValue()) + )); + } else { + new_instr->addOperand(std::make_unique( + std::make_unique(*base_reg), + std::make_unique(mem_op->getOffset()->getValue()) + )); + } + } else { // 立即数、标签等直接复制 + if(op->getKind() == MachineOperand::KIND_IMM) + new_instr->addOperand(std::make_unique(*static_cast(op.get()))); + else if (op->getKind() == MachineOperand::KIND_LABEL) + new_instr->addOperand(std::make_unique(*static_cast(op.get()))); + } + } + new_instructions.push_back(std::move(new_instr)); + + // d. 为每个溢出的 def 操作数,在原指令后插入 store 指令 + for (const auto& pair : def_remap) { + unsigned old_vreg = pair.first; + unsigned new_temp_vreg = pair.second; + Type* type = vreg_type_map.count(old_vreg) ? vreg_type_map.at(old_vreg) : Type::getIntType(); + + RVOpcodes store_op; + if (isFPVReg(old_vreg)) store_op = RVOpcodes::FSW; + else if (type->isPointer()) store_op = RVOpcodes::SD; + else store_op = RVOpcodes::SW; + + auto store = std::make_unique(store_op); + store->addOperand(std::make_unique(new_temp_vreg)); + store->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(frame_info.spill_offsets.at(old_vreg)) + )); + new_instructions.push_back(std::move(store)); } } mbb->getInstructions() = std::move(new_instructions); @@ -828,9 +854,11 @@ void RISCv64RegAlloc::getInstrUseDef(const MachineInstr* instr, VRegSet& use, VR } } +// in file: RISCv64RegAlloc.cpp + /** - * @brief [已修复] 获取一条指令完整的、包含物理寄存器的Use/Def集合 - * 这个新函数将专门服务于活跃性分析。 + * @brief [最终修复版] 获取一条指令完整的、包含物理寄存器的Use/Def集合 + * 这个函数专门服务于活跃性分析,现已补全所有指令(包括伪指令)的逻辑。 */ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet& use, VRegSet& def) { auto opcode = instr->getOpcode(); @@ -838,57 +866,52 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet // 映射表:指令操作码 -> {Def操作数索引列表, Use操作数索引列表} static const std::map, std::vector>> op_info = { - // ===== 已有指令定义 (保留) ===== + // ===== 整数算术与逻辑指令 (R-type & I-type) ===== {RVOpcodes::ADD, {{0}, {1, 2}}}, {RVOpcodes::SUB, {{0}, {1, 2}}}, {RVOpcodes::MUL, {{0}, {1, 2}}}, {RVOpcodes::DIV, {{0}, {1, 2}}}, {RVOpcodes::REM, {{0}, {1, 2}}}, {RVOpcodes::ADDW, {{0}, {1, 2}}}, {RVOpcodes::SUBW, {{0}, {1, 2}}}, {RVOpcodes::MULW, {{0}, {1, 2}}}, {RVOpcodes::DIVW, {{0}, {1, 2}}}, {RVOpcodes::REMW, {{0}, {1, 2}}}, {RVOpcodes::SLT, {{0}, {1, 2}}}, {RVOpcodes::SLTU, {{0}, {1, 2}}}, + {RVOpcodes::XOR, {{0}, {1, 2}}}, {RVOpcodes::OR, {{0}, {1, 2}}}, {RVOpcodes::AND, {{0}, {1, 2}}}, {RVOpcodes::ADDI, {{0}, {1}}}, {RVOpcodes::ADDIW, {{0}, {1}}}, {RVOpcodes::XORI, {{0}, {1}}}, - {RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, {RVOpcodes::LB, {{0}, {}}}, - {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}}, - {RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}}, - {RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, {RVOpcodes::SB, {{}, {0, 1}}}, - {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}}, - {RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, {RVOpcodes::BEQ, {{}, {0, 1}}}, - {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, {RVOpcodes::BGE, {{}, {0, 1}}}, - {RVOpcodes::JALR, {{0}, {1}}}, {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}}, - {RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}}, - {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}}, - {RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}}, - {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}}, - {RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, - {RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}}, + {RVOpcodes::ORI, {{0}, {1}}}, {RVOpcodes::ANDI, {{0}, {1}}}, + {RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{0}, {1}}}, - // ===== 新增的指令定义开始 ===== - - // --- 逻辑指令 --- - {RVOpcodes::XOR, {{0}, {1, 2}}}, - {RVOpcodes::OR, {{0}, {1, 2}}}, - {RVOpcodes::AND, {{0}, {1, 2}}}, - {RVOpcodes::ORI, {{0}, {1}}}, - {RVOpcodes::ANDI, {{0}, {1}}}, - - // --- 移位指令 --- + // ===== 移位指令 ===== {RVOpcodes::SLL, {{0}, {1, 2}}}, {RVOpcodes::SLLI, {{0}, {1}}}, {RVOpcodes::SLLW, {{0}, {1, 2}}}, {RVOpcodes::SLLIW, {{0}, {1}}}, {RVOpcodes::SRL, {{0}, {1, 2}}}, {RVOpcodes::SRLI, {{0}, {1}}}, {RVOpcodes::SRLW, {{0}, {1, 2}}}, {RVOpcodes::SRLIW, {{0}, {1}}}, {RVOpcodes::SRA, {{0}, {1, 2}}}, {RVOpcodes::SRAI, {{0}, {1}}}, {RVOpcodes::SRAW, {{0}, {1, 2}}}, {RVOpcodes::SRAIW, {{0}, {1}}}, + + // ===== 内存加载指令 (Def: 0, Use: MemBase) ===== + {RVOpcodes::LB, {{0}, {}}}, {RVOpcodes::LH, {{0}, {}}}, {RVOpcodes::LW, {{0}, {}}}, {RVOpcodes::LD, {{0}, {}}}, + {RVOpcodes::LBU, {{0}, {}}}, {RVOpcodes::LHU, {{0}, {}}}, {RVOpcodes::LWU, {{0}, {}}}, + {RVOpcodes::FLW, {{0}, {}}}, {RVOpcodes::FLD, {{0}, {}}}, + + // ===== 内存存储指令 (Def: None, Use: ValToStore, MemBase) ===== + {RVOpcodes::SB, {{}, {0, 1}}}, {RVOpcodes::SH, {{}, {0, 1}}}, {RVOpcodes::SW, {{}, {0, 1}}}, {RVOpcodes::SD, {{}, {0, 1}}}, + {RVOpcodes::FSW, {{}, {0, 1}}}, {RVOpcodes::FSD, {{}, {0, 1}}}, - // --- 控制流指令 (补全) --- - {RVOpcodes::BLTU, {{}, {0, 1}}}, - {RVOpcodes::BGEU, {{}, {0, 1}}}, - // J 没有寄存器操作数,JAL 由CALL指令类似的特殊逻辑处理 + // ===== 控制流指令 ===== + {RVOpcodes::BEQ, {{}, {0, 1}}}, {RVOpcodes::BNE, {{}, {0, 1}}}, {RVOpcodes::BLT, {{}, {0, 1}}}, + {RVOpcodes::BGE, {{}, {0, 1}}}, {RVOpcodes::BLTU, {{}, {0, 1}}}, {RVOpcodes::BGEU, {{}, {0, 1}}}, + {RVOpcodes::JALR, {{0}, {1}}}, // def: ra (implicit) and op0, use: op1 + + // ===== 浮点指令 ===== + {RVOpcodes::FADD_S, {{0}, {1, 2}}}, {RVOpcodes::FSUB_S, {{0}, {1, 2}}}, + {RVOpcodes::FMUL_S, {{0}, {1, 2}}}, {RVOpcodes::FDIV_S, {{0}, {1, 2}}}, {RVOpcodes::FEQ_S, {{0}, {1, 2}}}, + {RVOpcodes::FLT_S, {{0}, {1, 2}}}, {RVOpcodes::FLE_S, {{0}, {1, 2}}}, {RVOpcodes::FCVT_S_W, {{0}, {1}}}, + {RVOpcodes::FCVT_W_S, {{0}, {1}}}, {RVOpcodes::FMV_S, {{0}, {1}}}, {RVOpcodes::FMV_W_X, {{0}, {1}}}, + {RVOpcodes::FMV_X_W, {{0}, {1}}}, {RVOpcodes::FNEG_S, {{0}, {1}}}, - // --- 伪指令 (补全) --- - {RVOpcodes::NEG, {{0}, {1}}}, - {RVOpcodes::NEGW, {{0}, {1}}}, - - // ===== 新增的指令定义结束 ===== + // ===== 伪指令 ===== + {RVOpcodes::LI, {{0}, {}}}, {RVOpcodes::LA, {{0}, {}}}, + {RVOpcodes::MV, {{0}, {1}}}, {RVOpcodes::SEQZ, {{0}, {1}}}, {RVOpcodes::SNEZ, {{0}, {1}}}, + {RVOpcodes::NEG, {{0}, {1}}}, {RVOpcodes::NEGW, {{0}, {1}}}, }; - // 该lambda表达式用于获取操作数的寄存器ID(虚拟或物理),逻辑正确,保持不变 + // lambda表达式用于获取操作数的寄存器ID(虚拟或物理) const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); auto get_any_reg_id = [&](const MachineOperand* op) -> unsigned { if (op->getKind() == MachineOperand::KIND_REG) { @@ -902,6 +925,7 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet return (unsigned)-1; }; + // --- 主要处理逻辑 --- if (op_info.count(opcode)) { const auto& info = op_info.at(opcode); for (int idx : info.first) if (idx < operands.size()) { @@ -912,7 +936,7 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet unsigned reg_id = get_any_reg_id(operands[idx].get()); if (reg_id != (unsigned)-1) use.insert(reg_id); } - // 不要忘记内存操作数中的基址寄存器永远是use + // 对于所有内存操作,基址寄存器都必须是 use for (const auto& op : operands) { if (op->getKind() == MachineOperand::KIND_MEM) { unsigned reg_id = get_any_reg_id(op.get()); @@ -920,7 +944,7 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet } } } - // CALL 和 RET 的特殊处理逻辑,保持不变 + // --- 特殊指令处理逻辑 --- else if (opcode == RVOpcodes::CALL) { // 返回值是Def if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) { @@ -943,6 +967,16 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet use.insert(offset + static_cast(PhysicalReg::A0)); use.insert(offset + static_cast(PhysicalReg::F10)); // F10 is fa0 } + // [关键Bug修复] 添加对 PSEUDO_KEEPALIVE 的处理 + else if (opcode == RVOpcodes::PSEUDO_KEEPALIVE) { + // keepalive的所有操作数都是use,以确保它们的生命周期延续到该点 + for (const auto& op : operands) { + if (op->getKind() == MachineOperand::KIND_REG) { + unsigned reg_id = get_any_reg_id(op.get()); + if (reg_id != (unsigned)-1) use.insert(reg_id); + } + } + } } void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { @@ -1197,6 +1231,44 @@ bool RISCv64RegAlloc::georgeHeuristic(unsigned t, unsigned u) { return degree.at(t) < K || precolored.count(u) || adjList.at(t).count(u); } +// void RISCv64RegAlloc::combine(unsigned u, unsigned v) { +// // 1. 从相应的工作列表中移除即将被合并的节点 v +// if (freezeWorklist.count(v)) { +// freezeWorklist.erase(v); +// } else { +// spillWorklist.erase(v); +// } + +// // 2. 将 v 加入 coalescedNodes 集合,并设置其别名 +// coalescedNodes.insert(v); +// alias[v] = u; + +// // 3. 将 v 的传送指令列表合并到 u +// if (moveList.count(u) && moveList.count(v)) { +// moveList.at(u).insert(moveList.at(v).begin(), moveList.at(v).end()); +// } else if (moveList.count(v)) { +// moveList[u] = moveList.at(v); +// } + +// // [Bug修复] 移除了论文伪代码中不存在的 enableMoves({v}) 调用。 + +// // 4. [核心Bug修复] 遍历 v 的“当前有效”邻居 t (使用 adjacent(v) 而非 adjList.at(v)) +// // 将它们与 u 连接,并更新它们的度数。 +// for (unsigned t : adjacent(v)) { +// addEdge(t, u); +// decrementDegree(t); +// } + +// // 5. 检查合并后的节点 u 的状态,如果其度数变高,可能需要将其移到 spillWorklist +// if (!precolored.count(u)) { +// int K = isFPVReg(u) ? K_fp : K_int; +// if (degree.at(u) >= K && freezeWorklist.count(u)) { +// freezeWorklist.erase(u); +// spillWorklist.insert(u); +// } +// } +// } + void RISCv64RegAlloc::combine(unsigned u, unsigned v) { freezeWorklist.erase(v); spillWorklist.erase(v); From 373726b02f0138eff03d74f1087d329e0d662b0b Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 17:29:18 +0800 Subject: [PATCH 06/10] =?UTF-8?q?[backend-IRC]=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E6=9E=81=E5=85=B6=E9=9A=90=E8=94=BD=E7=9A=84=E5=AF=84=E5=AD=98?= =?UTF-8?q?=E5=99=A8=E5=88=86=E9=85=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/RISCv64/RISCv64RegAlloc.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 3b12bab..5216594 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -157,7 +157,7 @@ void RISCv64RegAlloc::precolorByCallingConvention() { // 修改部分:将物理寄存器ID转换为其字符串名称 for (unsigned v : precolored) std::cerr << regIdToString(v) << " "; std::cerr << "}\nColored nodes: { "; - for (unsigned v : coloredNodes) std::cerr << "%vreg" << v << " "; + for (unsigned v : coloredNodes) std::cerr << "<%vreg" << v << ", " << regToString(color_map.at(v)) << "> "; std::cerr << "}\n"; } } @@ -283,7 +283,7 @@ void RISCv64RegAlloc::build() { if (precolored.count(v)) { std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; } else { - std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register.\n"; + std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register with " << regToString(color_map.at(v)) << "\n"; } } } @@ -294,7 +294,7 @@ void RISCv64RegAlloc::build() { if (precolored.count(v)) { std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; } else { - std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register.\n"; + std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register with " << regToString(color_map.at(v)) << ".\n"; } } } @@ -611,7 +611,6 @@ void RISCv64RegAlloc::selectSpill() { void RISCv64RegAlloc::assignColors() { if (DEEPDEBUG) std::cerr << "[AssignColors] Starting...\n"; - // 步骤 1: 为 selectStack 中的节点分配颜色 (此部分逻辑不变) while (!selectStack.empty()) { unsigned n = selectStack.back(); @@ -983,7 +982,7 @@ void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { if (u == v) return; // 检查两个节点是否都是虚拟寄存器 - if (!precolored.count(u) && !precolored.count(v)) { + if (!precolored.count(u) && !precolored.count(v) && !coloredNodes.count(u) && !coloredNodes.count(v)) { // 只有当两个都是虚拟寄存器时,才为它们双方添加边和更新度数 // 使用 operator[] 是安全的,如果键不存在,它会默认构造一个空的set if (adjList[u].find(v) == adjList[u].end()) { @@ -994,7 +993,7 @@ void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { } } // 检查是否为 "虚拟-物理" 对 - else if (!precolored.count(u) && precolored.count(v)) { + else if (!precolored.count(u) && precolored.count(v) && !coloredNodes.count(u)) { // u是虚拟寄存器,v是物理寄存器,只更新u的邻接表和度数 if (adjList[u].find(v) == adjList[u].end()) { adjList[u].insert(v); @@ -1002,7 +1001,7 @@ void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { } } // 检查是否为 "物理-虚拟" 对 - else if (precolored.count(u) && !precolored.count(v)) { + else if (precolored.count(u) && !precolored.count(v) && !coloredNodes.count(v)) { // u是物理寄存器,v是虚拟寄存器,只更新v的邻接表和度数 if (adjList[v].find(u) == adjList[v].end()) { adjList[v].insert(u); @@ -1122,8 +1121,14 @@ void RISCv64RegAlloc::decrementDegree(unsigned m) { enableMoves(nodes_to_enable); spillWorklist.erase(m); if (moveRelated(m)) { + if (DEEPDEBUG) { + std::cerr << "[decrementDegree] Node " << regIdToString(m) << " has degree " << d << ", now decremented to " << degree.at(m) << ". Added to freezeWorklist.\n"; + } freezeWorklist.insert(m); } else { + if (DEEPDEBUG) { + std::cerr << "[decrementDegree] Node " << regIdToString(m) << " has degree " << d << ", now decremented to " << degree.at(m) << ". Added to simplifyWorklist.\n"; + } simplifyWorklist.insert(m); } } @@ -1160,6 +1165,9 @@ void RISCv64RegAlloc::addWorklist(unsigned u) { if (!moveRelated(u) && degree.at(u) < K) { freezeWorklist.erase(u); simplifyWorklist.insert(u); + if (DEEPDEBUG) { + std::cerr << "[addWorklist] Node " << regIdToString(u) << " added to simplifyWorklist (degree: " << degree.at(u) << ", K: " << K << ").\n"; + } } } @@ -1317,6 +1325,9 @@ void RISCv64RegAlloc::freezeMoves(unsigned u) { if (!precolored.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) { freezeWorklist.erase(v_alias); simplifyWorklist.insert(v_alias); + if (DEEPDEBUG) { + std::cerr << "[freezeMoves] Node " << regIdToString(v_alias) << " moved to simplifyWorklist (degree: " << degree.at(v_alias) << ").\n"; + } } } } From 57fe17dc21f42e2f85406805b7208f207952b167 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 21:20:04 +0800 Subject: [PATCH 07/10] =?UTF-8?q?[backend-IRC]=E4=B8=BA=E8=99=9A=E6=8B=9F?= =?UTF-8?q?=E5=AF=84=E5=AD=98=E5=99=A8=E4=B8=8E=E7=89=A9=E7=90=86=E5=AF=84?= =?UTF-8?q?=E5=AD=98=E5=99=A8=E4=B9=8B=E9=97=B4=E6=B7=BB=E5=8A=A0=E5=86=B2?= =?UTF-8?q?=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/RISCv64/RISCv64RegAlloc.cpp | 61 +++++++++++++++---------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 5216594..3eed7dd 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -124,29 +124,29 @@ void RISCv64RegAlloc::precolorByCallingConvention() { } } - // --- 部分2:为CALL指令的返回值预着色 --- - for (auto& mbb : MFunc->getBlocks()) { - for (auto& instr : mbb->getInstructions()) { - if (instr->getOpcode() == RVOpcodes::CALL) { - if (!instr->getOperands().empty() && - instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) - { - auto reg_op = static_cast(instr->getOperands().front().get()); - if (reg_op->isVirtual()) { - unsigned ret_vreg = reg_op->getVRegNum(); - assert(vreg_to_value_map.count(ret_vreg) && "Return vreg not found!"); - Value* ret_val = vreg_to_value_map.at(ret_vreg); + // // --- 部分2:为CALL指令的返回值预着色 --- + // for (auto& mbb : MFunc->getBlocks()) { + // for (auto& instr : mbb->getInstructions()) { + // if (instr->getOpcode() == RVOpcodes::CALL) { + // if (!instr->getOperands().empty() && + // instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) + // { + // auto reg_op = static_cast(instr->getOperands().front().get()); + // if (reg_op->isVirtual()) { + // unsigned ret_vreg = reg_op->getVRegNum(); + // assert(vreg_to_value_map.count(ret_vreg) && "Return vreg not found!"); + // Value* ret_val = vreg_to_value_map.at(ret_vreg); - if (ret_val->getType()->isFloat()) { - color_map[ret_vreg] = PhysicalReg::F10; // fa0 - } else { - color_map[ret_vreg] = PhysicalReg::A0; // a0 - } - } - } - } - } - } + // if (ret_val->getType()->isFloat()) { + // color_map[ret_vreg] = PhysicalReg::F10; // fa0 + // } else { + // color_map[ret_vreg] = PhysicalReg::A0; // a0 + // } + // } + // } + // } + // } + // } // 将所有预着色的vreg视为已着色节点 for(const auto& pair : color_map) { @@ -375,13 +375,17 @@ void RISCv64RegAlloc::build() { // --- 规则 1 & 2: Def 与 Live/Use 变量干扰 --- for (unsigned d : def) { - // [关键修正] Def必须是虚拟寄存器 - if (precolored.count(d)) continue; - + // 新逻辑:对于指令定义的所有寄存器d(无论是虚拟寄存器还是像call指令那样 + // 隐式定义的物理寄存器),它都与该指令之后的所有活跃寄存器l冲突。 + // addEdge函数内部会正确处理 vreg-vreg 和 vreg-preg 的情况, + // 并忽略 preg-preg 的情况。 for (unsigned l : live) { addEdge(d, l); } + // 对于非传送指令, Def还和Use冲突。 + // 这个逻辑主要用于确保在同一条指令内,例如 sub t0, t1, t0, + // 作为def的t0和作为use的t0被视为冲突。 if (!is_move) { for (unsigned u_op : use) { addEdge(d, u_op); @@ -961,6 +965,13 @@ void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet // 返回地址寄存器RA也被隐式定义 def.insert(offset + static_cast(PhysicalReg::RA)); } + else if (opcode == RVOpcodes::JALR) { + // JALR rd, rs1, imm. Def: rd, Use: rs1. + // 同时也隐式定义了ra(x1),但通常rd就是ra。为精确,我们只处理显式操作数。 + // 旧版本逻辑:def.insert(ra); first_reg_is_def = false; -> 这是不精确的 + def.insert(get_any_reg_id(operands[0].get())); + use.insert(get_any_reg_id(operands[1].get())); + } else if (opcode == RVOpcodes::RET) { // 遵循调用约定,a0(整数/指针)和fa0(浮点)被隐式使用 use.insert(offset + static_cast(PhysicalReg::A0)); From 384f7c548b793b2227e3342a9fce5bff1428fd52 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 23:18:53 +0800 Subject: [PATCH 08/10] =?UTF-8?q?[backend-IRC]=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E4=B8=89=E7=BA=A7=E8=B0=83=E8=AF=95=E6=89=93=E5=8D=B0=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/RISCv64/RISCv64RegAlloc.cpp | 173 ++++++++---------- src/include/backend/RISCv64/RISCv64RegAlloc.h | 4 +- src/sysyc.cpp | 2 + 3 files changed, 85 insertions(+), 94 deletions(-) diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 3eed7dd..76f003b 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -1,5 +1,3 @@ -// in file: RISCv64RegAlloc.cpp - #include "RISCv64RegAlloc.h" #include "RISCv64AsmPrinter.h" #include @@ -263,7 +261,7 @@ void RISCv64RegAlloc::build() { getInstrUseDef_Liveness(instr, use, def); // 调试输出 use 和 def (保留您的调试逻辑) - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "Instr:"; printer_inside_build.printInstruction(instr_ptr.get(), true); auto print_set = [this](const VRegSet& s, const std::string& name) { @@ -278,7 +276,7 @@ void RISCv64RegAlloc::build() { for (unsigned v : use) { if (!coloredNodes.count(v) && !precolored.count(v)) { initial.insert(v); - } else if (DEEPDEBUG) { + } else if ((DEEPDEBUG && initial.size() < DEBUGLENGTH) || DEEPERDEBUG) { // 这里的调试信息可以更精确 if (precolored.count(v)) { std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; @@ -290,7 +288,7 @@ void RISCv64RegAlloc::build() { for (unsigned v : def) { if (!coloredNodes.count(v) && !precolored.count(v)) { initial.insert(v); - } else if (DEEPDEBUG) { + } else if ((DEEPDEBUG && initial.size() < DEBUGLENGTH) || DEEPERDEBUG) { if (precolored.count(v)) { std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; } else { @@ -302,9 +300,20 @@ void RISCv64RegAlloc::build() { } if (DEEPDEBUG) { - std::cerr << "Initial set after build: { "; - for (unsigned v : initial) std::cerr << regIdToString(v) << " "; - std::cerr << "}\n"; + if (initial.size() > DEBUGLENGTH && !DEEPERDEBUG) { + std::cerr << "Initial set too large, showing first " << DEBUGLENGTH << " elements:\n"; + } + std::cerr << "Initial set (" << initial.size() << "): { "; + unsigned count = 0; + for (unsigned v : initial) { + if (count++ >= DEBUGLENGTH && !DEEPERDEBUG) break; // 限制输出数量 + std::cerr << regIdToString(v) << " "; + } + if (count < initial.size()) { + std::cerr << "... (total " << initial.size() << " elements)\n"; + } else { + std::cerr << "}\n"; + } } // 2. 为所有参与图构建的虚拟寄存器(initial + coloredNodes)初始化数据结构 @@ -331,7 +340,7 @@ void RISCv64RegAlloc::build() { const VRegSet& live_out = live_out_map.at(instr); // 保留您的指令级调试输出 - if (DEEPDEBUG) { + if (DEEPERDEBUG) { RISCv64AsmPrinter temp_printer(MFunc); temp_printer.setStream(std::cerr); std::cerr << "Instr: "; @@ -417,7 +426,7 @@ void RISCv64RegAlloc::makeWorklist() { std::cerr << "Error: degree not initialized for %vreg" << n << "\n"; continue; } - if (DEEPDEBUG) { + if ((DEEPDEBUG && initial.size() < DEBUGLENGTH) || DEEPERDEBUG) { std::cerr << "Assigning %vreg" << n << " (degree=" << degree.at(n) << ", moveRelated=" << moveRelated(n) << ")\n"; } @@ -429,7 +438,7 @@ void RISCv64RegAlloc::makeWorklist() { simplifyWorklist.insert(n); } } - if (DEEPDEBUG) std::cerr << "--------------------------------\n"; + if (DEEPDEBUG || DEEPERDEBUG) std::cerr << "--------------------------------\n"; initial.clear(); } @@ -437,7 +446,7 @@ void RISCv64RegAlloc::makeWorklist() { void RISCv64RegAlloc::simplify() { unsigned n = *simplifyWorklist.begin(); simplifyWorklist.erase(simplifyWorklist.begin()); - if (DEEPDEBUG) std::cerr << "[Simplify] Popped %vreg" << n << ", pushing to stack.\n"; + if (DEEPERDEBUG) std::cerr << "[Simplify] Popped %vreg" << n << ", pushing to stack.\n"; selectStack.push_back(n); for (unsigned m : adjacent(n)) { decrementDegree(m); @@ -455,19 +464,19 @@ void RISCv64RegAlloc::coalesce() { unsigned u, v; if (precolored.count(y)) { u = y; v = x; } else { u = x; v = y; } - if (DEEPDEBUG) std::cerr << "[Coalesce] Processing move between " << regIdToString(x) + if (DEEPERDEBUG) std::cerr << "[Coalesce] Processing move between " << regIdToString(x) << " and " << regIdToString(y) << " (aliases " << regIdToString(u) << ", " << regIdToString(v) << ").\n"; if (u == v) { - if (DEEPDEBUG) std::cerr << " -> Trivial coalesce (u == v).\n"; + if (DEEPERDEBUG) std::cerr << " -> Trivial coalesce (u == v).\n"; coalescedMoves.insert(move); addWorklist(u); return; // 处理完毕,提前返回 } if (isFPVReg(u) != isFPVReg(v)) { - if (DEEPDEBUG) std::cerr << " -> Constrained (type mismatch: " << regIdToString(u) << " is " + if (DEEPERDEBUG) std::cerr << " -> Constrained (type mismatch: " << regIdToString(u) << " is " << (isFPVReg(u) ? "float" : "int") << ", " << regIdToString(v) << " is " << (isFPVReg(v) ? "float" : "int") << ").\n"; constrainedMoves.insert(move); @@ -481,7 +490,7 @@ void RISCv64RegAlloc::coalesce() { bool pre_interfere = adjList.at(v).count(u); if (pre_interfere) { - if (DEEPDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n"; + if (DEEPERDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n"; constrainedMoves.insert(move); addWorklist(u); addWorklist(v); @@ -493,13 +502,13 @@ void RISCv64RegAlloc::coalesce() { if (is_u_precolored) { // --- 场景1:u是物理寄存器,使用 George 启发式 --- - if (DEEPDEBUG) std::cerr << " -> Trying George Heuristic (u is precolored)...\n"; + if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is precolored)...\n"; // ==================== [展开的 std::all_of 逻辑] ==================== // 步骤 1: 独立调用 adjacent(v) 获取邻居集合 VRegSet neighbors_of_v = adjacent(v); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << " - Neighbors of " << regIdToString(v) << " to check are (" << neighbors_of_v.size() << "): { "; for (unsigned id : neighbors_of_v) std::cerr << regIdToString(id) << " "; std::cerr << "}\n"; @@ -508,14 +517,14 @@ void RISCv64RegAlloc::coalesce() { // 步骤 2: 使用显式的 for 循环来代替 std::all_of bool george_ok = true; // 默认假设成功,任何一个邻居失败都会将此设为 false for (unsigned t : neighbors_of_v) { - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n"; } // 步骤 3: 独立调用启发式函数 bool heuristic_result = georgeHeuristic(t, u); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n"; } @@ -525,7 +534,7 @@ void RISCv64RegAlloc::coalesce() { } } - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n"; } // ================================================================= @@ -536,10 +545,10 @@ void RISCv64RegAlloc::coalesce() { } else { // --- 场景2:u和v都是虚拟寄存器,使用 Briggs 启发式 --- - if (DEEPDEBUG) std::cerr << " -> Trying Briggs Heuristic (u and v are virtual)...\n"; + if (DEEPERDEBUG) std::cerr << " -> Trying Briggs Heuristic (u and v are virtual)...\n"; bool briggs_ok = briggsHeuristic(u, v); - if (DEEPDEBUG) std::cerr << " - briggsHeuristic(" << regIdToString(u) << ", " << regIdToString(v) << ") -> " << (briggs_ok ? "OK" : "FAIL") << "\n"; + if (DEEPERDEBUG) std::cerr << " - briggsHeuristic(" << regIdToString(u) << ", " << regIdToString(v) << ") -> " << (briggs_ok ? "OK" : "FAIL") << "\n"; if (briggs_ok) { can_coalesce = true; @@ -549,12 +558,12 @@ void RISCv64RegAlloc::coalesce() { // --- 根据启发式结果进行最终决策 --- if (can_coalesce) { - if (DEEPDEBUG) std::cerr << " -> Heuristic OK. Combining " << regIdToString(v) << " into " << regIdToString(u) << ".\n"; + if (DEEPERDEBUG) std::cerr << " -> Heuristic OK. Combining " << regIdToString(v) << " into " << regIdToString(u) << ".\n"; coalescedMoves.insert(move); combine(u, v); addWorklist(u); } else { - if (DEEPDEBUG) std::cerr << " -> Heuristic failed. Adding to active moves.\n"; + if (DEEPERDEBUG) std::cerr << " -> Heuristic failed. Adding to active moves.\n"; activeMoves.insert(move); } } @@ -563,58 +572,24 @@ void RISCv64RegAlloc::coalesce() { void RISCv64RegAlloc::freeze() { unsigned u = *freezeWorklist.begin(); freezeWorklist.erase(freezeWorklist.begin()); - if (DEEPDEBUG) std::cerr << "[Freeze] Freezing %vreg" << u << " and moving to simplify list.\n"; + if (DEEPERDEBUG) std::cerr << "[Freeze] Freezing %vreg" << u << " and moving to simplify list.\n"; simplifyWorklist.insert(u); freezeMoves(u); } -// // 选择溢出节点 -// // in file: RISCv64RegAlloc.cpp - -// void RISCv64RegAlloc::selectSpill() { -// // [核心逻辑修正] 遵从 George & Appel 论文的“乐观着色”策略。 -// // 此函数不再将节点直接放入 spilledNodes。 -// // 它的作用是选择一个“潜在溢出”节点,并将其移回 simplifyWorklist,以打破僵局。 -// // 真正的溢出决策被推迟到 AssignColors 阶段。 - -// // 使用启发式规则从 spillWorklist 中选择一个节点 m。 -// // 论文建议使用代价函数,这里我们继续使用度数最高的简单启发式。 -// auto it = std::max_element(spillWorklist.begin(), spillWorklist.end(), -// [&](unsigned a, unsigned b){ return degree.at(a) < degree.at(b); }); - -// // 理论上此时 spillWorklist 不应为空,但做保护性检查。 -// if (it == spillWorklist.end()) { -// return; -// } - -// unsigned m = *it; - -// // 1. 将选中的节点 m 从溢出工作列表移动到简化工作列表。 -// spillWorklist.erase(it); -// simplifyWorklist.insert(m); // - -// // 2. 冻结与 m 相关的所有传送指令,因为我们已经放弃了对它的合并尝试。 -// freezeMoves(m); // - -// if (DEEPDEBUG) { -// std::cerr << "[Spill] Optimistically moving %vreg" << m -// << " from spillWorklist to simplifyWorklist.\n"; -// } -// } - // 选择溢出节点 void RISCv64RegAlloc::selectSpill() { auto it = std::max_element(spillWorklist.begin(), spillWorklist.end(), [&](unsigned a, unsigned b){ return degree.at(a) < degree.at(b); }); unsigned m = *it; spillWorklist.erase(it); - if (DEEPDEBUG) std::cerr << "[Spill] Selecting %vreg" << m << " to spill.\n"; + if (DEEPERDEBUG) std::cerr << "[Spill] Selecting %vreg" << m << " to spill.\n"; simplifyWorklist.insert(m); freezeMoves(m); } void RISCv64RegAlloc::assignColors() { - if (DEEPDEBUG) std::cerr << "[AssignColors] Starting...\n"; + if (DEEPERDEBUG) std::cerr << "[AssignColors] Starting...\n"; // 步骤 1: 为 selectStack 中的节点分配颜色 (此部分逻辑不变) while (!selectStack.empty()) { unsigned n = selectStack.back(); @@ -638,12 +613,12 @@ void RISCv64RegAlloc::assignColors() { if (ok_colors.empty()) { spilledNodes.insert(n); - if (DEEPDEBUG) std::cerr << " -> WARNING: No color for %vreg" << n << " from selectStack. Spilling.\n"; + if (DEEPERDEBUG) std::cerr << " -> WARNING: No color for %vreg" << n << " from selectStack. Spilling.\n"; } else { PhysicalReg c = *ok_colors.begin(); coloredNodes.insert(n); color_map[n] = c; - if (DEEPDEBUG) std::cerr << " -> Colored %vreg" << n << " with " << regToString(c) << ".\n"; + if (DEEPERDEBUG) std::cerr << " -> Colored %vreg" << n << " with " << regToString(c) << ".\n"; } } @@ -657,17 +632,17 @@ void RISCv64RegAlloc::assignColors() { if (precolored.count(root_alias)) { const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); color_map[n] = static_cast(root_alias - offset); - if (DEEPDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from PHYSICAL alias " << regIdToString(root_alias) << ".\n"; + if (DEEPERDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from PHYSICAL alias " << regIdToString(root_alias) << ".\n"; } // 情况 2: 别名是被成功着色的虚拟寄存器 else if (color_map.count(root_alias)) { color_map[n] = color_map.at(root_alias); - if (DEEPDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from VIRTUAL alias " << regIdToString(root_alias) << ".\n"; + if (DEEPERDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from VIRTUAL alias " << regIdToString(root_alias) << ".\n"; } // 情况 3: 别名是被溢出的虚拟寄存器 else { spilledNodes.insert(n); - if (DEEPDEBUG) std::cerr << " -> Alias " << regIdToString(root_alias) << " of %vreg" << n << " was SPILLED. Spilling %vreg" << n << " as well.\n"; + if (DEEPERDEBUG) std::cerr << " -> Alias " << regIdToString(root_alias) << " of %vreg" << n << " was SPILLED. Spilling %vreg" << n << " as well.\n"; } } } @@ -1024,14 +999,14 @@ void RISCv64RegAlloc::addEdge(unsigned u, unsigned v) { RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { // 仅在 DEEPDEBUG 模式下启用详细日志 - if (DEEPDEBUG) { + if (DEEPERDEBUG) { // 使用 regIdToString 打印节点 n,无论是物理还是虚拟 std::cerr << "\n[adjacent] >>>>> Executing for node " << regIdToString(n) << " <<<<<\n"; } // 1. 如果节点 n 是物理寄存器,它没有邻接表,直接返回空集 if (precolored.count(n)) { - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[adjacent] Node " << regIdToString(n) << " is precolored. Returning {}.\n"; } return {}; @@ -1039,7 +1014,7 @@ RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { // 安全检查:确保 n 在 adjList 中存在,防止 map::at 崩溃 if (adjList.count(n) == 0) { - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[adjacent] WARNING: Node " << regIdToString(n) << " not found in adjList. Returning {}.\n"; } return {}; @@ -1048,7 +1023,7 @@ RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { // 2. 获取 n 在冲突图中的所有邻居 VRegSet result = adjList.at(n); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { // 定义一个局部的 lambda 方便打印集合 auto print_set = [this](const VRegSet& s, const std::string& name) { std::cerr << "[adjacent] " << name << " (" << s.size() << "): { "; @@ -1065,11 +1040,11 @@ RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { VRegSet removed_from_stack; // 仅用于调试打印 for (auto it = selectStack.rbegin(); it != selectStack.rend(); ++it) { if (result.count(*it)) { - if (DEEPDEBUG) removed_from_stack.insert(*it); + if (DEEPERDEBUG) removed_from_stack.insert(*it); result.erase(*it); } } - if (DEEPDEBUG && !removed_from_stack.empty()) { + if (DEEPERDEBUG && !removed_from_stack.empty()) { std::cerr << "[adjacent] - Removed from selectStack: { "; for(unsigned id : removed_from_stack) std::cerr << regIdToString(id) << " "; std::cerr << "}\n"; @@ -1079,18 +1054,18 @@ RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { VRegSet removed_from_coalesced; // 仅用于调试打印 for (unsigned cn : coalescedNodes) { if (result.count(cn)) { - if (DEEPDEBUG) removed_from_coalesced.insert(cn); + if (DEEPERDEBUG) removed_from_coalesced.insert(cn); result.erase(cn); } } - if (DEEPDEBUG && !removed_from_coalesced.empty()) { + if (DEEPERDEBUG && !removed_from_coalesced.empty()) { std::cerr << "[adjacent] - Removed from coalescedNodes: { "; for(unsigned id : removed_from_coalesced) std::cerr << regIdToString(id) << " "; std::cerr << "}\n"; } // 4. 返回最终的、过滤后的“有效”邻居集合 - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[adjacent] >>>>> Returning final adjacent set (" << result.size() << "): { "; for (unsigned id : result) std::cerr << regIdToString(id) << " "; std::cerr << "}\n\n"; @@ -1132,12 +1107,12 @@ void RISCv64RegAlloc::decrementDegree(unsigned m) { enableMoves(nodes_to_enable); spillWorklist.erase(m); if (moveRelated(m)) { - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[decrementDegree] Node " << regIdToString(m) << " has degree " << d << ", now decremented to " << degree.at(m) << ". Added to freezeWorklist.\n"; } freezeWorklist.insert(m); } else { - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[decrementDegree] Node " << regIdToString(m) << " has degree " << d << ", now decremented to " << degree.at(m) << ". Added to simplifyWorklist.\n"; } simplifyWorklist.insert(m); @@ -1176,7 +1151,7 @@ void RISCv64RegAlloc::addWorklist(unsigned u) { if (!moveRelated(u) && degree.at(u) < K) { freezeWorklist.erase(u); simplifyWorklist.insert(u); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[addWorklist] Node " << regIdToString(u) << " added to simplifyWorklist (degree: " << degree.at(u) << ", K: " << K << ").\n"; } } @@ -1184,7 +1159,7 @@ void RISCv64RegAlloc::addWorklist(unsigned u) { // Briggs启发式 bool RISCv64RegAlloc::briggsHeuristic(unsigned u, unsigned v) { - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "\n[Briggs] >>>>> Checking coalesce between " << regIdToString(u) << " and " << regIdToString(v) << " <<<<<\n"; } @@ -1196,7 +1171,7 @@ bool RISCv64RegAlloc::briggsHeuristic(unsigned u, unsigned v) { VRegSet all_adj = u_adj; all_adj.insert(v_adj.begin(), v_adj.end()); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { auto print_set = [this](const VRegSet& s, const std::string& name) { std::cerr << "[Briggs] " << name << " (" << s.size() << "): { "; for (unsigned id : s) std::cerr << regIdToString(id) << " "; @@ -1209,14 +1184,14 @@ bool RISCv64RegAlloc::briggsHeuristic(unsigned u, unsigned v) { // 步骤 3: 遍历合并后的邻居集合,计算度数 >= K 的节点数量 int k = 0; - if (DEEPDEBUG) std::cerr << "[Briggs] Checking significance of combined neighbors:\n"; + if (DEEPERDEBUG) std::cerr << "[Briggs] Checking significance of combined neighbors:\n"; for (unsigned n : all_adj) { // 关键修正:只考虑那些在工作集中的邻居节点 n if (degree.count(n) > 0) { int K = isFPVReg(n) ? K_fp : K_int; if (degree.at(n) >= K) { k++; - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[Briggs] - Node " << regIdToString(n) << " is significant (degree " << degree.at(n) << " >= " << K << "). Count k is now " << k << ".\n"; } } @@ -1227,12 +1202,11 @@ bool RISCv64RegAlloc::briggsHeuristic(unsigned u, unsigned v) { int K_u = isFPVReg(u) ? K_fp : K_int; bool result = (k < K_u); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[Briggs] Final count of significant neighbors (k) = " << k << ".\n"; std::cerr << "[Briggs] K value for node " << regIdToString(u) << " is " << K_u << ".\n"; std::cerr << "[Briggs] >>>>> Result (k < K): " << (result ? "OK (can coalesce)" : "FAIL (cannot coalesce)") << "\n\n"; } - return result; } @@ -1336,7 +1310,7 @@ void RISCv64RegAlloc::freezeMoves(unsigned u) { if (!precolored.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) { freezeWorklist.erase(v_alias); simplifyWorklist.insert(v_alias); - if (DEEPDEBUG) { + if (DEEPERDEBUG) { std::cerr << "[freezeMoves] Node " << regIdToString(v_alias) << " moved to simplifyWorklist (degree: " << degree.at(v_alias) << ").\n"; } } @@ -1431,9 +1405,26 @@ void RISCv64RegAlloc::dumpState(const std::string& stage) { if (!DEEPDEBUG) return; std::cerr << "\n=============== STATE DUMP (" << stage << ") ===============\n"; auto print_vreg_set = [&](const VRegSet& s, const std::string& name){ - std::cerr << name << " (" << s.size() << "): { "; - for(unsigned v : s) std::cerr << "%vreg" << v << " "; - std::cerr << "}\n"; + if (s.size() > DEBUGLENGTH) { + std::cerr << name << " (" << s.size() << ")\n"; + } + else { + std::cerr << name << " (" << s.size() << "): { "; + for(unsigned v : s) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + } + + }; + auto print_vreg_stack = [&](const VRegStack& s, const std::string& name){ + if (s.size() > DEBUGLENGTH) { + std::cerr << name << " (" << s.size() << ")\n"; + } + else { + std::cerr << name << " (" << s.size() << "): { "; + for(unsigned v : s) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + } + }; print_vreg_set(simplifyWorklist, "SimplifyWorklist"); print_vreg_set(freezeWorklist, "FreezeWorklist"); @@ -1441,9 +1432,7 @@ void RISCv64RegAlloc::dumpState(const std::string& stage) { print_vreg_set(coalescedNodes, "CoalescedNodes"); print_vreg_set(spilledNodes, "SpilledNodes"); - std::cerr << "SelectStack (" << selectStack.size() << "): { "; - for(unsigned v : selectStack) std::cerr << "%vreg" << v << " "; - std::cerr << "}\n"; + print_vreg_stack(selectStack, "SelectStack"); std::cerr << "WorklistMoves (" << worklistMoves.size() << ")\n"; std::cerr << "ActiveMoves (" << activeMoves.size() << ")\n"; diff --git a/src/include/backend/RISCv64/RISCv64RegAlloc.h b/src/include/backend/RISCv64/RISCv64RegAlloc.h index caf8149..bea9ddc 100644 --- a/src/include/backend/RISCv64/RISCv64RegAlloc.h +++ b/src/include/backend/RISCv64/RISCv64RegAlloc.h @@ -1,5 +1,3 @@ -// in file: RISCv64RegAlloc.h - #ifndef RISCV64_REGALLOC_H #define RISCV64_REGALLOC_H @@ -12,6 +10,8 @@ extern int DEBUG; extern int DEEPDEBUG; +extern int DEBUGLENGTH; // 用于限制调试输出的长度 +extern int DEEPERDEBUG; // 用于更深层次的调试输出 namespace sysy { diff --git a/src/sysyc.cpp b/src/sysyc.cpp index 04da485..747eb89 100644 --- a/src/sysyc.cpp +++ b/src/sysyc.cpp @@ -21,6 +21,8 @@ using namespace sysy; int DEBUG = 0; int DEEPDEBUG = 0; +int DEEPERDEBUG = 0; +int DEBUGLENGTH = 50; static string argStopAfter; static string argInputFile; From 004ef8248859598ba8ff27bf552078b3154cf401 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Sat, 2 Aug 2025 15:10:19 +0800 Subject: [PATCH 09/10] =?UTF-8?q?[backend-IRC]=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=B8=8D=E9=80=82=E9=85=8D=E4=B8=AD=E7=AB=AF?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E5=8F=98=E9=87=8F=E5=AE=9A=E4=B9=89=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/RISCv64/RISCv64Backend.cpp | 103 +++++++++++++++---- src/include/backend/RISCv64/RISCv64Backend.h | 3 + 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index dc9c089..90caeef 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -12,6 +12,39 @@ std::string RISCv64CodeGen::code_gen() { return module_gen(); } +unsigned RISCv64CodeGen::getTypeSizeInBytes(Type* type) { + if (!type) { + assert(false && "Cannot get size of a null type."); + return 0; + } + + switch (type->getKind()) { + // 对于SysY语言,基本类型int和float都占用4字节 + case Type::kInt: + case Type::kFloat: + return 4; + + // 指针类型在RISC-V 64位架构下占用8字节 + // 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型 + case Type::kPointer: + return 8; + + // 数组类型的总大小 = 元素数量 * 单个元素的大小 + case Type::kArray: { + auto arrayType = type->as(); + // 递归调用以计算元素大小 + return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType()); + } + + // 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里 + default: + // 如果遇到未处理的类型,触发断言,方便调试 + // assert(false && "Unsupported type for size calculation."); + return 0; // 对于像Label或Void这样的类型,返回0是合理的 + } +} + + void printInitializer(std::stringstream& ss, const ValueCounter& init_values) { for (size_t i = 0; i < init_values.getValues().size(); ++i) { auto val = init_values.getValues()[i]; @@ -39,18 +72,36 @@ std::string RISCv64CodeGen::module_gen() { for (const auto& global_ptr : module->getGlobals()) { GlobalValue* global = global_ptr.get(); + + // [核心修改] 使用更健壮的逻辑来判断是否为大型零初始化数组 + bool is_all_zeros = true; const auto& init_values = global->getInitValues(); - // 判断是否为大型零初始化数组,以便放入.bss段 - bool is_large_zero_array = false; - if (init_values.getValues().size() == 1) { - if (auto const_val = dynamic_cast(init_values.getValues()[0])) { - if (const_val->isInt() && const_val->getInt() == 0 && init_values.getNumbers()[0] > 16) { - is_large_zero_array = true; + // 检查初始化值是否全部为0 + if (init_values.getValues().empty()) { + // 如果 ValueCounter 为空,GlobalValue 的构造函数会确保它是零初始化的 + is_all_zeros = true; + } else { + for (auto val : init_values.getValues()) { + if (auto const_val = dynamic_cast(val)) { + if (!const_val->isZero()) { + is_all_zeros = false; + break; + } + } else { + // 如果初始值包含非常量(例如,另一个全局变量的地址),则不认为是纯零初始化 + is_all_zeros = false; + break; } } } + // 使用 getTypeSizeInBytes 检查总大小是否超过阈值 (16个整数 = 64字节) + Type* allocated_type = global->getType()->as()->getBaseType(); + unsigned total_size = getTypeSizeInBytes(allocated_type); + + bool is_large_zero_array = is_all_zeros && (total_size > 64); + if (is_large_zero_array) { bss_globals.push_back(global); } else { @@ -58,12 +109,12 @@ std::string RISCv64CodeGen::module_gen() { } } - // --- 步骤2:生成 .bss 段的代码 (这部分不变) --- + // --- 步骤2:生成 .bss 段的代码 --- if (!bss_globals.empty()) { ss << ".bss\n"; for (GlobalValue* global : bss_globals) { - unsigned count = global->getInitValues().getNumbers()[0]; - unsigned total_size = count * 4; // 假设元素都是4字节 + Type* allocated_type = global->getType()->as()->getBaseType(); + unsigned total_size = getTypeSizeInBytes(allocated_type); ss << " .align 3\n"; ss << ".globl " << global->getName() << "\n"; @@ -74,33 +125,45 @@ std::string RISCv64CodeGen::module_gen() { } } - // --- [修改] 步骤3:生成 .data 段的代码 --- - // 我们需要检查 data_globals 和 常量列表是否都为空 + // --- 步骤3:生成 .data 段的代码 --- if (!data_globals.empty() || !module->getConsts().empty()) { ss << ".data\n"; - // a. 先处理普通的全局变量 (GlobalValue) + // a. 处理普通的全局变量 (GlobalValue) for (GlobalValue* global : data_globals) { + Type* allocated_type = global->getType()->as()->getBaseType(); + unsigned total_size = getTypeSizeInBytes(allocated_type); + + ss << " .align 3\n"; ss << ".globl " << global->getName() << "\n"; + ss << ".type " << global->getName() << ", @object\n"; + ss << ".size " << global->getName() << ", " << total_size << "\n"; ss << global->getName() << ":\n"; printInitializer(ss, global->getInitValues()); } - // b. [新增] 再处理全局常量 (ConstantVariable) + // b. 处理全局常量 (ConstantVariable) for (const auto& const_ptr : module->getConsts()) { ConstantVariable* cnst = const_ptr.get(); + Type* allocated_type = cnst->getType()->as()->getBaseType(); + unsigned total_size = getTypeSizeInBytes(allocated_type); + + ss << " .align 3\n"; ss << ".globl " << cnst->getName() << "\n"; + ss << ".type " << cnst->getName() << ", @object\n"; + ss << ".size " << cnst->getName() << ", " << total_size << "\n"; ss << cnst->getName() << ":\n"; printInitializer(ss, cnst->getInitValues()); } } - // --- 处理函数 (.text段) 的逻辑保持不变 --- + // --- 步骤4:处理函数 (.text段) 的逻辑 --- if (!module->getFunctions().empty()) { ss << ".text\n"; for (const auto& func_pair : module->getFunctions()) { - if (func_pair.second.get()) { + if (func_pair.second.get() && !func_pair.second->getBasicBlocks().empty()) { ss << function_gen(func_pair.second.get()); + if (DEBUG) std::cerr << "Function: " << func_pair.first << " generated.\n"; } } } @@ -161,10 +224,10 @@ std::string RISCv64CodeGen::function_gen(Function* func) { RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); - DEBUG = 0; - DEEPDEBUG = 0; - // DEBUG = 1; - // DEEPDEBUG = 1; + // DEBUG = 0; + // DEEPDEBUG = 0; + DEBUG = 1; + DEEPDEBUG = 1; if (DEBUG) { std::cerr << "====== stack info after reg alloc ======\n"; mfunc->dumpStackFrameInfo(std::cerr); @@ -207,6 +270,8 @@ std::string RISCv64CodeGen::function_gen(Function* func) { ss << "\n\n; --- Intermediate Representation after Instruction Selection ---\n" << ss_after_isel.str(); } + DEBUG = 1; + DEEPDEBUG = 1; return ss.str(); } diff --git a/src/include/backend/RISCv64/RISCv64Backend.h b/src/include/backend/RISCv64/RISCv64Backend.h index 403d586..7b9afe7 100644 --- a/src/include/backend/RISCv64/RISCv64Backend.h +++ b/src/include/backend/RISCv64/RISCv64Backend.h @@ -22,6 +22,9 @@ private: // 函数级代码生成 (实现新的流水线) std::string function_gen(Function* func); + // 私有辅助函数,用于根据类型计算其占用的字节数。 + unsigned getTypeSizeInBytes(Type* type); + Module* module; }; From 845f969c2ea6891a47a60049378e72bfdabb4359 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Sun, 3 Aug 2025 14:42:19 +0800 Subject: [PATCH 10/10] =?UTF-8?q?[backend-IRC]=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E7=8E=B0=E5=9C=BA=E7=AE=A1=E7=90=86=E4=B8=8E=E6=BA=A2=E5=87=BA?= =?UTF-8?q?=E5=A4=84=E7=90=86=E7=9A=84=E6=A0=88=E5=81=8F=E7=A7=BB=E9=87=8F?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/runit-riscv64.sh | 6 +- .../RISCv64/Handler/EliminateFrameIndices.cpp | 53 ++++++++++++++-- .../Handler/PrologueEpilogueInsertion.cpp | 61 ++++++++----------- src/backend/RISCv64/RISCv64RegAlloc.cpp | 31 ++++++++-- src/include/backend/RISCv64/RISCv64LLIR.h | 3 +- 5 files changed, 101 insertions(+), 53 deletions(-) diff --git a/script/runit-riscv64.sh b/script/runit-riscv64.sh index 3a0026f..00e65a4 100644 --- a/script/runit-riscv64.sh +++ b/script/runit-riscv64.sh @@ -60,11 +60,7 @@ display_file_content() { # 清理临时文件的函数 clean_tmp() { echo "正在清理临时目录: ${TMP_DIR}" - rm -rf "${TMP_DIR}"/*.s \ - "${TMP_DIR}"/*_sysyc_riscv64 \ - "${TMP_DIR}"/*_sysyc_riscv64.actual_out \ - "${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \ - "${TMP_DIR}"/*_sysyc_riscv64.o + rm -rf "${TMP_DIR}"/* echo "清理完成。" } diff --git a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp index 6973293..59f4db3 100644 --- a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp +++ b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp @@ -29,6 +29,8 @@ unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) { } void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { +// [方案一修改] 这是修改后完整的函数代码。 +// 主要的逻辑变更在原注释"[核心修改]"部分。 StackFrameInfo& frame_info = mfunc->getFrameInfo(); Function* F = mfunc->getFunc(); RISCv64ISel* isel = mfunc->getISel(); @@ -65,6 +67,8 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { // 记录仅由AllocaInst分配的局部变量的总大小 frame_info.locals_size = local_var_offset - 16; + // [新增] 记录局部变量区域分配结束的最终偏移量 + frame_info.locals_end_offset = -local_var_offset; // 3. [核心修改] 在函数入口为所有栈传递的参数插入load指令 // 这个步骤至关重要:它在寄存器分配之前,为这些参数的vreg创建了明确的“定义(def)”指令。 @@ -72,6 +76,8 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { if (F && isel && !mfunc->getBlocks().empty()) { MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); std::vector> arg_load_instrs; + + // 步骤 3.1: 生成所有加载栈参数的指令,暂存起来 int arg_idx = 0; for (Argument* arg : F->getArguments()) { // 根据ABI,前8个整型/指针参数通过寄存器传递,这里只处理超出部分。 @@ -104,13 +110,48 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { arg_idx++; } - // 将所有新创建的参数加载指令一次性插入到入口块的起始位置 - auto& entry_instrs = entry_block->getInstructions(); - entry_instrs.insert(entry_instrs.begin(), - std::make_move_iterator(arg_load_instrs.begin()), - std::make_move_iterator(arg_load_instrs.end())); - } + // [方案一修改] 仅当有需要加载的栈参数时,才执行插入逻辑 + if (!arg_load_instrs.empty()) { + auto& entry_instrs = entry_block->getInstructions(); + auto insertion_point = entry_instrs.begin(); // 默认插入点为块的开头 + auto last_arg_save_it = entry_instrs.end(); + // 步骤 3.2: 寻找一个安全的插入点。 + // 遍历入口块的指令,找到最后一条保存“寄存器传递参数”的伪指令。 + // 这样可以确保我们在所有 a0-a7 参数被保存之后,才执行可能覆盖它们的加载指令。 + for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) { + MachineInstr* instr = it->get(); + // 寻找代表保存参数到栈的伪指令 + if (instr->getOpcode() == RVOpcodes::FRAME_STORE_W || + instr->getOpcode() == RVOpcodes::FRAME_STORE_D || + instr->getOpcode() == RVOpcodes::FRAME_STORE_F) { + + // 检查被保存的值是否是寄存器参数 (arg_no < 8) + auto& operands = instr->getOperands(); + if (operands.empty() || operands[0]->getKind() != MachineOperand::KIND_REG) continue; + + unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); + Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr; + + if (auto ir_arg = dynamic_cast(ir_value)) { + if (ir_arg->getIndex() < 8) { + last_arg_save_it = it; // 找到了一个保存寄存器参数的指令,更新位置 + } + } + } + } + + // 如果找到了这样的保存指令,我们的插入点就在它之后 + if (last_arg_save_it != entry_instrs.end()) { + insertion_point = std::next(last_arg_save_it); + } + + // 步骤 3.3: 在计算出的安全位置,一次性插入所有新创建的参数加载指令 + entry_instrs.insert(insertion_point, + std::make_move_iterator(arg_load_instrs.begin()), + std::make_move_iterator(arg_load_instrs.end())); + } + } // 4. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令 // 由于处理参数的逻辑已移除,这里的展开现在只针对局部变量,因此是正确的。 diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index ef86ea7..245a275 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -9,7 +9,12 @@ namespace sysy { char PrologueEpilogueInsertionPass::ID = 0; +// [函数上下文] +// ... + void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { +// [最终修正] 这是修正后完整的函数代码。 +// 序言(4.4)和尾声(5.1)中的循环逻辑现在完全一致。 StackFrameInfo& frame_info = mfunc->getFrameInfo(); Function* F = mfunc->getFunc(); RISCv64ISel* isel = mfunc->getISel(); @@ -27,8 +32,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) ); } - // 2. [新增] 确定需要保存的被调用者保存寄存器 (callee-saved) - // 这部分逻辑从 CalleeSavedHandler Pass 移入,以集中管理序言生成 + // 2. 确定需要保存的被调用者保存寄存器 (callee-saved) auto& vreg_to_preg_map = frame_info.vreg_to_preg_map; std::set used_callee_saved_regs_set; const auto& callee_saved_int = getCalleeSavedIntRegs(); @@ -36,38 +40,34 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) for (const auto& pair : vreg_to_preg_map) { PhysicalReg preg = pair.second; - // 检查是否在整数或浮点 callee-saved 集合中 - // 注意:s0作为帧指针,由序言/尾声逻辑特殊处理,不在此处保存 bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end(); bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end(); if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) { used_callee_saved_regs_set.insert(preg); } } - // 为了确定性排序,并存入 frame_info 供尾声使用 frame_info.callee_saved_regs_to_store.assign( used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end() ); std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end()); - frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8; // 每个寄存器8字节 + frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8; // 3. 计算最终的栈帧总大小 int total_stack_size = frame_info.locals_size + frame_info.spill_size + frame_info.callee_saved_size + - 16; // 为 ra 和 s0 固定的16字节 + 16; - int aligned_stack_size = (total_stack_size + 15) & ~15; // 16字节对齐 + int aligned_stack_size = (total_stack_size + 15) & ~15; frame_info.total_size = aligned_stack_size; - // 只有在需要分配栈空间时才生成序言和尾声 if (aligned_stack_size > 0) { // --- 4. 插入完整的序言 --- MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); auto& entry_instrs = entry_block->getInstructions(); std::vector> prologue_instrs; - // 4.1. 分配栈帧: addi sp, sp, -aligned_stack_size + // 4.1. 分配栈帧 auto alloc_stack = std::make_unique(RVOpcodes::ADDI); alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); @@ -75,7 +75,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) prologue_instrs.push_back(std::move(alloc_stack)); // 4.2. 保存 ra 和 s0 - // sd ra, (aligned_stack_size - 8)(sp) auto save_ra = std::make_unique(RVOpcodes::SD); save_ra->addOperand(std::make_unique(PhysicalReg::RA)); save_ra->addOperand(std::make_unique( @@ -83,7 +82,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::make_unique(aligned_stack_size - 8) )); prologue_instrs.push_back(std::move(save_ra)); - // sd s0, (aligned_stack_size - 16)(sp) auto save_fp = std::make_unique(RVOpcodes::SD); save_fp->addOperand(std::make_unique(PhysicalReg::S0)); save_fp->addOperand(std::make_unique( @@ -92,60 +90,55 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); prologue_instrs.push_back(std::move(save_fp)); - // 4.3. 设置新的帧指针 s0: addi s0, sp, aligned_stack_size + // 4.3. 设置新的帧指针 s0 auto set_fp = std::make_unique(RVOpcodes::ADDI); set_fp->addOperand(std::make_unique(PhysicalReg::S0)); set_fp->addOperand(std::make_unique(PhysicalReg::SP)); set_fp->addOperand(std::make_unique(aligned_stack_size)); prologue_instrs.push_back(std::move(set_fp)); - // 4.4. [新增] 保存所有使用到的被调用者保存寄存器 - // 它们保存在 s0 下方,紧接着 ra/s0 的位置 - int callee_saved_offset = -16; + // 4.4. 保存所有使用到的被调用者保存寄存器 + int next_available_offset = -(16 + frame_info.locals_size + frame_info.spill_size); for (const auto& reg : frame_info.callee_saved_regs_to_store) { - callee_saved_offset -= 8; - RVOpcodes store_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD; + // [修正] 采用“先使用,后更新”逻辑 + RVOpcodes store_op = isFPR(reg) ? RVOpcodes::FSD : RVOpcodes::SD; auto save_cs_reg = std::make_unique(store_op); save_cs_reg->addOperand(std::make_unique(reg)); save_cs_reg->addOperand(std::make_unique( std::make_unique(PhysicalReg::S0), - std::make_unique(callee_saved_offset) + std::make_unique(next_available_offset) // 使用当前偏移 )); prologue_instrs.push_back(std::move(save_cs_reg)); + next_available_offset -= 8; // 为下一个寄存器准备偏移 } - // 4.5. [核心修改] 加载栈传递参数的逻辑已从此移除 - // 这项工作已经前移至 `EliminateFrameIndicesPass` 中完成, - // 以确保在寄存器分配前就将相关虚拟寄存器定义,从而修复溢出逻辑的bug。 - - // 4.6. 将所有生成的序言指令一次性插入到函数入口 + // 4.5. 将所有生成的序言指令一次性插入到函数入口 entry_instrs.insert(entry_instrs.begin(), std::make_move_iterator(prologue_instrs.begin()), std::make_move_iterator(prologue_instrs.end())); // --- 5. 插入完整的尾声 --- for (auto& mbb : mfunc->getBlocks()) { - // [修正] 使用前向迭代器查找RET指令,以确保在正确的位置(RET之前)插入尾声。 for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { if ((*it)->getOpcode() == RVOpcodes::RET) { std::vector> epilogue_instrs; - // 5.1. [新增] 恢复被调用者保存寄存器 - callee_saved_offset = -16; + // 5.1. 恢复被调用者保存寄存器 + // [修正] 采用与序言完全相同的“先使用,后更新”逻辑 + int next_available_offset_restore = -(16 + frame_info.locals_size + frame_info.spill_size); for (const auto& reg : frame_info.callee_saved_regs_to_store) { - callee_saved_offset -= 8; - RVOpcodes load_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD; + RVOpcodes load_op = isFPR(reg) ? RVOpcodes::FLD : RVOpcodes::LD; auto restore_cs_reg = std::make_unique(load_op); restore_cs_reg->addOperand(std::make_unique(reg)); restore_cs_reg->addOperand(std::make_unique( std::make_unique(PhysicalReg::S0), - std::make_unique(callee_saved_offset) + std::make_unique(next_available_offset_restore) // 使用当前偏移 )); epilogue_instrs.push_back(std::move(restore_cs_reg)); + next_available_offset_restore -= 8; // 为下一个寄存器准备偏移 } - // 5.2. 恢复 ra 和 s0 (注意基址现在是sp) - // ld ra, (aligned_stack_size - 8)(sp) + // 5.2. 恢复 ra 和 s0 auto restore_ra = std::make_unique(RVOpcodes::LD); restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); restore_ra->addOperand(std::make_unique( @@ -153,7 +146,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::make_unique(aligned_stack_size - 8) )); epilogue_instrs.push_back(std::move(restore_ra)); - // ld s0, (aligned_stack_size - 16)(sp) auto restore_fp = std::make_unique(RVOpcodes::LD); restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); restore_fp->addOperand(std::make_unique( @@ -162,7 +154,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); epilogue_instrs.push_back(std::move(restore_fp)); - // 5.3. 释放栈帧: addi sp, sp, aligned_stack_size + // 5.3. 释放栈帧 auto dealloc_stack = std::make_unique(RVOpcodes::ADDI); dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); dealloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); @@ -174,7 +166,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::make_move_iterator(epilogue_instrs.begin()), std::make_move_iterator(epilogue_instrs.end())); - // 一个基本块通常只有一个终止指令,处理完就可以跳到下一个块 goto next_block; } } diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 76f003b..aa6c956 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -647,11 +647,22 @@ void RISCv64RegAlloc::assignColors() { } } +// 在文件 RISCv64RegAlloc.cpp 中: + +// [函数上下文] +// ... +// 我将修改下面这个函数 +// ... + // 重写程序,插入溢出代码 void RISCv64RegAlloc::rewriteProgram() { - // 1. 为溢出的旧vreg在栈上分配空间 StackFrameInfo& frame_info = MFunc->getFrameInfo(); - int spill_base_offset = frame_info.locals_size + frame_info.callee_saved_size; + // 使用 EFI Pass 确定的 locals_end_offset 作为溢出分配的基准。 + // locals_end_offset 本身是负数,代表局部变量区域的下边界地址。 + int spill_current_offset = frame_info.locals_end_offset; + + // [新增] 保存溢出区域的起始点,用于最后计算总的 spill_size + const int spill_start_offset = frame_info.locals_end_offset; for (unsigned vreg : spilledNodes) { if (frame_info.spill_offsets.count(vreg)) continue; @@ -663,11 +674,19 @@ void RISCv64RegAlloc::rewriteProgram() { size = 8; // pointer } - spill_base_offset += size; - spill_base_offset = (spill_base_offset + 7) & ~7; - frame_info.spill_offsets[vreg] = -spill_base_offset; // [修正] 溢出槽也使用负偏移量 + // [修改] 在当前偏移基础上继续向下(地址变得更负)分配空间 + spill_current_offset -= size; + + // [修改] 对齐新的、更小的地址,RISC-V 要求8字节对齐 + spill_current_offset = spill_current_offset & ~7; + + // 将计算出的、不会冲突的正确偏移量存入 spill_offsets + frame_info.spill_offsets[vreg] = spill_current_offset; } - frame_info.spill_size = spill_base_offset - (frame_info.locals_size + frame_info.callee_saved_size); + + // [修改] 更新总的溢出区域大小。 + // spill_size = -(结束偏移 - 开始偏移) + frame_info.spill_size = -(spill_current_offset - spill_start_offset); // 2. 遍历所有指令,重写代码 for (auto& mbb : MFunc->getBlocks()) { diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index 1931617..0cd6b9b 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -39,7 +39,7 @@ enum class PhysicalReg { // 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突) // 假设 vreg_counter 不会达到这么大的值 - PHYS_REG_START_ID = 100000, + PHYS_REG_START_ID = 1000000, PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间 }; @@ -280,6 +280,7 @@ private: // 栈帧信息 struct StackFrameInfo { int locals_size = 0; // 仅为AllocaInst分配的大小 + int locals_end_offset = 0; // [新增] 记录局部变量分配结束后的偏移量(相对于s0,为负) int spill_size = 0; // 仅为溢出分配的大小 int total_size = 0; // 总大小 int callee_saved_size = 0; // 保存寄存器的大小