diff --git a/src/RISCv64AsmPrinter.cpp b/src/RISCv64AsmPrinter.cpp index 8c0b10c..3c9d0c6 100644 --- a/src/RISCv64AsmPrinter.cpp +++ b/src/RISCv64AsmPrinter.cpp @@ -46,46 +46,6 @@ void RISCv64AsmPrinter::printPrologue() { *OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n"; *OS << " addi s0, sp, " << aligned_stack_size << "\n"; } - - // // 为函数参数分配寄存器 - // Function* F = MFunc->getFunc(); - // if (F && F->getEntryBlock()) { - // int arg_idx = 0; - // RISCv64ISel* isel = MFunc->getISel(); - - // // 获取函数所有参数的类型列表 - // auto param_types = F->getParamTypes(); - - // for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) { - // if (arg_idx >= 8) break; - - // unsigned vreg = isel->getVReg(alloca_for_param); - // if (frame_info.alloca_offsets.count(vreg)) { - // int offset = frame_info.alloca_offsets.at(vreg); - // auto arg_reg = static_cast(static_cast(PhysicalReg::A0) + arg_idx); - - // // 1. 获取当前参数的真实类型 - // // 注意:F->getParamTypes() 返回的是一个 range-based view,需要转换为vector或直接使用 - // Type* current_param_type = nullptr; - // int temp_idx = 0; - // for(auto p_type : param_types) { - // if (temp_idx == arg_idx) { - // current_param_type = p_type; - // break; - // } - // temp_idx++; - // } - // assert(current_param_type && "Could not find parameter type."); - - // // 2. 根据类型决定使用 "sw" 还是 "sd" - // const char* store_op = current_param_type->isPointer() ? "sd" : "sw"; - - // // 3. 打印正确的存储指令 - // *OS << " " << store_op << " " << regToString(arg_reg) << ", " << offset << "(s0)\n"; - // } - // arg_idx++; - // } - // } } void RISCv64AsmPrinter::printEpilogue() { diff --git a/src/RISCv64Backend.cpp b/src/RISCv64Backend.cpp index c429a63..4ee03cc 100644 --- a/src/RISCv64Backend.cpp +++ b/src/RISCv64Backend.cpp @@ -73,6 +73,10 @@ std::string RISCv64CodeGen::function_gen(Function* func) { RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); + // 阶段 3.5: 处理被调用者保存寄存器 + CalleeSavedHandler callee_handler; + callee_handler.runOnMachineFunction(mfunc.get()); + // 阶段 4: 窥孔优化 (Peephole Optimization) PeepholeOptimizer peephole; peephole.runOnMachineFunction(mfunc.get()); diff --git a/src/RISCv64Passes.cpp b/src/RISCv64Passes.cpp index 5d7c8ad..efa333f 100644 --- a/src/RISCv64Passes.cpp +++ b/src/RISCv64Passes.cpp @@ -51,4 +51,99 @@ void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) { // std::cout << "Running Post-RA Local Scheduler..." << std::endl; } +void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { + StackFrameInfo& frame_info = mfunc->getFrameInfo(); + std::set used_callee_saved; + + // 1. 扫描所有指令,找出被使用的s寄存器 + for (auto& mbb : mfunc->getBlocks()) { + for (auto& instr : mbb->getInstructions()) { + for (auto& op : instr->getOperands()) { + + // 辅助Lambda,用于检查和插入寄存器 + auto check_and_insert_reg = [&](RegOperand* reg_op) { + if (!reg_op->isVirtual()) { + PhysicalReg preg = reg_op->getPReg(); + // --- 关键检查点 --- + // 必须严格判断是否在 s0-s11 的范围内。 + // a0, t0 等寄存器绝对不应被视为被调用者保存寄存器。 + if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) { + 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()); + } + } + } + } + + // 如果没有使用s寄存器(除了可能作为帧指针的s0),则无需操作 + if (used_callee_saved.empty() || (used_callee_saved.size() == 1 && used_callee_saved.count(PhysicalReg::S0))) { + return; + } + + // 将结果存入StackFrameInfo,供后续使用 + frame_info.used_callee_saved_regs = used_callee_saved; + + // 2. 在函数序言插入保存指令 + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + auto& entry_instrs = entry_block->getInstructions(); + auto prologue_end = entry_instrs.begin(); + + // 找到序言结束的位置(通常是addi s0, sp, size之后) + for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) { + if ((*it)->getOpcode() == RVOpcodes::ADDI && + (*it)->getOperands()[0]->getKind() == MachineOperand::KIND_REG && + static_cast((*it)->getOperands()[0].get())->getPReg() == PhysicalReg::S0) + { + prologue_end = std::next(it); + break; + } + } + + // 为了栈帧布局确定性,对寄存器进行排序 + std::vector sorted_regs(used_callee_saved.begin(), used_callee_saved.end()); + std::sort(sorted_regs.begin(), sorted_regs.end()); + + int current_offset = -16; // ra和s0已经占用了-8和-16的位置 + for (PhysicalReg reg : sorted_regs) { + if (reg == PhysicalReg::S0) continue; // s0已经在序言中处理 + current_offset -= 8; + auto sd = std::make_unique(RVOpcodes::SD); + sd->addOperand(std::make_unique(reg)); + sd->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), // 假设s0是帧指针 + std::make_unique(current_offset) + )); + entry_instrs.insert(prologue_end, std::move(sd)); + } + + // 3. 在函数结尾(ret之前)插入恢复指令 + for (auto& mbb : mfunc->getBlocks()) { + for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { + if ((*it)->getOpcode() == RVOpcodes::RET) { + // 以相反的顺序恢复 + current_offset = -16; + for (PhysicalReg reg : sorted_regs) { + if (reg == PhysicalReg::S0) continue; + current_offset -= 8; + auto ld = std::make_unique(RVOpcodes::LD); + ld->addOperand(std::make_unique(reg)); + ld->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(current_offset) + )); + mbb->getInstructions().insert(it, std::move(ld)); + } + break; // 处理完一个基本块的ret即可 + } + } + } +} + } // namespace sysy \ No newline at end of file diff --git a/src/RISCv64RegAlloc.cpp b/src/RISCv64RegAlloc.cpp index 0dfbd7d..97f9614 100644 --- a/src/RISCv64RegAlloc.cpp +++ b/src/RISCv64RegAlloc.cpp @@ -36,7 +36,6 @@ void RISCv64RegAlloc::handleCallingConvention() { // 获取函数的Argument对象列表 if (F) { auto& args = F->getArguments(); - // RISC-V RV64G调用约定:前8个整型/指针参数通过 a0-a7 传递 int arg_idx = 0; // 遍历 AllocaInst* 列表 @@ -494,10 +493,6 @@ void RISCv64RegAlloc::rewriteFunction() { if (color_map.count(vreg)) { PhysicalReg preg = color_map.at(vreg); reg_op->setPReg(preg); - // 检查这个物理寄存器是否是 s0-s11 - if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) { - used_callee_saved_regs.insert(preg); - } } else if (spilled_vregs.count(vreg)) { // 如果vreg被溢出,替换为专用的溢出物理寄存器t6 reg_op->setPReg(PhysicalReg::T6); @@ -512,14 +507,16 @@ void RISCv64RegAlloc::rewriteFunction() { // 对这个基址寄存器,执行与情况一完全相同的替换逻辑 if(base_reg_op->isVirtual()){ - unsigned vreg = base_reg_op->getVRegNum(); - if(color_map.count(vreg)) { - // 如果基址vreg被成功着色,替换 - base_reg_op->setPReg(color_map.at(vreg)); - } else if (spilled_vregs.count(vreg)) { - // 如果基址vreg被溢出,替换为t6 - base_reg_op->setPReg(PhysicalReg::T6); - } + unsigned vreg = base_reg_op->getVRegNum(); + if(color_map.count(vreg)) { + // 如果基址vreg被成功着色,替换 + PhysicalReg preg = color_map.at(vreg); + base_reg_op->setPReg(preg); + + } else if (spilled_vregs.count(vreg)) { + // 如果基址vreg被溢出,替换为t6 + base_reg_op->setPReg(PhysicalReg::T6); + } } } } diff --git a/src/include/RISCv64LLIR.h b/src/include/RISCv64LLIR.h index d8797bc..0331d78 100644 --- a/src/include/RISCv64LLIR.h +++ b/src/include/RISCv64LLIR.h @@ -18,8 +18,24 @@ namespace sysy { // 物理寄存器定义 enum class PhysicalReg { - ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6, - F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31 + // --- 特殊功能寄存器 --- + ZERO, RA, SP, GP, TP, + + // --- 整数寄存器 (按调用约定分组) --- + // 临时寄存器 (调用者保存) + T0, T1, T2, T3, T4, T5, T6, + + // 保存寄存器 (被调用者保存) + S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, + + // 参数/返回值寄存器 (调用者保存) + A0, A1, A2, A3, A4, A5, A6, A7, + + // --- 浮点寄存器 --- + // (保持您原有的 F0-F31 命名) + F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, + F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, + F22, F23, F24, F25, F26, F27, F28, F29, F30, F31 }; // RISC-V 指令操作码枚举 @@ -173,6 +189,7 @@ struct StackFrameInfo { int total_size = 0; // 总大小 std::map alloca_offsets; // std::map spill_offsets; // <溢出vreg, 栈偏移> + std::set used_callee_saved_regs; // 使用的保存寄存器 }; // 机器函数 diff --git a/src/include/RISCv64Passes.h b/src/include/RISCv64Passes.h index d2da152..56013ae 100644 --- a/src/include/RISCv64Passes.h +++ b/src/include/RISCv64Passes.h @@ -31,6 +31,20 @@ public: }; +/** + * @class CalleeSavedHandler + * @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。 + * * 这个Pass在寄存器分配之后运行。它的主要职责是: + * 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。 + * 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。 + * 3. 在函数结尾(ret指令前)插入 `ld` 指令来恢复这些寄存器。 + * 4. 正确计算因保存这些寄存器而需要的额外栈空间,并更新StackFrameInfo。 + */ +class CalleeSavedHandler : public BackendPass { +public: + void runOnMachineFunction(MachineFunction* mfunc) override; +}; + // --- 寄存器分配后优化 --- /** diff --git a/src/include/RISCv64RegAlloc.h b/src/include/RISCv64RegAlloc.h index e7786ed..6fbecb5 100644 --- a/src/include/RISCv64RegAlloc.h +++ b/src/include/RISCv64RegAlloc.h @@ -56,8 +56,6 @@ private: // 存储vreg到IR Value*的反向映射 // 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。 std::map vreg_to_value_map; - - std::set used_callee_saved_regs; // 用于计算类型大小的辅助函数 unsigned getTypeSizeInBytes(Type* type);