From 166d0fc3721abfa955a84f115133ab067f387203 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 05:21:37 +0800 Subject: [PATCH] =?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