From 1fb5cd398dd71dcfda79f9fff4864c688f3f2db4 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Wed, 30 Jul 2025 17:58:39 +0800 Subject: [PATCH] =?UTF-8?q?[backend]=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=A4=9A?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=BC=A0=E9=80=92=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/CalleeSavedHandler.cpp | 34 +++++++-- .../Handler/PrologueEpilogueInsertion.cpp | 76 ++++++++++++++++--- src/backend/RISCv64/RISCv64RegAlloc.cpp | 7 +- src/include/backend/RISCv64/RISCv64LLIR.h | 1 + 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp index c69d154..47b92e0 100644 --- a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp +++ b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp @@ -1,6 +1,8 @@ #include "CalleeSavedHandler.h" #include +#include // #include +#include // namespace sysy { @@ -77,9 +79,10 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { std::sort(sorted_int_regs.begin(), sorted_int_regs.end()); std::sort(sorted_fp_regs.begin(), sorted_fp_regs.end()); + std::vector> save_instrs; int current_offset = -16; // ra和s0已占用-8和-16,从-24开始分配 - // 插入整数保存指令 (sd) + // 准备整数保存指令 (sd) for (PhysicalReg reg : sorted_int_regs) { current_offset -= 8; auto sd = std::make_unique(RVOpcodes::SD); @@ -88,10 +91,10 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { std::make_unique(PhysicalReg::S0), // 基址为帧指针 s0 std::make_unique(current_offset) )); - entry_instrs.insert(insert_pos, std::move(sd)); + save_instrs.push_back(std::move(sd)); } - // 插入浮点保存指令 (fsd) + // 准备浮点保存指令 (fsd) for (PhysicalReg reg : sorted_fp_regs) { current_offset -= 8; auto fsd = std::make_unique(RVOpcodes::FSD); // 使用浮点保存指令 @@ -100,16 +103,24 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { std::make_unique(PhysicalReg::S0), std::make_unique(current_offset) )); - entry_instrs.insert(insert_pos, std::move(fsd)); + save_instrs.push_back(std::move(fsd)); + } + + // 一次性插入所有保存指令 + if (!save_instrs.empty()) { + entry_instrs.insert(insert_pos, + std::make_move_iterator(save_instrs.begin()), + std::make_move_iterator(save_instrs.end())); } // 4. 在函数结尾(ret之前)插入恢复指令 for (auto& mbb : mfunc->getBlocks()) { for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { if ((*it)->getOpcode() == RVOpcodes::RET) { + std::vector> restore_instrs; current_offset = -16; // 重置偏移量用于恢复 - // 恢复整数寄存器 (ld) - 以与保存时相同的顺序 + // 准备恢复整数寄存器 (ld) - 以与保存时相同的顺序 for (PhysicalReg reg : sorted_int_regs) { current_offset -= 8; auto ld = std::make_unique(RVOpcodes::LD); @@ -118,10 +129,10 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { std::make_unique(PhysicalReg::S0), std::make_unique(current_offset) )); - mbb->getInstructions().insert(it, std::move(ld)); + restore_instrs.push_back(std::move(ld)); } - // 恢复浮点寄存器 (fld) + // 准备恢复浮点寄存器 (fld) for (PhysicalReg reg : sorted_fp_regs) { current_offset -= 8; auto fld = std::make_unique(RVOpcodes::FLD); // 使用浮点加载指令 @@ -130,7 +141,14 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { std::make_unique(PhysicalReg::S0), std::make_unique(current_offset) )); - mbb->getInstructions().insert(it, std::move(fld)); + restore_instrs.push_back(std::move(fld)); + } + + // 一次性插入所有恢复指令 + if (!restore_instrs.empty()) { + mbb->getInstructions().insert(it, + std::make_move_iterator(restore_instrs.begin()), + std::make_move_iterator(restore_instrs.end())); } // 处理完一个基本块的RET后,迭代器已失效,需跳出当前块的循环 diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index 9eec6b5..f43ca1c 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -1,4 +1,6 @@ #include "PrologueEpilogueInsertion.h" +#include "RISCv64ISel.h" +#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果 namespace sysy { @@ -6,7 +8,13 @@ char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { StackFrameInfo& frame_info = mfunc->getFrameInfo(); + Function* F = mfunc->getFunc(); + RISCv64ISel* isel = mfunc->getISel(); + // [关键] 获取寄存器分配的结果 (vreg -> preg 的映射) + // RegAlloc Pass 必须已经运行过 + auto& vreg_to_preg_map = frame_info.vreg_to_preg_map; + // 完全遵循 AsmPrinter 中的计算逻辑 int total_stack_size = frame_info.locals_size + frame_info.spill_size + @@ -24,7 +32,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::vector> prologue_instrs; - // 严格按照 AsmPrinter 的打印顺序来创建和组织指令 // 1. addi sp, sp, -aligned_stack_size auto alloc_stack = std::make_unique(RVOpcodes::ADDI); alloc_stack->addOperand(std::make_unique(PhysicalReg::SP)); @@ -57,10 +64,63 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) set_fp->addOperand(std::make_unique(aligned_stack_size)); prologue_instrs.push_back(std::move(set_fp)); - // 确定插入点(在函数名标签之后) + // --- [正确逻辑] 在s0设置完毕后,使用物理寄存器加载栈参数 --- + if (F && isel) { + // 定义暂存寄存器 + const PhysicalReg INT_SCRATCH_REG = PhysicalReg::T5; + const PhysicalReg FP_SCRATCH_REG = PhysicalReg::F7; + + int arg_idx = 0; + for (Argument* arg : F->getArguments()) { + if (arg_idx >= 8) { + unsigned vreg = isel->getVReg(arg); + + // 确认RegAlloc已经为这个vreg计算了偏移量,并且分配了物理寄存器 + if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) { + int offset = frame_info.alloca_offsets.at(vreg); + PhysicalReg dest_preg = vreg_to_preg_map.at(vreg); + Type* arg_type = arg->getType(); + + // 根据类型执行不同的加载序列 + if (arg_type->isFloat()) { + // 1. flw ft7, offset(s0) + auto load_arg = std::make_unique(RVOpcodes::FLW); + load_arg->addOperand(std::make_unique(FP_SCRATCH_REG)); + load_arg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(offset) + )); + prologue_instrs.push_back(std::move(load_arg)); + // 2. fmv.s dest_preg, ft7 + auto move_arg = std::make_unique(RVOpcodes::FMV_S); + move_arg->addOperand(std::make_unique(dest_preg)); + move_arg->addOperand(std::make_unique(FP_SCRATCH_REG)); + prologue_instrs.push_back(std::move(move_arg)); + } else { + // 确定是加载32位(lw)还是64位(ld) + RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW; + // 1. lw/ld t5, offset(s0) + auto load_arg = std::make_unique(load_op); + load_arg->addOperand(std::make_unique(INT_SCRATCH_REG)); + load_arg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(offset) + )); + prologue_instrs.push_back(std::move(load_arg)); + // 2. mv dest_preg, t5 + auto move_arg = std::make_unique(RVOpcodes::MV); + move_arg->addOperand(std::make_unique(dest_preg)); + move_arg->addOperand(std::make_unique(INT_SCRATCH_REG)); + prologue_instrs.push_back(std::move(move_arg)); + } + } + } + arg_idx++; + } + } + + // 确定插入点 auto insert_pos = entry_instrs.begin(); - // [重要] 这里我们不再需要跳过LABEL,因为AsmPrinter将不再打印函数名标签 - // 第一个基本块的标签就是函数入口 // 一次性将所有序言指令插入 if (!prologue_instrs.empty()) { @@ -69,14 +129,13 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::make_move_iterator(prologue_instrs.end())); } - // --- 2. 插入尾声 --- + // --- 2. 插入尾声 (此部分逻辑保持不变) --- for (auto& mbb : mfunc->getBlocks()) { for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { if ((*it)->getOpcode() == RVOpcodes::RET) { std::vector> epilogue_instrs; - // 同样严格按照 AsmPrinter 的打印顺序 - // 1. ld ra, (aligned_stack_size - 8)(sp) + // 1. ld ra auto restore_ra = std::make_unique(RVOpcodes::LD); restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); restore_ra->addOperand(std::make_unique( @@ -85,7 +144,7 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); epilogue_instrs.push_back(std::move(restore_ra)); - // 2. ld s0, (aligned_stack_size - 16)(sp) + // 2. ld s0 auto restore_fp = std::make_unique(RVOpcodes::LD); restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); restore_fp->addOperand(std::make_unique( @@ -106,7 +165,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::make_move_iterator(epilogue_instrs.begin()), std::make_move_iterator(epilogue_instrs.end())); } - // 处理完一个基本块中的RET后,迭代器已失效,需跳出 goto next_block; } } diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 4bd7662..966b0bd 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -82,7 +82,10 @@ void RISCv64RegAlloc::run() { // 阶段 5: 图着色算法分配物理寄存器 colorGraph(); // 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器) - rewriteFunction(); + rewriteFunction(); + + // 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用 + MFunc->getFrameInfo().vreg_to_preg_map = this->color_map; } /** @@ -794,7 +797,7 @@ void RISCv64RegAlloc::colorGraph() { 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)); } diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index aa23477..f39ed73 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -279,6 +279,7 @@ struct StackFrameInfo { std::map alloca_offsets; // std::map spill_offsets; // <溢出vreg, 栈偏移> std::set used_callee_saved_regs; // 使用的保存寄存器 + std::map vreg_to_preg_map; }; // 机器函数