From 03b62b138f87b83f9877adcce69cbd0d11dbf8cf Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Wed, 30 Jul 2025 20:40:56 +0800 Subject: [PATCH] =?UTF-8?q?[backend]=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=A0=88=E7=AE=A1=E7=90=86=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 | 115 +++++++----------- src/backend/RISCv64/RISCv64Backend.cpp | 16 +-- src/backend/RISCv64/RISCv64RegAlloc.cpp | 22 ++-- src/include/backend/RISCv64/RISCv64LLIR.h | 3 +- 4 files changed, 66 insertions(+), 90 deletions(-) diff --git a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp index 47b92e0..cdbccc1 100644 --- a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp +++ b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp @@ -1,45 +1,45 @@ #include "CalleeSavedHandler.h" #include -#include // +#include #include -#include // +#include 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; } void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { - // 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。 - // 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。 - StackFrameInfo& frame_info = mfunc->getFrameInfo(); - // [修改] 分别记录被使用的整数和浮点被调用者保存寄存器 - std::set used_int_callee_saved; - std::set used_fp_callee_saved; + std::set used_callee_saved; - // 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11) 和 fs寄存器 (fs0-fs11) + // 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->isVirtual()) { + if (reg_op && !reg_op->isVirtual()) { PhysicalReg preg = reg_op->getPReg(); - // [修改] 区分整数和浮点被调用者保存寄存器 - // s0 由序言/尾声处理器专门处理,这里不计入 + // 检查整数 s1-s11 if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) { - used_int_callee_saved.insert(preg); + used_callee_saved.insert(preg); } - // fs0-fs11 在我们的枚举中对应 f8,f9,f18-f27 + // 检查浮点 fs0-fs11 (f8,f9,f18-f27) else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) { - used_fp_callee_saved.insert(preg); + used_callee_saved.insert(preg); } } }; @@ -53,60 +53,44 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { } } - // 如果没有使用任何需要处理的 callee-saved 寄存器,则直接返回 - if (used_int_callee_saved.empty() && used_fp_callee_saved.empty()) { - frame_info.callee_saved_size = 0; // 确保大小被初始化 + if (used_callee_saved.empty()) { + frame_info.callee_saved_size = 0; return; } - // 2. 计算为 callee-saved 寄存器分配的栈空间大小 - // 每个寄存器在RV64中都占用8字节 - int callee_saved_size = (used_int_callee_saved.size() + used_fp_callee_saved.size()) * 8; - frame_info.callee_saved_size = callee_saved_size; + // 2. 计算并更新 frame_info + frame_info.callee_saved_size = used_callee_saved.size() * 8; + // 为了布局确定性和恢复顺序一致,对寄存器排序 + std::vector sorted_regs(used_callee_saved.begin(), used_callee_saved.end()); + std::sort(sorted_regs.begin(), sorted_regs.end()); + // 3. 在函数序言中插入保存指令 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); } - // 为了布局确定性,对寄存器进行排序并按序保存 - std::vector sorted_int_regs(used_int_callee_saved.begin(), used_int_callee_saved.end()); - std::vector sorted_fp_regs(used_fp_callee_saved.begin(), used_fp_callee_saved.end()); - std::sort(sorted_int_regs.begin(), sorted_int_regs.end()); - std::sort(sorted_fp_regs.begin(), sorted_fp_regs.end()); - std::vector> save_instrs; - int current_offset = -16; // ra和s0已占用-8和-16,从-24开始分配 + // [关键] 从局部变量区域之后开始分配空间 + int current_offset = - (16 + frame_info.locals_size); - // 准备整数保存指令 (sd) - for (PhysicalReg reg : sorted_int_regs) { + for (PhysicalReg reg : sorted_regs) { current_offset -= 8; - auto sd = std::make_unique(RVOpcodes::SD); - sd->addOperand(std::make_unique(reg)); - sd->addOperand(std::make_unique( + 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) )); - save_instrs.push_back(std::move(sd)); - } - - // 准备浮点保存指令 (fsd) - for (PhysicalReg reg : sorted_fp_regs) { - current_offset -= 8; - auto fsd = std::make_unique(RVOpcodes::FSD); // 使用浮点保存指令 - fsd->addOperand(std::make_unique(reg)); - fsd->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(current_offset) - )); - save_instrs.push_back(std::move(fsd)); + save_instrs.push_back(std::move(save_instr)); } - // 一次性插入所有保存指令 if (!save_instrs.empty()) { entry_instrs.insert(insert_pos, std::make_move_iterator(save_instrs.begin()), @@ -118,40 +102,27 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { if ((*it)->getOpcode() == RVOpcodes::RET) { std::vector> restore_instrs; - current_offset = -16; // 重置偏移量用于恢复 + // [关键] 使用与保存时完全相同的逻辑来计算偏移量 + current_offset = - (16 + frame_info.locals_size); - // 准备恢复整数寄存器 (ld) - 以与保存时相同的顺序 - for (PhysicalReg reg : sorted_int_regs) { + for (PhysicalReg reg : sorted_regs) { current_offset -= 8; - auto ld = std::make_unique(RVOpcodes::LD); - ld->addOperand(std::make_unique(reg)); - ld->addOperand(std::make_unique( + 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) )); - restore_instrs.push_back(std::move(ld)); + restore_instrs.push_back(std::move(restore_instr)); } - - // 准备恢复浮点寄存器 (fld) - for (PhysicalReg reg : sorted_fp_regs) { - current_offset -= 8; - auto fld = std::make_unique(RVOpcodes::FLD); // 使用浮点加载指令 - fld->addOperand(std::make_unique(reg)); - fld->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(current_offset) - )); - restore_instrs.push_back(std::move(fld)); - } - - // 一次性插入所有恢复指令 + if (!restore_instrs.empty()) { mbb->getInstructions().insert(it, std::make_move_iterator(restore_instrs.begin()), std::make_move_iterator(restore_instrs.end())); } - - // 处理完一个基本块的RET后,迭代器已失效,需跳出当前块的循环 goto next_block_label; } } diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index 1f552cf..ce5b465 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -12,11 +12,10 @@ std::string RISCv64CodeGen::code_gen() { return module_gen(); } -// 模块级代码生成 std::string RISCv64CodeGen::module_gen() { std::stringstream ss; - // --- 步骤1:将全局变量分为.data和.bss两组 --- + // --- 步骤1:将全局变量(GlobalValue)分为.data和.bss两组 --- std::vector data_globals; std::vector bss_globals; @@ -41,7 +40,7 @@ std::string RISCv64CodeGen::module_gen() { } } - // --- 步骤2:生成 .bss 段的代码 --- + // --- 步骤2:生成 .bss 段的代码 (这部分不变) --- if (!bss_globals.empty()) { ss << ".bss\n"; for (GlobalValue* global : bss_globals) { @@ -57,9 +56,12 @@ std::string RISCv64CodeGen::module_gen() { } } - // --- 步骤3:生成 .data 段的代码 --- - if (!data_globals.empty()) { - ss << ".data\n"; // 切换到 .data 段 + // --- [修改] 步骤3:生成 .data 段的代码 --- + // 我们需要检查 data_globals 和 常量列表是否都为空 + if (!data_globals.empty() || !module->getConsts().empty()) { + ss << ".data\n"; + + // a. 先处理普通的全局变量 (GlobalValue) for (GlobalValue* global : data_globals) { ss << ".globl " << global->getName() << "\n"; ss << global->getName() << ":\n"; @@ -106,7 +108,7 @@ std::string RISCv64CodeGen::module_gen() { } } - // --- 处理函数 (.text段) --- + // --- 处理函数 (.text段) 的逻辑保持不变 --- if (!module->getFunctions().empty()) { ss << ".text\n"; for (const auto& func_pair : module->getFunctions()) { diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 966b0bd..8bee681 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -165,10 +165,6 @@ void RISCv64RegAlloc::handleCallingConvention() { */ void RISCv64RegAlloc::eliminateFrameIndices() { StackFrameInfo& frame_info = MFunc->getFrameInfo(); - // 初始偏移量,为保存ra和s0留出空间。 - // 假设序言是 addi sp, sp, -stack_size; sd ra, stack_size-8(sp); sd s0, stack_size-16(sp); - int current_offset = 16; - Function* F = MFunc->getFunc(); RISCv64ISel* isel = MFunc->getISel(); @@ -190,12 +186,15 @@ void RISCv64RegAlloc::eliminateFrameIndices() { } } - // 处理局部变量 - // 遍历AllocaInst来计算局部变量所需的总空间 + // [关键修改] 为局部变量分配空间时,起始点必须考虑为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())) { - // 获取Alloca指令指向的类型 (例如 alloca i32* 中,获取 i32) Type* allocated_type = alloca->getType()->as()->getBaseType(); int size = getTypeSizeInBytes(allocated_type); @@ -203,14 +202,17 @@ void RISCv64RegAlloc::eliminateFrameIndices() { size = (size + 7) & ~7; if (size == 0) size = 8; // 至少分配8字节 - current_offset += size; + local_var_offset += size; unsigned alloca_vreg = isel->getVReg(alloca); // 局部变量使用相对于s0的负向偏移 - frame_info.alloca_offsets[alloca_vreg] = -current_offset; + frame_info.alloca_offsets[alloca_vreg] = -local_var_offset; } } } - frame_info.locals_size = current_offset; + + // [修复] 正确计算并设置locals_size + // 它只应该包含由AllocaInst分配的局部变量的总大小。 + frame_info.locals_size = local_var_offset - locals_start_offset; // 遍历所有机器指令,将伪指令展开为真实指令 for (auto& mbb : MFunc->getBlocks()) { diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index f39ed73..9f44776 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -279,7 +279,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::map vreg_to_preg_map; + std::vector callee_saved_regs; // 用于存储需要保存的被调用者保存寄存器列表 }; // 机器函数