From 8fe9867f33188dd541ecce5d41a3a6f88d10001c Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 1 Aug 2025 12:15:03 +0800 Subject: [PATCH] =?UTF-8?q?[backend-IRC]=E4=BF=AE=E5=A4=8D=E4=BA=86keepali?= =?UTF-8?q?ve=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);