From 167c2ac2aece809765dd8ed2b869fc16f84005f2 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Tue, 5 Aug 2025 16:10:04 +0800 Subject: [PATCH] =?UTF-8?q?[backend]=E5=AE=8C=E5=96=84=E4=BA=86=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E6=B5=81=E6=B0=B4=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/RISCv64/RISCv64Backend.cpp | 200 +++++------------- src/backend/RISCv64/RISCv64LinearScan.cpp | 46 ++-- src/backend/RISCv64/RISCv64RegAlloc.cpp | 3 +- src/include/backend/RISCv64/RISCv64RegAlloc.h | 2 +- 4 files changed, 82 insertions(+), 169 deletions(-) diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index e3deae3..02541a1 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -1,13 +1,14 @@ #include "RISCv64Backend.h" #include "RISCv64ISel.h" #include "RISCv64RegAlloc.h" -#include "RISCv64LinearScan.h" // <--- 新增此行 +#include "RISCv64LinearScan.h" +#include "RISCv64BasicBlockAlloc.h" #include "RISCv64AsmPrinter.h" #include "RISCv64Passes.h" #include -#include // <--- 新增此行 -#include // <--- 新增此行 -#include // <--- 新增此行,用于打印超时警告 +#include +#include +#include namespace sysy { // 顶层入口 @@ -196,139 +197,7 @@ std::string RISCv64CodeGen::module_gen() { } std::string RISCv64CodeGen::function_gen(Function* func) { - if (DEBUG) { - // === 完整的后端处理流水线 === - - // 阶段 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); - // DEBUG = 1; - // DEEPDEBUG = 1; - if (DEBUG) { - std::cerr << "====== Intermediate Representation after Instruction Selection ======\n" - << ss_after_isel.str(); - } - - // 阶段 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: 除法强度削弱优化 (Division Strength Reduction) - DivStrengthReduction div_strength_reduction; - div_strength_reduction.runOnMachineFunction(mfunc.get()); - - // // 阶段 2.1: 指令调度 (Instruction Scheduling) - // PreRA_Scheduler scheduler; - // scheduler.runOnMachineFunction(mfunc.get()); - - // 阶段 3: 物理寄存器分配 (Register Allocation) - - DEBUG = 1; - // DEEPERDEBUG = 1; - - // 阶段 3: 物理寄存器分配 (带超时回退机制) - - /* - * [临时修改] - * 为了优先测试线性扫描分配器,暂时注释掉图着色分配器及其超时逻辑。 - * 原始逻辑是:优先使用图着色,超时(20s)后回退到线性扫描。 - * 在线性扫描分配器测试稳定后,可以恢复此处的代码。 - */ - /* - // 首先尝试图着色分配器 - if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n"; - RISCv64RegAlloc gc_alloc(mfunc.get()); - - // 异步执行图着色分配 - auto future = std::async(std::launch::async, [&gc_alloc]{ - gc_alloc.run(); - }); - - // 等待最多20秒 - auto status = future.wait_for(std::chrono::seconds(20)); - - if (status == std::future_status::timeout) { - // 超时,切换到线性扫描分配器 - std::cerr << "Warning: Graph coloring register allocation timed out for function '" - << func->getName() - << "'. Switching to Linear Scan allocator." - << std::endl; - - // 注意:由于无法安全地停止gc_alloc线程,我们只能放弃它的结果。 - // 在此项目中,我们假设超时后原mfunc状态未被严重破坏, - // 或者线性扫描会基于isel后的状态重新开始。 - // 为了安全,我们应该用一个新的mfunc或者重置mfunc状态, - // 但在这里我们简化处理,直接在同一个mfunc上运行线性扫描。 - - RISCv64LinearScan ls_alloc(mfunc.get()); - ls_alloc.run(); - - } else { - // 图着色成功完成 - if (DEBUG) std::cerr << "Graph Coloring allocation completed successfully.\n"; - // future.get()会重新抛出在线程中发生的任何异常 - future.get(); - } - */ - - // [临时修改] 直接调用线性扫描分配器进行测试 - std::cerr << "Info: Directly testing Register Allocation with Linear Scan...\n"; - RISCv64LinearScan ls_alloc(mfunc.get()); - ls_alloc.run(); - - // 阶段 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); - - return ss.str(); - } else { - // === 完整的后端处理流水线 === + // === 完整的后端处理流水线 === // 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers) RISCv64ISel isel; @@ -367,12 +236,56 @@ std::string RISCv64CodeGen::function_gen(Function* func) { // scheduler.runOnMachineFunction(mfunc.get()); // 阶段 3: 物理寄存器分配 (Register Allocation) - // RISCv64RegAlloc reg_alloc(mfunc.get()); - // reg_alloc.run(); - // [临时修改] 直接调用线性扫描分配器进行测试 - std::cerr << "Info: Directly testing Register Allocation with Linear Scan...\n"; - RISCv64LinearScan ls_alloc(mfunc.get()); - ls_alloc.run(); + + // 首先尝试图着色分配器 + if (DEBUG) std::cerr << "Attempting Register Allocation with Graph Coloring...\n"; + RISCv64RegAlloc gc_alloc(mfunc.get()); + + // 异步执行图着色分配 + auto future = std::async(std::launch::async, [&gc_alloc]{ + gc_alloc.run(); + }); + + // 等待最多20秒 + auto status = future.wait_for(std::chrono::seconds(20)); + + if (status == std::future_status::timeout) { + // 超时,切换到线性扫描分配器 + std::cerr << "Warning: Graph coloring register allocation timed out for function '" + << func->getName() + << "'. Switching to Linear Scan allocator." + << std::endl; + + // 注意:由于无法安全地停止gc_alloc线程,我们只能放弃它的结果。 + // 在此项目中,我们假设超时后原mfunc状态未被严重破坏, + // 或者线性扫描会基于isel后的状态重新开始。 + // 为了安全,我们应该用一个新的mfunc或者重置mfunc状态, + // 但在这里我们简化处理,直接在同一个mfunc上运行线性扫描。 + + RISCv64LinearScan ls_alloc(mfunc.get()); + bool success = ls_alloc.run(); + if (!success) { + // 如果线性扫描最终失败,则调用基本块分配器作为终极后备 + std::cerr << "Info: Linear Scan failed. Switching to Basic Block Allocator as final fallback.\n"; + + // 注意:我们需要在一个“干净”的MachineFunction上运行。 + // 最安全的方式是重新运行指令选择。 + RISCv64ISel isel_fallback; + mfunc = isel_fallback.runOnFunction(func); + EliminateFrameIndicesPass efi_pass_fallback; + efi_pass_fallback.runOnMachineFunction(mfunc.get()); + if (DEBUG) { + std::cerr << "====== stack info after reg alloc ======\n"; + } + RISCv64BasicBlockAlloc bb_alloc(mfunc.get()); + bb_alloc.run(); + } + } else { + // 图着色成功完成 + if (DEBUG) std::cerr << "Graph Coloring allocation completed successfully.\n"; + // future.get()会重新抛出在线程中发生的任何异常 + future.get(); + } if (DEBUG) { std::cerr << "====== stack info after reg alloc ======\n"; @@ -410,7 +323,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) { printer.run(ss); return ss.str(); - } } } // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/RISCv64LinearScan.cpp b/src/backend/RISCv64/RISCv64LinearScan.cpp index 4b9491f..5dde6bd 100644 --- a/src/backend/RISCv64/RISCv64LinearScan.cpp +++ b/src/backend/RISCv64/RISCv64LinearScan.cpp @@ -643,31 +643,31 @@ void RISCv64LinearScan::applyAllocation() { } } -void getInstrUseDef(const MachineInstr* instr, std::set& use, std::set& def) { - auto opcode = instr->getOpcode(); - const auto& operands = instr->getOperands(); +// void getInstrUseDef(const MachineInstr* instr, std::set& use, std::set& def) { +// auto opcode = instr->getOpcode(); +// const auto& operands = instr->getOperands(); - auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set& s) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op); - if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum()); - } else if (op->getKind() == MachineOperand::KIND_MEM) { - auto mem_op = static_cast(op); - auto reg_op = mem_op->getBase(); - if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum()); - } - }; +// auto get_vreg_id_if_virtual = [&](const MachineOperand* op, std::set& s) { +// if (op->getKind() == MachineOperand::KIND_REG) { +// auto reg_op = static_cast(op); +// if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum()); +// } else if (op->getKind() == MachineOperand::KIND_MEM) { +// auto mem_op = static_cast(op); +// auto reg_op = mem_op->getBase(); +// if (reg_op->isVirtual()) s.insert(reg_op->getVRegNum()); +// } +// }; - if (op_info.count(opcode)) { - const auto& info = op_info.at(opcode); - for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def); - for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use); - for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use); - } else if (opcode == RVOpcodes::CALL) { - if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def); - for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use); - } -} +// if (op_info.count(opcode)) { +// const auto& info = op_info.at(opcode); +// for (int idx : info.first) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), def); +// for (int idx : info.second) if (idx < operands.size()) get_vreg_id_if_virtual(operands[idx].get(), use); +// for (const auto& op : operands) if (op->getKind() == MachineOperand::KIND_MEM) get_vreg_id_if_virtual(op.get(), use); +// } else if (opcode == RVOpcodes::CALL) { +// if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[0].get(), def); +// for (size_t i = 1; i < operands.size(); ++i) if (operands[i]->getKind() == MachineOperand::KIND_REG) get_vreg_id_if_virtual(operands[i].get(), use); +// } +// } bool RISCv64LinearScan::isFPVReg(unsigned vreg) const { return vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isFloat(); diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index c09bd5d..1cbf64b 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -45,7 +45,7 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) } // 主入口: 迭代运行分配算法直到无溢出 -void RISCv64RegAlloc::run() { +bool RISCv64RegAlloc::run() { if (DEBUG) std::cerr << "===== LLIR Before Running Graph Coloring Register Allocation " << MFunc->getName() << " =====\n"; std::stringstream ss_before_reg_alloc; if (DEBUG) { @@ -108,6 +108,7 @@ void RISCv64RegAlloc::run() { MFunc->getFrameInfo().vreg_to_preg_map = this->color_map; collectUsedCalleeSavedRegs(); if (DEBUG) std::cerr << "===== Finished Graph Coloring Register Allocation =====\n\n"; + return true; } // 单次分配的核心流程 diff --git a/src/include/backend/RISCv64/RISCv64RegAlloc.h b/src/include/backend/RISCv64/RISCv64RegAlloc.h index bea9ddc..420623a 100644 --- a/src/include/backend/RISCv64/RISCv64RegAlloc.h +++ b/src/include/backend/RISCv64/RISCv64RegAlloc.h @@ -20,7 +20,7 @@ public: RISCv64RegAlloc(MachineFunction* mfunc); // 模块主入口 - void run(); + bool run(); private: // 类型定义,与Python版本对应