From b3cf3cba29d2f1098aeee0826d88b46b62f5db50 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Wed, 30 Jul 2025 22:16:37 +0800 Subject: [PATCH] =?UTF-8?q?[backend]=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=A4=9A?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=BC=A0=E9=80=92=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/runit-single.sh | 2 +- .../Handler/PrologueEpilogueInsertion.cpp | 40 +++++++++---------- src/backend/RISCv64/RISCv64AsmPrinter.cpp | 3 ++ src/backend/RISCv64/RISCv64ISel.cpp | 27 +++++++++++++ src/backend/RISCv64/RISCv64RegAlloc.cpp | 28 +++++++++++++ src/include/backend/RISCv64/RISCv64LLIR.h | 3 +- 6 files changed, 79 insertions(+), 24 deletions(-) diff --git a/script/runit-single.sh b/script/runit-single.sh index 106873b..549c3bc 100644 --- a/script/runit-single.sh +++ b/script/runit-single.sh @@ -23,7 +23,7 @@ EXECUTE_MODE=false CLEAN_MODE=false SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒) GCC_TIMEOUT=10 # gcc 编译超时 (秒) -EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒) +EXEC_TIMEOUT=600 # qemu 自动化执行超时 (秒) MAX_OUTPUT_LINES=50 # 对比失败时显示的最大行数 SY_FILES=() # 存储用户提供的 .sy 文件列表 PASSED_CASES=0 diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index f43ca1c..30fa6bd 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -1,12 +1,27 @@ #include "PrologueEpilogueInsertion.h" #include "RISCv64ISel.h" #include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果 +#include namespace sysy { char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { + for (auto& mbb : mfunc->getBlocks()) { + auto& instrs = mbb->getInstructions(); + + // 使用标准的 Erase-Remove Idiom 来删除满足条件的元素 + instrs.erase( + std::remove_if(instrs.begin(), instrs.end(), + [](const std::unique_ptr& instr) { + return instr->getOpcode() == RVOpcodes::PSEUDO_KEEPALIVE; + } + ), + instrs.end() + ); + } + StackFrameInfo& frame_info = mfunc->getFrameInfo(); Function* F = mfunc->getFunc(); RISCv64ISel* isel = mfunc->getISel(); @@ -64,54 +79,35 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) set_fp->addOperand(std::make_unique(aligned_stack_size)); prologue_instrs.push_back(std::move(set_fp)); - // --- [正确逻辑] 在s0设置完毕后,使用物理寄存器加载栈参数 --- + // --- 在s0设置完毕后,使用物理寄存器加载栈参数 --- if (F && isel) { - // 定义暂存寄存器 - const PhysicalReg INT_SCRATCH_REG = PhysicalReg::T5; - const PhysicalReg FP_SCRATCH_REG = PhysicalReg::F7; - int arg_idx = 0; for (Argument* arg : F->getArguments()) { if (arg_idx >= 8) { unsigned vreg = isel->getVReg(arg); - // 确认RegAlloc已经为这个vreg计算了偏移量,并且分配了物理寄存器 if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) { int offset = frame_info.alloca_offsets.at(vreg); PhysicalReg dest_preg = vreg_to_preg_map.at(vreg); Type* arg_type = arg->getType(); - // 根据类型执行不同的加载序列 if (arg_type->isFloat()) { - // 1. flw ft7, offset(s0) auto load_arg = std::make_unique(RVOpcodes::FLW); - load_arg->addOperand(std::make_unique(FP_SCRATCH_REG)); + 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)); - // 2. fmv.s dest_preg, ft7 - auto move_arg = std::make_unique(RVOpcodes::FMV_S); - move_arg->addOperand(std::make_unique(dest_preg)); - move_arg->addOperand(std::make_unique(FP_SCRATCH_REG)); - prologue_instrs.push_back(std::move(move_arg)); } else { - // 确定是加载32位(lw)还是64位(ld) RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW; - // 1. lw/ld t5, offset(s0) auto load_arg = std::make_unique(load_op); - load_arg->addOperand(std::make_unique(INT_SCRATCH_REG)); + 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)); - // 2. mv dest_preg, t5 - auto move_arg = std::make_unique(RVOpcodes::MV); - move_arg->addOperand(std::make_unique(dest_preg)); - move_arg->addOperand(std::make_unique(INT_SCRATCH_REG)); - prologue_instrs.push_back(std::move(move_arg)); } } } diff --git a/src/backend/RISCv64/RISCv64AsmPrinter.cpp b/src/backend/RISCv64/RISCv64AsmPrinter.cpp index 75ebd4d..183003c 100644 --- a/src/backend/RISCv64/RISCv64AsmPrinter.cpp +++ b/src/backend/RISCv64/RISCv64AsmPrinter.cpp @@ -144,6 +144,9 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) { case RVOpcodes::FRAME_STORE_F: if (!debug) throw std::runtime_error("FRAME_STORE_F not eliminated before AsmPrinter"); *OS << "frame_store_f "; break; + case RVOpcodes::PSEUDO_KEEPALIVE: + if (!debug) throw std::runtime_error("PSEUDO_KEEPALIVE not eliminated before AsmPrinter"); + *OS << "keepalive "; break; default: throw std::runtime_error("Unknown opcode in AsmPrinter"); } diff --git a/src/backend/RISCv64/RISCv64ISel.cpp b/src/backend/RISCv64/RISCv64ISel.cpp index f1b6497..f07c0e5 100644 --- a/src/backend/RISCv64/RISCv64ISel.cpp +++ b/src/backend/RISCv64/RISCv64ISel.cpp @@ -166,6 +166,33 @@ void RISCv64ISel::selectBasicBlock(BasicBlock* bb) { select_recursive(node_to_select); } } + + if (CurMBB == MFunc->getBlocks().front().get()) { // 只对入口块操作 + auto keepalive = std::make_unique(RVOpcodes::PSEUDO_KEEPALIVE); + for (Argument* arg : F->getArguments()) { + keepalive->addOperand(std::make_unique(getVReg(arg))); + } + + auto& instrs = CurMBB->getInstructions(); + auto insert_pos = instrs.end(); + + // 关键:检查基本块是否以一个“终止指令”结尾 + if (!instrs.empty()) { + RVOpcodes last_op = instrs.back()->getOpcode(); + // 扩充了判断条件,涵盖所有可能的终止指令 + if (last_op == RVOpcodes::J || last_op == RVOpcodes::RET || + last_op == RVOpcodes::BEQ || last_op == RVOpcodes::BNE || + last_op == RVOpcodes::BLT || last_op == RVOpcodes::BGE || + last_op == RVOpcodes::BLTU || last_op == RVOpcodes::BGEU) + { + // 如果是,插入点就在这个终止指令之前 + insert_pos = std::prev(instrs.end()); + } + } + + // 在计算出的正确位置插入伪指令 + instrs.insert(insert_pos, std::move(keepalive)); + } } // 核心函数:为DAG节点选择并生成MachineInstr (已修复和增强的完整版本) diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index 8bee681..4010833 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -351,6 +351,18 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def) auto opcode = instr->getOpcode(); + if (opcode == RVOpcodes::PSEUDO_KEEPALIVE) { + for (auto& op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual()) { + use.insert(reg_op->getVRegNum()); // 它的所有操作数都是 "use" + } + } + } + return; // 处理完毕 + } + // 1. 特殊指令的 `is_def` 标志调整 // 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。 if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW || @@ -673,6 +685,22 @@ void RISCv64RegAlloc::buildInterferenceGraph() { } } + // 所有在某一点上同时活跃的寄存器(即live_out集合中的所有成员), + // 它们之间必须两两互相干扰。 + // 这会根据我们修正后的 liveness 信息,在所有参数vreg之间构建一个完全图(clique)。 + std::vector live_out_vec(live_out.begin(), live_out.end()); + for (size_t i = 0; i < live_out_vec.size(); ++i) { + for (size_t j = i + 1; j < live_out_vec.size(); ++j) { + unsigned u = live_out_vec[i]; + unsigned v = live_out_vec[j]; + if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) { + std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n"; + } + interference_graph[u].insert(v); + interference_graph[v].insert(u); + } + } + // 在非move指令中,def 与 use 互相干扰 if (instr->getOpcode() != RVOpcodes::MV) { for (unsigned d : def) { diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index 9f44776..be11528 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -92,7 +92,7 @@ enum class RVOpcodes { FMV_X_W, // fmv.x.w rd, rs1 (浮点寄存器位模式 -> 整数寄存器) FNEG_S, // fneg.s rd, rs (浮点取负) - // 新增伪指令,用于解耦栈帧处理 + // 伪指令 FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw) FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld) FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw) @@ -100,6 +100,7 @@ enum class RVOpcodes { FRAME_LOAD_F, // 从栈帧加载单精度浮点数 FRAME_STORE_F, // 将单精度浮点数存入栈帧 FRAME_ADDR, // 获取栈帧变量的地址 + PSEUDO_KEEPALIVE, // 保持寄存器活跃,防止优化器删除 }; inline bool isGPR(PhysicalReg reg) {