From 8deb4ed076cdfe709da3af7688368553ca5bf9cc Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Tue, 29 Jul 2025 15:48:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?[backend]=E6=B7=BB=E5=8A=A0=E4=BA=862?= =?UTF-8?q?=E4=B8=AA=E6=96=B0=E7=9A=84pass=EF=BC=8C=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=A4=A7=E7=AB=8B=E5=8D=B3=E6=95=B0=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CMakeLists.txt | 2 + src/CalleeSavedHandler.cpp | 4 +- src/LegalizeImmediates.cpp | 168 ++++++++++++++++++++++++ src/PrologueEpilogueInsertion.cpp | 121 +++++++++++++++++ src/RISCv64AsmPrinter.cpp | 43 ------ src/RISCv64Backend.cpp | 13 +- src/RISCv64ISel.cpp | 12 +- src/RISCv64RegAlloc.cpp | 44 +++++-- src/include/LegalizeImmediates.h | 36 +++++ src/include/PrologueEpilogueInsertion.h | 35 +++++ src/include/RISCv64AsmPrinter.h | 2 - src/include/RISCv64Passes.h | 2 + 12 files changed, 422 insertions(+), 60 deletions(-) create mode 100644 src/LegalizeImmediates.cpp create mode 100644 src/PrologueEpilogueInsertion.cpp create mode 100644 src/include/LegalizeImmediates.h create mode 100644 src/include/PrologueEpilogueInsertion.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 48ab612..31adcf8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,6 +37,8 @@ add_executable(sysyc PreRA_Scheduler.cpp PostRA_Scheduler.cpp CalleeSavedHandler.cpp + LegalizeImmediates.cpp + PrologueEpilogueInsertion.cpp RISCv64LLIR.cpp ) diff --git a/src/CalleeSavedHandler.cpp b/src/CalleeSavedHandler.cpp index fa2cd7e..2780f31 100644 --- a/src/CalleeSavedHandler.cpp +++ b/src/CalleeSavedHandler.cpp @@ -12,7 +12,7 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) { } void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { - // 【最终方案】: 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。 + // 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。 // 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。 // 这样做可以使生成的 sd/ld 指令能被后续的优化 Pass (如 PostRA-Scheduler) 处理。 @@ -83,7 +83,7 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { current_offset -= 8; } - // 5. 【已修复】在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效 + // 5. 在函数结尾(ret之前)插入恢复指令,使用反向遍历来避免迭代器失效 for (auto& mbb : mfunc->getBlocks()) { // 使用手动控制的反向循环 for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { diff --git a/src/LegalizeImmediates.cpp b/src/LegalizeImmediates.cpp new file mode 100644 index 0000000..7e0c834 --- /dev/null +++ b/src/LegalizeImmediates.cpp @@ -0,0 +1,168 @@ +#include "LegalizeImmediates.h" +#include "RISCv64ISel.h" // 需要包含它以调用 getNewVReg() +#include "RISCv64AsmPrinter.h" +#include +#include + + +// 声明外部调试控制变量 +extern int DEBUG; +extern int DEEPDEBUG; + +namespace sysy { + +char LegalizeImmediatesPass::ID = 0; + +// 辅助函数:检查一个立即数是否在RISC-V的12位有符号范围内 +static bool isLegalImmediate(int64_t imm) { + return imm >= -2048 && imm <= 2047; +} + +void LegalizeImmediatesPass::runOnMachineFunction(MachineFunction* mfunc) { + if (DEBUG) { + std::cerr << "===== Running Legalize Immediates Pass on function: " << mfunc->getName() << " =====\n"; + } + + // 定义我们保留的、用于暂存的物理寄存器 + const PhysicalReg TEMP_REG = PhysicalReg::T5; + + // 创建一个临时的AsmPrinter用于打印指令,方便调试 + RISCv64AsmPrinter temp_printer(mfunc); + if (DEEPDEBUG) { + temp_printer.setStream(std::cerr); + } + + for (auto& mbb : mfunc->getBlocks()) { + if (DEEPDEBUG) { + std::cerr << "--- Processing Basic Block: " << mbb->getName() << " ---\n"; + } + // 创建一个新的指令列表,用于存放合法化后的指令 + std::vector> new_instructions; + + for (auto& instr_ptr : mbb->getInstructions()) { + if (DEEPDEBUG) { + std::cerr << " Checking: "; + // 打印指令时末尾会带换行符,所以这里不用 std::endl + temp_printer.printInstruction(instr_ptr.get(), true); + } + + bool legalized = false; // 标记当前指令是否已被展开处理 + + switch (instr_ptr->getOpcode()) { + case RVOpcodes::ADDI: + case RVOpcodes::ADDIW: { + auto& operands = instr_ptr->getOperands(); + auto imm_op = static_cast(operands.back().get()); + + if (!isLegalImmediate(imm_op->getValue())) { + if (DEEPDEBUG) { + std::cerr << " >> ILLEGAL immediate (" << imm_op->getValue() << "). Expanding...\n"; + } + // 立即数超出范围,需要展开 + auto rd_op = std::make_unique(*static_cast(operands[0].get())); + auto rs1_op = std::make_unique(*static_cast(operands[1].get())); + + // 1. li t5, immediate + auto li = std::make_unique(RVOpcodes::LI); + li->addOperand(std::make_unique(TEMP_REG)); + li->addOperand(std::make_unique(imm_op->getValue())); + + // 2. add/addw rd, rs1, t5 + auto new_op = (instr_ptr->getOpcode() == RVOpcodes::ADDI) ? RVOpcodes::ADD : RVOpcodes::ADDW; + auto add = std::make_unique(new_op); + add->addOperand(std::move(rd_op)); + add->addOperand(std::move(rs1_op)); + add->addOperand(std::make_unique(TEMP_REG)); + + if (DEEPDEBUG) { + std::cerr << " New sequence:\n "; + temp_printer.printInstruction(li.get(), true); + std::cerr << " "; + temp_printer.printInstruction(add.get(), true); + } + + new_instructions.push_back(std::move(li)); + new_instructions.push_back(std::move(add)); + + legalized = true; + } + break; + } + + // 处理所有内存加载/存储指令 + case RVOpcodes::LB: case RVOpcodes::LH: case RVOpcodes::LW: case RVOpcodes::LD: + case RVOpcodes::LBU: case RVOpcodes::LHU: case RVOpcodes::LWU: + case RVOpcodes::SB: case RVOpcodes::SH: case RVOpcodes::SW: case RVOpcodes::SD: { + auto& operands = instr_ptr->getOperands(); + auto mem_op = static_cast(operands.back().get()); + auto offset_op = mem_op->getOffset(); + + if (!isLegalImmediate(offset_op->getValue())) { + if (DEEPDEBUG) { + std::cerr << " >> ILLEGAL immediate offset (" << offset_op->getValue() << "). Expanding...\n"; + } + // 偏移量超出范围,需要展开 + auto data_reg_op = std::make_unique(*static_cast(operands[0].get())); + auto base_reg_op = std::make_unique(*mem_op->getBase()); + + // 1. li t5, offset + auto li = std::make_unique(RVOpcodes::LI); + li->addOperand(std::make_unique(TEMP_REG)); + li->addOperand(std::make_unique(offset_op->getValue())); + + // 2. add t5, base_reg, t5 (计算最终地址,结果也放在t5) + auto add = std::make_unique(RVOpcodes::ADD); + add->addOperand(std::make_unique(TEMP_REG)); + add->addOperand(std::move(base_reg_op)); + add->addOperand(std::make_unique(TEMP_REG)); + + // 3. lw/sw data_reg, 0(t5) + auto mem_instr = std::make_unique(instr_ptr->getOpcode()); + mem_instr->addOperand(std::move(data_reg_op)); + mem_instr->addOperand(std::make_unique( + std::make_unique(TEMP_REG), + std::make_unique(0) + )); + + if (DEEPDEBUG) { + std::cerr << " New sequence:\n "; + temp_printer.printInstruction(li.get(), true); + std::cerr << " "; + temp_printer.printInstruction(add.get(), true); + std::cerr << " "; + temp_printer.printInstruction(mem_instr.get(), true); + } + + new_instructions.push_back(std::move(li)); + new_instructions.push_back(std::move(add)); + new_instructions.push_back(std::move(mem_instr)); + + legalized = true; + } + break; + } + + default: + // 其他指令不需要处理 + break; + } + + if (!legalized) { + if (DEEPDEBUG) { + std::cerr << " -- Immediate is legal. Skipping.\n"; + } + // 如果当前指令不需要合法化,直接将其移动到新列表中 + new_instructions.push_back(std::move(instr_ptr)); + } + } + + // 用新的、已合法化的指令列表替换旧的列表 + mbb->getInstructions() = std::move(new_instructions); + } + + if (DEBUG) { + std::cerr << "===== Finished Legalize Immediates Pass =====\n\n"; + } +} + +} // namespace sysy \ No newline at end of file diff --git a/src/PrologueEpilogueInsertion.cpp b/src/PrologueEpilogueInsertion.cpp new file mode 100644 index 0000000..d5ab753 --- /dev/null +++ b/src/PrologueEpilogueInsertion.cpp @@ -0,0 +1,121 @@ +#include "include/PrologueEpilogueInsertion.h" + +namespace sysy { + +char PrologueEpilogueInsertionPass::ID = 0; + +void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { + StackFrameInfo& frame_info = mfunc->getFrameInfo(); + // 最终计算总栈帧大小。 + int total_stack_size = frame_info.locals_size + + frame_info.spill_size + + frame_info.callee_saved_size + + 16; // 为 ra 和 s0 固定的16字节 + + // 保持栈指针16字节对齐 + int aligned_stack_size = (total_stack_size + 15) & ~15; + frame_info.total_size = aligned_stack_size; + + if (aligned_stack_size == 0) { + return; // 无需插入序言/尾声 + } + + // --- 1. 插入序言 --- + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + auto& entry_instrs = entry_block->getInstructions(); + + // [修复] 创建一个临时 vector 来存放所有序言指令,以避免迭代器失效 + 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, offset(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, offset(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. 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)); + + // 确定插入点(在函数名标签之后) + auto insert_pos = entry_instrs.begin(); + if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) { + insert_pos++; + } + + // 一次性将所有序言指令插入,安全且高效 + if (!prologue_instrs.empty()) { + entry_instrs.insert(insert_pos, + std::make_move_iterator(prologue_instrs.begin()), + std::make_move_iterator(prologue_instrs.end())); + } + + // --- 2. 插入尾声 --- + for (auto& mbb : mfunc->getBlocks()) { + for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { + if ((*it)->getOpcode() == RVOpcodes::RET) { + // [修复] 创建一个临时 vector 来存放所有尾声指令 + std::vector> epilogue_instrs; + + // a. ld ra, offset(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)); + + // b. ld s0, offset(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)); + + // c. 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 指令前一次性插入所有尾声指令 + if (!epilogue_instrs.empty()) { + mbb->getInstructions().insert(it, + std::make_move_iterator(epilogue_instrs.begin()), + std::make_move_iterator(epilogue_instrs.end())); + } + + // 处理完当前基本块的RET后即可跳出内层循环 + break; + } + } + } +} + +} // namespace sysy \ No newline at end of file diff --git a/src/RISCv64AsmPrinter.cpp b/src/RISCv64AsmPrinter.cpp index 9fbf0e9..9974a7d 100644 --- a/src/RISCv64AsmPrinter.cpp +++ b/src/RISCv64AsmPrinter.cpp @@ -22,52 +22,12 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) { OS = &os; *OS << ".globl " << MFunc->getName() << "\n"; - *OS << MFunc->getName() << ":\n"; - - printPrologue(); for (auto& mbb : MFunc->getBlocks()) { printBasicBlock(mbb.get(), debug); } } -// 在 RISCv64AsmPrinter.cpp 文件中 - -void RISCv64AsmPrinter::printPrologue() { - StackFrameInfo& frame_info = MFunc->getFrameInfo(); - // 计算总栈帧大小。 - // 包含三部分:局部变量区、寄存器溢出区、以及为被调用者保存(callee-saved)寄存器预留的区域。 - // 最后再加上为保存 ra 和 s0 固定的16字节。 - int total_stack_size = frame_info.locals_size + - frame_info.spill_size + - frame_info.callee_saved_size + - 16; - - // 保持栈指针16字节对齐 - int aligned_stack_size = (total_stack_size + 15) & ~15; - frame_info.total_size = aligned_stack_size; // 更新最终的栈大小 - - // 只有在需要分配栈空间时才生成指令 - if (aligned_stack_size > 0) { - // 1. 一次性分配整个栈帧 - *OS << " addi sp, sp, -" << aligned_stack_size << "\n"; - // 2. 在新的栈顶附近保存 ra 和 s0 - *OS << " sd ra, " << (aligned_stack_size - 8) << "(sp)\n"; - *OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n"; - // 3. 设置新的帧指针 s0,使其指向栈帧的底部(高地址) - *OS << " addi s0, sp, " << aligned_stack_size << "\n"; - } -} - -void RISCv64AsmPrinter::printEpilogue() { - int aligned_stack_size = MFunc->getFrameInfo().total_size; - if (aligned_stack_size > 0) { - *OS << " ld ra, " << (aligned_stack_size - 8) << "(sp)\n"; - *OS << " ld s0, " << (aligned_stack_size - 16) << "(sp)\n"; - *OS << " addi sp, sp, " << aligned_stack_size << "\n"; - } -} - void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) { if (!mbb->getName().empty()) { *OS << mbb->getName() << ":\n"; @@ -79,9 +39,6 @@ void RISCv64AsmPrinter::printBasicBlock(MachineBasicBlock* mbb, bool debug) { void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) { auto opcode = instr->getOpcode(); - if (opcode == RVOpcodes::RET) { - printEpilogue(); - } if (opcode == RVOpcodes::LABEL) { // 标签直接打印,不加缩进 diff --git a/src/RISCv64Backend.cpp b/src/RISCv64Backend.cpp index 453c026..26e37ac 100644 --- a/src/RISCv64Backend.cpp +++ b/src/RISCv64Backend.cpp @@ -2,7 +2,7 @@ #include "RISCv64ISel.h" #include "RISCv64RegAlloc.h" #include "RISCv64AsmPrinter.h" -#include "RISCv64Passes.h" // 包含优化Pass的头文件 +#include "RISCv64Passes.h" #include namespace sysy { @@ -107,6 +107,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) { RISCv64ISel isel; std::unique_ptr mfunc = isel.runOnFunction(func); + // 第一次调试打印输出 std::stringstream ss1; RISCv64AsmPrinter printer1(mfunc.get()); printer1.run(ss1, true); @@ -119,10 +120,18 @@ std::string RISCv64CodeGen::function_gen(Function* func) { RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); - // 阶段 3.5: 处理被调用者保存寄存器 + // 阶段 3.1: 处理被调用者保存寄存器 CalleeSavedHandler callee_handler; callee_handler.runOnMachineFunction(mfunc.get()); + // 阶段 3.2: 插入序言和尾声 + PrologueEpilogueInsertionPass pei_pass; + pei_pass.runOnMachineFunction(mfunc.get()); + + // 阶段 3.3: 清理产生的大立即数 + LegalizeImmediatesPass legalizer; + legalizer.runOnMachineFunction(mfunc.get()); + // 阶段 4: 窥孔优化 (Peephole Optimization) PeepholeOptimizer peephole; peephole.runOnMachineFunction(mfunc.get()); diff --git a/src/RISCv64ISel.cpp b/src/RISCv64ISel.cpp index 4ffad0c..11d13a1 100644 --- a/src/RISCv64ISel.cpp +++ b/src/RISCv64ISel.cpp @@ -52,8 +52,18 @@ std::unique_ptr RISCv64ISel::runOnFunction(Function* func) { // 指令选择主流程 void RISCv64ISel::select() { // 遍历基本块,为它们创建对应的MachineBasicBlock + bool is_first_block = true; for (const auto& bb_ptr : F->getBasicBlocks()) { - auto mbb = std::make_unique(bb_ptr->getName(), MFunc.get()); + std::string mbb_name; + if (is_first_block) { + // 对于函数的第一个基本块,其标签必须与函数名完全相同 + mbb_name = F->getName(); + is_first_block = false; + } else { + // 对于后续的基本块,继续使用它们在IR中的原始名称 + mbb_name = bb_ptr->getName(); + } + auto mbb = std::make_unique(mbb_name, MFunc.get()); bb_map[bb_ptr.get()] = mbb.get(); MFunc->addBlock(std::move(mbb)); } diff --git a/src/RISCv64RegAlloc.cpp b/src/RISCv64RegAlloc.cpp index c007d9d..357cb3f 100644 --- a/src/RISCv64RegAlloc.cpp +++ b/src/RISCv64RegAlloc.cpp @@ -1,6 +1,7 @@ #include "RISCv64RegAlloc.h" #include "RISCv64ISel.h" #include "RISCv64AsmPrinter.h" // For DEBUG output +#include "LegalizeImmediates.h" #include #include #include // For DEBUG output @@ -10,6 +11,17 @@ namespace sysy { RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) { allocable_int_regs = { + PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, + PhysicalReg::T4, /*PhysicalReg::T5,*/PhysicalReg::T6, + PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, + PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7, + PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, + PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7, + PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11, + }; + + // 创建一个包含所有通用整数寄存器的临时列表 + const std::vector all_int_regs = { PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6, PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, @@ -21,7 +33,7 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) { // 映射物理寄存器到特殊的虚拟寄存器ID,用于干扰图中的物理寄存器节点 // 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突 - for (PhysicalReg preg : allocable_int_regs) { + for (PhysicalReg preg : all_int_regs) { preg_to_vreg_id_map[preg] = static_cast(PhysicalReg::PHYS_REG_START_ID) + static_cast(preg); } } @@ -32,6 +44,8 @@ void RISCv64RegAlloc::run() { handleCallingConvention(); // 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移) eliminateFrameIndices(); + + // 调试输出当前的LLIR状态 { // 使用大括号创建一个局部作用域,避免printer变量泄露 if (DEBUG) { std::cerr << "\n===== LLIR after eliminateFrameIndices for function: " @@ -46,6 +60,7 @@ void RISCv64RegAlloc::run() { std::cerr << "===== End of LLIR =====\n\n"; } } + // 阶段 3: 活跃性分析 analyzeLiveness(); // 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响) @@ -592,17 +607,26 @@ void RISCv64RegAlloc::buildInterferenceGraph() { // 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。 const std::vector& caller_saved_regs = getCallerSavedIntRegs(); for (PhysicalReg cs_reg : caller_saved_regs) { - unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID + if (preg_to_vreg_id_map.count(cs_reg)) { + unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID - // 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。 - for (unsigned live_vreg_out : live_out) { - if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰 - // [新增调试逻辑] 打印添加的干扰边及其原因 - if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) { - std::cerr << " Edge (CALL) : preg(" << static_cast(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n"; + // 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。 + for (unsigned live_vreg_out : live_out) { + if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰 + // [新增调试逻辑] 打印添加的干扰边及其原因 + if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) { + std::cerr << " Edge (CALL) : preg(" << static_cast(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n"; + } + interference_graph[cs_vreg_id].insert(live_vreg_out); + interference_graph[live_vreg_out].insert(cs_vreg_id); } - interference_graph[cs_vreg_id].insert(live_vreg_out); - interference_graph[live_vreg_out].insert(cs_vreg_id); + } + } else { + // 如果物理寄存器没有对应的特殊虚拟寄存器ID,可能是因为它不是调用者保存的寄存器。 + // 这种情况通常不应该发生,但我们可以在这里添加一个警告或错误处理。 + if (DEEPDEBUG) { + std::cerr << "Warning: Physical register " << static_cast(cs_reg) + << " does not have a corresponding special vreg ID.\n"; } } } diff --git a/src/include/LegalizeImmediates.h b/src/include/LegalizeImmediates.h new file mode 100644 index 0000000..e3701b2 --- /dev/null +++ b/src/include/LegalizeImmediates.h @@ -0,0 +1,36 @@ +#ifndef SYSY_LEGALIZE_IMMEDIATES_H +#define SYSY_LEGALIZE_IMMEDIATES_H + +#include "RISCv64LLIR.h" +#include "Pass.h" + +namespace sysy { + +// MachineFunction 的前向声明在这里是可选的,因为 RISCv64LLIR.h 已经定义了它 +// class MachineFunction; + +/** + * @class LegalizeImmediatesPass + * @brief 一个用于“合法化”机器指令的Pass。 + * + * 这个Pass的主要职责是遍历所有机器指令,查找那些包含了超出 + * 目标架构(RISC-V)编码范围的大立即数(immediate)的指令, + * 并将它们展开成一个等价的、只包含合法立即数的指令序列。 + * + * 它在指令选择之后、寄存器分配之前运行,确保进入后续阶段的 + * 所有指令都符合硬件约束。 + */ +class LegalizeImmediatesPass : public Pass { +public: + static char ID; + + LegalizeImmediatesPass() : Pass("legalize-immediates", Granularity::Function, PassKind::Optimization) {} + + void *getPassID() const override { return &ID; } + + void runOnMachineFunction(MachineFunction* mfunc); +}; + +} // namespace sysy + +#endif // SYSY_LEGALIZE_IMMEDIATES_H \ No newline at end of file diff --git a/src/include/PrologueEpilogueInsertion.h b/src/include/PrologueEpilogueInsertion.h new file mode 100644 index 0000000..d07f8bf --- /dev/null +++ b/src/include/PrologueEpilogueInsertion.h @@ -0,0 +1,35 @@ +#ifndef SYSY_PROLOGUE_EPILOGUE_INSERTION_H +#define SYSY_PROLOGUE_EPILOGUE_INSERTION_H + +#include "RISCv64LLIR.h" +#include "Pass.h" + +namespace sysy { + +class MachineFunction; + +/** + * @class PrologueEpilogueInsertionPass + * @brief 在函数中插入序言和尾声的机器指令。 + * + * 这个Pass在所有栈帧大小计算完毕后(包括局部变量、溢出槽、被调用者保存寄存器), + * 在寄存器分配之后运行。它的职责是: + * 1. 根据 StackFrameInfo 中的最终栈大小,生成用于分配和释放栈帧的指令 (addi sp, sp, +/-size)。 + * 2. 生成用于保存和恢复返回地址(ra)和旧帧指针(s0)的指令。 + * 3. 将这些指令作为 MachineInstr 对象插入到 MachineFunction 的入口块和所有返回块中。 + * 4. 这个Pass可能会生成带有大立即数的指令,需要后续的 LegalizeImmediatesPass 来处理。 + */ +class PrologueEpilogueInsertionPass : public Pass { +public: + static char ID; + + PrologueEpilogueInsertionPass() : Pass("prologue-epilogue-insertion", Granularity::Function, PassKind::Optimization) {} + + void *getPassID() const override { return &ID; } + + void runOnMachineFunction(MachineFunction* mfunc); +}; + +} // namespace sysy + +#endif // SYSY_PROLOGUE_EPILOGUE_INSERTION_H \ No newline at end of file diff --git a/src/include/RISCv64AsmPrinter.h b/src/include/RISCv64AsmPrinter.h index f85dcfc..a8f403d 100644 --- a/src/include/RISCv64AsmPrinter.h +++ b/src/include/RISCv64AsmPrinter.h @@ -20,8 +20,6 @@ public: void setStream(std::ostream& os) { OS = &os; } private: // 打印各个部分 - void printPrologue(); - void printEpilogue(); void printBasicBlock(MachineBasicBlock* mbb, bool debug = false); // 辅助函数 diff --git a/src/include/RISCv64Passes.h b/src/include/RISCv64Passes.h index 565cf81..4888589 100644 --- a/src/include/RISCv64Passes.h +++ b/src/include/RISCv64Passes.h @@ -6,6 +6,8 @@ #include "PreRA_Scheduler.h" #include "PostRA_Scheduler.h" #include "CalleeSavedHandler.h" +#include "LegalizeImmediates.h" +#include "PrologueEpilogueInsertion.h" #include "Pass.h" namespace sysy { From 32bdc17dc3d25aaa968d37979a3d52aa192e8d31 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Tue, 29 Jul 2025 16:15:01 +0800 Subject: [PATCH 2/2] =?UTF-8?q?[backend]=E8=B0=83=E6=95=B4=E4=BA=86?= =?UTF-8?q?=E5=90=8E=E7=AB=AFpass=E7=9A=84=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/PrologueEpilogueInsertion.cpp | 175 +++++++++++++++--------------- src/RISCv64Backend.cpp | 16 +-- 2 files changed, 94 insertions(+), 97 deletions(-) diff --git a/src/PrologueEpilogueInsertion.cpp b/src/PrologueEpilogueInsertion.cpp index d5ab753..9eec6b5 100644 --- a/src/PrologueEpilogueInsertion.cpp +++ b/src/PrologueEpilogueInsertion.cpp @@ -1,4 +1,4 @@ -#include "include/PrologueEpilogueInsertion.h" +#include "PrologueEpilogueInsertion.h" namespace sysy { @@ -6,114 +6,111 @@ char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { StackFrameInfo& frame_info = mfunc->getFrameInfo(); - // 最终计算总栈帧大小。 + + // 完全遵循 AsmPrinter 中的计算逻辑 int total_stack_size = frame_info.locals_size + frame_info.spill_size + frame_info.callee_saved_size + 16; // 为 ra 和 s0 固定的16字节 - // 保持栈指针16字节对齐 int aligned_stack_size = (total_stack_size + 15) & ~15; frame_info.total_size = aligned_stack_size; - if (aligned_stack_size == 0) { - return; // 无需插入序言/尾声 - } + // 只有在需要分配栈空间时才生成指令 + if (aligned_stack_size > 0) { + // --- 1. 插入序言 --- + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + auto& entry_instrs = entry_block->getInstructions(); - // --- 1. 插入序言 --- - MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); - auto& entry_instrs = entry_block->getInstructions(); + std::vector> prologue_instrs; - // [修复] 创建一个临时 vector 来存放所有序言指令,以避免迭代器失效 - 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)); + 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)); - // 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)); + // 2. 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)); - // b. sd ra, offset(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)); + // 3. 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. 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)); - // c. sd s0, offset(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. 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)); + // 确定插入点(在函数名标签之后) + auto insert_pos = entry_instrs.begin(); + // [重要] 这里我们不再需要跳过LABEL,因为AsmPrinter将不再打印函数名标签 + // 第一个基本块的标签就是函数入口 + + // 一次性将所有序言指令插入 + if (!prologue_instrs.empty()) { + entry_instrs.insert(insert_pos, + std::make_move_iterator(prologue_instrs.begin()), + std::make_move_iterator(prologue_instrs.end())); + } - // 确定插入点(在函数名标签之后) - auto insert_pos = entry_instrs.begin(); - if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) { - insert_pos++; - } - - // 一次性将所有序言指令插入,安全且高效 - if (!prologue_instrs.empty()) { - entry_instrs.insert(insert_pos, - std::make_move_iterator(prologue_instrs.begin()), - std::make_move_iterator(prologue_instrs.end())); - } + // --- 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; - // --- 2. 插入尾声 --- - for (auto& mbb : mfunc->getBlocks()) { - for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { - if ((*it)->getOpcode() == RVOpcodes::RET) { - // [修复] 创建一个临时 vector 来存放所有尾声指令 - std::vector> epilogue_instrs; + // 同样严格按照 AsmPrinter 的打印顺序 + // 1. 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)); - // a. ld ra, offset(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)); + // 2. 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)); - // b. ld s0, offset(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)); + // 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)); - // c. 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 指令前一次性插入所有尾声指令 - if (!epilogue_instrs.empty()) { - mbb->getInstructions().insert(it, - std::make_move_iterator(epilogue_instrs.begin()), - std::make_move_iterator(epilogue_instrs.end())); + if (!epilogue_instrs.empty()) { + mbb->getInstructions().insert(it, + std::make_move_iterator(epilogue_instrs.begin()), + std::make_move_iterator(epilogue_instrs.end())); + } + // 处理完一个基本块中的RET后,迭代器已失效,需跳出 + goto next_block; } - - // 处理完当前基本块的RET后即可跳出内层循环 - break; } + next_block:; } } } diff --git a/src/RISCv64Backend.cpp b/src/RISCv64Backend.cpp index 26e37ac..c32af0c 100644 --- a/src/RISCv64Backend.cpp +++ b/src/RISCv64Backend.cpp @@ -124,14 +124,6 @@ std::string RISCv64CodeGen::function_gen(Function* func) { CalleeSavedHandler callee_handler; callee_handler.runOnMachineFunction(mfunc.get()); - // 阶段 3.2: 插入序言和尾声 - PrologueEpilogueInsertionPass pei_pass; - pei_pass.runOnMachineFunction(mfunc.get()); - - // 阶段 3.3: 清理产生的大立即数 - LegalizeImmediatesPass legalizer; - legalizer.runOnMachineFunction(mfunc.get()); - // 阶段 4: 窥孔优化 (Peephole Optimization) PeepholeOptimizer peephole; peephole.runOnMachineFunction(mfunc.get()); @@ -140,6 +132,14 @@ std::string RISCv64CodeGen::function_gen(Function* func) { PostRA_Scheduler local_scheduler; local_scheduler.runOnMachineFunction(mfunc.get()); + // 阶段 3.2: 插入序言和尾声 + PrologueEpilogueInsertionPass pei_pass; + pei_pass.runOnMachineFunction(mfunc.get()); + + // 阶段 3.3: 清理产生的大立即数 + LegalizeImmediatesPass legalizer; + legalizer.runOnMachineFunction(mfunc.get()); + // 阶段 6: 代码发射 (Code Emission) std::stringstream ss; RISCv64AsmPrinter printer(mfunc.get());