diff --git a/script/runit-riscv64.sh b/script/runit-riscv64.sh index 3a0026f..00e65a4 100644 --- a/script/runit-riscv64.sh +++ b/script/runit-riscv64.sh @@ -60,11 +60,7 @@ display_file_content() { # 清理临时文件的函数 clean_tmp() { echo "正在清理临时目录: ${TMP_DIR}" - rm -rf "${TMP_DIR}"/*.s \ - "${TMP_DIR}"/*_sysyc_riscv64 \ - "${TMP_DIR}"/*_sysyc_riscv64.actual_out \ - "${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \ - "${TMP_DIR}"/*_sysyc_riscv64.o + rm -rf "${TMP_DIR}"/* echo "清理完成。" } diff --git a/script/runit-single.sh b/script/runit-single.sh index 8b7804f..ed32181 100644 --- a/script/runit-single.sh +++ b/script/runit-single.sh @@ -68,7 +68,7 @@ display_file_content() { fi } -# --- 本次修改点: 整个参数解析逻辑被重写 --- +# --- 参数解析 --- # 使用标准的 while 循环来健壮地处理任意顺序的参数 while [[ "$#" -gt 0 ]]; do case "$1" in @@ -164,6 +164,16 @@ for sy_file in "${SY_FILES[@]}"; do echo "======================================================================" echo "正在处理: ${sy_file}" + # --- 本次修改点: 拷贝源文件到 tmp 目录 --- + echo " 拷贝源文件到 ${TMP_DIR}..." + cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")" + if [ -f "${input_file}" ]; then + cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")" + fi + if [ -f "${output_reference_file}" ]; then + cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")" + fi + # 步骤 1: sysyc 编译 echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..." timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}" diff --git a/src/backend/RISCv64/CMakeLists.txt b/src/backend/RISCv64/CMakeLists.txt index f1e8f55..4330e40 100644 --- a/src/backend/RISCv64/CMakeLists.txt +++ b/src/backend/RISCv64/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(riscv64_backend_lib STATIC Handler/CalleeSavedHandler.cpp Handler/LegalizeImmediates.cpp Handler/PrologueEpilogueInsertion.cpp + Handler/EliminateFrameIndices.cpp Optimize/Peephole.cpp Optimize/PostRA_Scheduler.cpp Optimize/PreRA_Scheduler.cpp diff --git a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp index cdbccc1..e7587b9 100644 --- a/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp +++ b/src/backend/RISCv64/Handler/CalleeSavedHandler.cpp @@ -8,11 +8,6 @@ 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; @@ -20,114 +15,37 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) { void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) { StackFrameInfo& frame_info = mfunc->getFrameInfo(); - - std::set used_callee_saved; - - // 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 && !reg_op->isVirtual()) { - PhysicalReg preg = reg_op->getPReg(); - - // 检查整数 s1-s11 - if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) { - used_callee_saved.insert(preg); - } - // 检查浮点 fs0-fs11 (f8,f9,f18-f27) - else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) { - used_callee_saved.insert(preg); - } - } - }; - - if (op->getKind() == MachineOperand::KIND_REG) { - check_and_insert_reg(static_cast(op.get())); - } else if (op->getKind() == MachineOperand::KIND_MEM) { - check_and_insert_reg(static_cast(op.get())->getBase()); - } - } - } - } + const std::set& used_callee_saved = frame_info.used_callee_saved_regs; if (used_callee_saved.empty()) { frame_info.callee_saved_size = 0; + frame_info.callee_saved_regs_to_store.clear(); return; } - // 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); + // 1. 计算被调用者保存寄存器所需的总空间大小 + // s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中 + int size = 0; + std::set regs_to_save = used_callee_saved; + if (regs_to_save.count(PhysicalReg::S0)) { + regs_to_save.erase(PhysicalReg::S0); } - - std::vector> save_instrs; - // [关键] 从局部变量区域之后开始分配空间 - int current_offset = - (16 + frame_info.locals_size); + size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit) + frame_info.callee_saved_size = size; - for (PhysicalReg reg : sorted_regs) { - current_offset -= 8; - RVOpcodes save_op = is_fp_reg(reg) ? RVOpcodes::FSD : RVOpcodes::SD; + // 2. 创建一个有序的、需要保存的寄存器列表,以便后续 Pass 确定地生成代码 + // s0 不应包含在此列表中,因为它由 PEI Pass 特殊处理 + std::vector sorted_regs(regs_to_save.begin(), regs_to_save.end()); + std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){ + return static_cast(a) < static_cast(b); + }); + frame_info.callee_saved_regs_to_store = sorted_regs; - 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(save_instr)); - } - - if (!save_instrs.empty()) { - entry_instrs.insert(insert_pos, - std::make_move_iterator(save_instrs.begin()), - std::make_move_iterator(save_instrs.end())); - } - - // 4. 在函数结尾(ret之前)插入恢复指令 - for (auto& mbb : mfunc->getBlocks()) { - for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) { - if ((*it)->getOpcode() == RVOpcodes::RET) { - std::vector> restore_instrs; - // [关键] 使用与保存时完全相同的逻辑来计算偏移量 - current_offset = - (16 + frame_info.locals_size); - - for (PhysicalReg reg : sorted_regs) { - current_offset -= 8; - 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(restore_instr)); - } - - if (!restore_instrs.empty()) { - mbb->getInstructions().insert(it, - std::make_move_iterator(restore_instrs.begin()), - std::make_move_iterator(restore_instrs.end())); - } - goto next_block_label; - } - } - next_block_label:; - } + // 3. 更新栈帧总大小。 + // 这是初步计算,PEI Pass 会进行最终的对齐。 + frame_info.total_size = frame_info.locals_size + + frame_info.spill_size + + frame_info.callee_saved_size; } -} // namespace sysy \ No newline at end of file +} // namespace sysy diff --git a/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp new file mode 100644 index 0000000..d343fbf --- /dev/null +++ b/src/backend/RISCv64/Handler/EliminateFrameIndices.cpp @@ -0,0 +1,231 @@ +#include "EliminateFrameIndices.h" +#include "RISCv64ISel.h" +#include +#include + +namespace sysy { + +// getTypeSizeInBytes 是一个通用辅助函数,保持不变 +unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) { + if (!type) { + assert(false && "Cannot get size of a null type."); + return 0; + } + + switch (type->getKind()) { + case Type::kInt: + case Type::kFloat: + return 4; + case Type::kPointer: + return 8; + case Type::kArray: { + auto arrayType = type->as(); + return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType()); + } + default: + assert(false && "Unsupported type for size calculation."); + return 0; + } +} + +void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) { + StackFrameInfo& frame_info = mfunc->getFrameInfo(); + Function* F = mfunc->getFunc(); + RISCv64ISel* isel = mfunc->getISel(); + + // 在这里处理栈传递的参数,以便在寄存器分配前就将数据流显式化,修复溢出逻辑的BUG。 + + // 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量 + // 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后 + int local_var_offset = 16; + + if(F) { // 确保函数指针有效 + for (auto& bb : F->getBasicBlocks()) { + for (auto& inst : bb->getInstructions()) { + if (auto alloca = dynamic_cast(inst.get())) { + Type* allocated_type = alloca->getType()->as()->getBaseType(); + int size = getTypeSizeInBytes(allocated_type); + + // RISC-V要求栈地址8字节对齐 + size = (size + 7) & ~7; + if (size == 0) size = 8; // 至少分配8字节 + + local_var_offset += size; + unsigned alloca_vreg = isel->getVReg(alloca); + // 局部变量使用相对于s0的负向偏移 + frame_info.alloca_offsets[alloca_vreg] = -local_var_offset; + } + } + } + } + + // 记录仅由AllocaInst分配的局部变量的总大小 + frame_info.locals_size = local_var_offset - 16; + // 记录局部变量区域分配结束的最终偏移量 + frame_info.locals_end_offset = -local_var_offset; + + // 在函数入口为所有栈传递的参数插入load指令 + // 这个步骤至关重要:它在寄存器分配之前,为这些参数的vreg创建了明确的“定义(def)”指令。 + // 这解决了在高寄存器压力下,当这些vreg被溢出时,`rewriteProgram`找不到其定义点而崩溃的问题。 + if (F && isel && !mfunc->getBlocks().empty()) { + MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); + std::vector> arg_load_instrs; + + // 步骤 3.1: 生成所有加载栈参数的指令,暂存起来 + 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++; + } + + //仅当有需要加载的栈参数时,才执行插入逻辑 + if (!arg_load_instrs.empty()) { + auto& entry_instrs = entry_block->getInstructions(); + auto insertion_point = entry_instrs.begin(); // 默认插入点为块的开头 + auto last_arg_save_it = entry_instrs.end(); + + // 步骤 3.2: 寻找一个安全的插入点。 + // 遍历入口块的指令,找到最后一条保存“寄存器传递参数”的伪指令。 + // 这样可以确保我们在所有 a0-a7 参数被保存之后,才执行可能覆盖它们的加载指令。 + for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) { + MachineInstr* instr = it->get(); + // 寻找代表保存参数到栈的伪指令 + if (instr->getOpcode() == RVOpcodes::FRAME_STORE_W || + instr->getOpcode() == RVOpcodes::FRAME_STORE_D || + instr->getOpcode() == RVOpcodes::FRAME_STORE_F) { + + // 检查被保存的值是否是寄存器参数 (arg_no < 8) + auto& operands = instr->getOperands(); + if (operands.empty() || operands[0]->getKind() != MachineOperand::KIND_REG) continue; + + unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); + Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr; + + if (auto ir_arg = dynamic_cast(ir_value)) { + if (ir_arg->getIndex() < 8) { + last_arg_save_it = it; // 找到了一个保存寄存器参数的指令,更新位置 + } + } + } + } + + // 如果找到了这样的保存指令,我们的插入点就在它之后 + if (last_arg_save_it != entry_instrs.end()) { + insertion_point = std::next(last_arg_save_it); + } + + // 步骤 3.3: 在计算出的安全位置,一次性插入所有新创建的参数加载指令 + entry_instrs.insert(insertion_point, + 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()) { + RVOpcodes opcode = instr_ptr->getOpcode(); + + if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D || opcode == RVOpcodes::FRAME_LOAD_F) { + RVOpcodes real_load_op; + if (opcode == RVOpcodes::FRAME_LOAD_W) real_load_op = RVOpcodes::LW; + else if (opcode == RVOpcodes::FRAME_LOAD_D) real_load_op = RVOpcodes::LD; + else real_load_op = RVOpcodes::FLW; + + auto& operands = instr_ptr->getOperands(); + unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); + unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); + int offset = frame_info.alloca_offsets.at(alloca_vreg); + auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType())); + + // 展开为: addi addr_vreg, s0, offset + auto addi = std::make_unique(RVOpcodes::ADDI); + addi->addOperand(std::make_unique(addr_vreg)); + addi->addOperand(std::make_unique(PhysicalReg::S0)); + addi->addOperand(std::make_unique(offset)); + new_instructions.push_back(std::move(addi)); + + // 展开为: lw/ld/flw dest_vreg, 0(addr_vreg) + auto load_instr = std::make_unique(real_load_op); + load_instr->addOperand(std::make_unique(dest_vreg)); + load_instr->addOperand(std::make_unique( + std::make_unique(addr_vreg), + std::make_unique(0))); + new_instructions.push_back(std::move(load_instr)); + + } else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D || opcode == RVOpcodes::FRAME_STORE_F) { + RVOpcodes real_store_op; + if (opcode == RVOpcodes::FRAME_STORE_W) real_store_op = RVOpcodes::SW; + else if (opcode == RVOpcodes::FRAME_STORE_D) real_store_op = RVOpcodes::SD; + else real_store_op = RVOpcodes::FSW; + + auto& operands = instr_ptr->getOperands(); + unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); + unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); + int offset = frame_info.alloca_offsets.at(alloca_vreg); + auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType())); + + // 展开为: addi addr_vreg, s0, offset + auto addi = std::make_unique(RVOpcodes::ADDI); + addi->addOperand(std::make_unique(addr_vreg)); + addi->addOperand(std::make_unique(PhysicalReg::S0)); + addi->addOperand(std::make_unique(offset)); + new_instructions.push_back(std::move(addi)); + + // 展开为: sw/sd/fsw src_vreg, 0(addr_vreg) + auto store_instr = std::make_unique(real_store_op); + store_instr->addOperand(std::make_unique(src_vreg)); + store_instr->addOperand(std::make_unique( + std::make_unique(addr_vreg), + std::make_unique(0))); + new_instructions.push_back(std::move(store_instr)); + + } else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { + auto& operands = instr_ptr->getOperands(); + unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); + unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); + int offset = frame_info.alloca_offsets.at(alloca_vreg); + + // 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset` + auto addi = std::make_unique(RVOpcodes::ADDI); + addi->addOperand(std::make_unique(dest_vreg)); + addi->addOperand(std::make_unique(PhysicalReg::S0)); + addi->addOperand(std::make_unique(offset)); + new_instructions.push_back(std::move(addi)); + + } else { + new_instructions.push_back(std::move(instr_ptr)); + } + } + mbb->getInstructions() = std::move(new_instructions); + } +} + +} // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp index 30fa6bd..0eef863 100644 --- a/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp +++ b/src/backend/RISCv64/Handler/PrologueEpilogueInsertion.cpp @@ -1,17 +1,22 @@ #include "PrologueEpilogueInsertion.h" +#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义 #include "RISCv64ISel.h" -#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果 #include +#include +#include namespace sysy { char PrologueEpilogueInsertionPass::ID = 0; void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) { + StackFrameInfo& frame_info = mfunc->getFrameInfo(); + Function* F = mfunc->getFunc(); + RISCv64ISel* isel = mfunc->getISel(); + + // 1. 清理 KEEPALIVE 伪指令 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) { @@ -22,39 +27,49 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) ); } - StackFrameInfo& frame_info = mfunc->getFrameInfo(); - Function* F = mfunc->getFunc(); - RISCv64ISel* isel = mfunc->getISel(); - - // [关键] 获取寄存器分配的结果 (vreg -> preg 的映射) - // RegAlloc Pass 必须已经运行过 + // 2. 确定需要保存的被调用者保存寄存器 (callee-saved) auto& vreg_to_preg_map = frame_info.vreg_to_preg_map; + std::set used_callee_saved_regs_set; + const auto& callee_saved_int = getCalleeSavedIntRegs(); + const auto& callee_saved_fp = getCalleeSavedFpRegs(); - // 完全遵循 AsmPrinter 中的计算逻辑 + for (const auto& pair : vreg_to_preg_map) { + PhysicalReg preg = pair.second; + bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end(); + bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end(); + if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) { + used_callee_saved_regs_set.insert(preg); + } + } + frame_info.callee_saved_regs_to_store.assign( + used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end() + ); + std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end()); + frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8; + + // 3. 计算最终的栈帧总大小 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) { - // --- 1. 插入序言 --- + // --- 4. 插入完整的序言 --- MachineBasicBlock* entry_block = mfunc->getBlocks().front().get(); auto& entry_instrs = entry_block->getInstructions(); - std::vector> prologue_instrs; - // 1. addi sp, sp, -aligned_stack_size + // 4.1. 分配栈帧 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) + // 4.2. 保存 ra 和 s0 auto save_ra = std::make_unique(RVOpcodes::SD); save_ra->addOperand(std::make_unique(PhysicalReg::RA)); save_ra->addOperand(std::make_unique( @@ -62,8 +77,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) 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( @@ -72,66 +85,54 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); prologue_instrs.push_back(std::move(save_fp)); - // 4. addi s0, sp, aligned_stack_size + // 4.3. 设置新的帧指针 s0 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)); - - // --- 在s0设置完毕后,使用物理寄存器加载栈参数 --- - if (F && isel) { - int arg_idx = 0; - for (Argument* arg : F->getArguments()) { - if (arg_idx >= 8) { - unsigned vreg = isel->getVReg(arg); - - 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()) { - auto load_arg = std::make_unique(RVOpcodes::FLW); - 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)); - } else { - RVOpcodes load_op = 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++; - } - } - // 确定插入点 - auto insert_pos = entry_instrs.begin(); - - // 一次性将所有序言指令插入 - if (!prologue_instrs.empty()) { - entry_instrs.insert(insert_pos, - std::make_move_iterator(prologue_instrs.begin()), - std::make_move_iterator(prologue_instrs.end())); + // 4.4. 保存所有使用到的被调用者保存寄存器 + int next_available_offset = -(16 + frame_info.locals_size + frame_info.spill_size); + for (const auto& reg : frame_info.callee_saved_regs_to_store) { + // 采用“先使用,后更新”逻辑 + RVOpcodes store_op = isFPR(reg) ? RVOpcodes::FSD : RVOpcodes::SD; + auto save_cs_reg = std::make_unique(store_op); + save_cs_reg->addOperand(std::make_unique(reg)); + save_cs_reg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(next_available_offset) // 使用当前偏移 + )); + prologue_instrs.push_back(std::move(save_cs_reg)); + next_available_offset -= 8; // 为下一个寄存器准备偏移 } - // --- 2. 插入尾声 (此部分逻辑保持不变) --- + // 4.5. 将所有生成的序言指令一次性插入到函数入口 + entry_instrs.insert(entry_instrs.begin(), + std::make_move_iterator(prologue_instrs.begin()), + std::make_move_iterator(prologue_instrs.end())); + + // --- 5. 插入完整的尾声 --- 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; + + // 5.1. 恢复被调用者保存寄存器 + int next_available_offset_restore = -(16 + frame_info.locals_size + frame_info.spill_size); + for (const auto& reg : frame_info.callee_saved_regs_to_store) { + RVOpcodes load_op = isFPR(reg) ? RVOpcodes::FLD : RVOpcodes::LD; + auto restore_cs_reg = std::make_unique(load_op); + restore_cs_reg->addOperand(std::make_unique(reg)); + restore_cs_reg->addOperand(std::make_unique( + std::make_unique(PhysicalReg::S0), + std::make_unique(next_available_offset_restore) // 使用当前偏移 + )); + epilogue_instrs.push_back(std::move(restore_cs_reg)); + next_available_offset_restore -= 8; // 为下一个寄存器准备偏移 + } - // 1. ld ra + // 5.2. 恢复 ra 和 s0 auto restore_ra = std::make_unique(RVOpcodes::LD); restore_ra->addOperand(std::make_unique(PhysicalReg::RA)); restore_ra->addOperand(std::make_unique( @@ -139,8 +140,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) std::make_unique(aligned_stack_size - 8) )); epilogue_instrs.push_back(std::move(restore_ra)); - - // 2. ld s0 auto restore_fp = std::make_unique(RVOpcodes::LD); restore_fp->addOperand(std::make_unique(PhysicalReg::S0)); restore_fp->addOperand(std::make_unique( @@ -149,18 +148,18 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) )); epilogue_instrs.push_back(std::move(restore_fp)); - // 3. addi sp, sp, aligned_stack_size + // 5.3. 释放栈帧 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)); - if (!epilogue_instrs.empty()) { - mbb->getInstructions().insert(it, - std::make_move_iterator(epilogue_instrs.begin()), - std::make_move_iterator(epilogue_instrs.end())); - } + // 将尾声指令插入到 RET 指令之前 + mbb->getInstructions().insert(it, + std::make_move_iterator(epilogue_instrs.begin()), + std::make_move_iterator(epilogue_instrs.end())); + goto next_block; } } diff --git a/src/backend/RISCv64/RISCv64AsmPrinter.cpp b/src/backend/RISCv64/RISCv64AsmPrinter.cpp index 5e73cd2..fcedb43 100644 --- a/src/backend/RISCv64/RISCv64AsmPrinter.cpp +++ b/src/backend/RISCv64/RISCv64AsmPrinter.cpp @@ -104,7 +104,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) { case RVOpcodes::FMV_S: *OS << "fmv.s "; break; case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break; case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break; - case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑 + case RVOpcodes::CALL: { // 为CALL指令添加特殊处理逻辑 *OS << "call "; // 遍历所有操作数,只寻找并打印函数名标签 for (const auto& op : instr->getOperands()) { diff --git a/src/backend/RISCv64/RISCv64Backend.cpp b/src/backend/RISCv64/RISCv64Backend.cpp index 0f948f0..e45248f 100644 --- a/src/backend/RISCv64/RISCv64Backend.cpp +++ b/src/backend/RISCv64/RISCv64Backend.cpp @@ -73,7 +73,7 @@ std::string RISCv64CodeGen::module_gen() { for (const auto& global_ptr : module->getGlobals()) { GlobalValue* global = global_ptr.get(); - // [核心修改] 使用更健壮的逻辑来判断是否为大型零初始化数组 + // 使用更健壮的逻辑来判断是否为大型零初始化数组 bool is_all_zeros = true; const auto& init_values = global->getInitValues(); @@ -174,13 +174,37 @@ std::string RISCv64CodeGen::function_gen(Function* func) { // === 完整的后端处理流水线 === // 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers) + DEBUG = 0; + DEEPDEBUG = 0; + RISCv64ISel isel; std::unique_ptr mfunc = isel.runOnFunction(func); // 第一次调试打印输出 - std::stringstream ss1; - RISCv64AsmPrinter printer1(mfunc.get()); - printer1.run(ss1, true); + 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(); + } + 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; @@ -194,10 +218,20 @@ std::string RISCv64CodeGen::function_gen(Function* func) { RISCv64RegAlloc reg_alloc(mfunc.get()); reg_alloc.run(); + 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()); @@ -210,7 +244,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) { PrologueEpilogueInsertionPass pei_pass; pei_pass.runOnMachineFunction(mfunc.get()); - // 阶段 3.3: 清理产生的大立即数 + // 阶段 3.3: 大立即数合法化 LegalizeImmediatesPass legalizer; legalizer.runOnMachineFunction(mfunc.get()); @@ -218,8 +252,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) { std::stringstream ss; RISCv64AsmPrinter printer(mfunc.get()); printer.run(ss); - if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中 + return ss.str(); + } } // namespace sysy \ No newline at end of file diff --git a/src/backend/RISCv64/RISCv64ISel.cpp b/src/backend/RISCv64/RISCv64ISel.cpp index e6b0929..2f7c9ae 100644 --- a/src/backend/RISCv64/RISCv64ISel.cpp +++ b/src/backend/RISCv64/RISCv64ISel.cpp @@ -2,8 +2,8 @@ #include #include #include -#include // For std::fabs -#include // For std::numeric_limits +#include +#include #include namespace sysy { @@ -402,7 +402,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { Value* base = nullptr; Value* offset = nullptr; - // [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue + // 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue if (dynamic_cast(lhs) || dynamic_cast(lhs)) { base = lhs; offset = rhs; @@ -421,7 +421,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { CurMBB->addInstruction(std::move(li)); } - // 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址 + // 2. 根据基地址的类型,生成不同的指令来获取基地址 auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址 // 情况一:基地址是局部栈变量 @@ -452,7 +452,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { } } - // [V2优点] 在BINARY节点内部按需加载常量操作数。 + // 在BINARY节点内部按需加载常量操作数。 auto load_val_if_const = [&](Value* val) { if (auto c = dynamic_cast(val)) { if (DEBUG) { @@ -483,7 +483,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { auto dest_vreg = getVReg(bin); auto lhs_vreg = getVReg(lhs); - // [V2优点] 融合 ADDIW 优化。 + // 融合 ADDIW 优化。 if (rhs_is_imm_opt) { auto rhs_const = dynamic_cast(rhs); auto instr = std::make_unique(RVOpcodes::ADDIW); @@ -952,7 +952,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { // --- 步骤 3: 生成CALL指令 --- auto call_instr = std::make_unique(RVOpcodes::CALL); - // [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数 + // 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数 if (!call->getType()->isVoid()) { unsigned dest_vreg = getVReg(call); call_instr->addOperand(std::make_unique(dest_vreg)); @@ -1029,7 +1029,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { } else { // --- 处理整数/指针返回值 --- // 返回值需要被放入 a0 - // [V2优点] 在RETURN节点内加载常量返回值 + // 在RETURN节点内加载常量返回值 if (auto const_val = dynamic_cast(ret_val)) { auto li_instr = std::make_unique(RVOpcodes::LI); li_instr->addOperand(std::make_unique(PhysicalReg::A0)); @@ -1043,7 +1043,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { } } } - // [V1设计保留] 函数尾声(epilogue)不由RETURN节点生成, + // 函数尾声(epilogue)不由RETURN节点生成, // 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。 auto ret_mi = std::make_unique(RVOpcodes::RET); CurMBB->addInstruction(std::move(ret_mi)); @@ -1057,7 +1057,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { auto then_bb_name = cond_br->getThenBlock()->getName(); auto else_bb_name = cond_br->getElseBlock()->getName(); - // [优化] 检查分支条件是否为编译期常量 + // 检查分支条件是否为编译期常量 if (auto const_cond = dynamic_cast(condition)) { // 如果条件是常量,直接生成一个无条件跳转J,而不是BNE if (const_cond->getInt() != 0) { // 条件为 true @@ -1072,7 +1072,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { } // 如果条件不是常量,则执行标准流程 else { - // [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了) + // 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了) // 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获 if (auto const_val = dynamic_cast(condition)) { auto li = std::make_unique(RVOpcodes::LI); @@ -1106,7 +1106,7 @@ void RISCv64ISel::selectNode(DAGNode* node) { } case DAGNode::MEMSET: { - // [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。 + // Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。 // 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。 // 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。 @@ -1454,7 +1454,7 @@ std::vector> RISCv64ISel::build_dag(BasicB // 依次添加所有索引作为后续的操作数 for (auto index : gep->getIndices()) { - // [修复] 从 Use 对象中获取真正的 Value* + // 从 Use 对象中获取真正的 Value* gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage)); } } else if (auto load = dynamic_cast(inst)) { @@ -1558,7 +1558,7 @@ unsigned RISCv64ISel::getTypeSizeInBytes(Type* type) { } } -// [新] 打印DAG图以供调试的辅助函数 +// 打印DAG图以供调试的辅助函数 void RISCv64ISel::print_dag(const std::vector>& dag, const std::string& bb_name) { // 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印 // if (!DEBUG) return; diff --git a/src/backend/RISCv64/RISCv64LLIR.cpp b/src/backend/RISCv64/RISCv64LLIR.cpp index 3816ad1..3a580d7 100644 --- a/src/backend/RISCv64/RISCv64LLIR.cpp +++ b/src/backend/RISCv64/RISCv64LLIR.cpp @@ -1,6 +1,122 @@ #include "RISCv64LLIR.h" #include +#include // 用于 std::ostream 和 std::cerr +#include // 用于 std::string namespace sysy { -} \ No newline at end of file +// 辅助函数:将 PhysicalReg 枚举转换为可读的字符串 +std::string regToString(PhysicalReg reg) { + switch (reg) { + case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra"; + case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp"; + case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0"; + case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2"; + case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1"; + case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1"; + case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3"; + case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5"; + case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7"; + case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3"; + case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5"; + case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7"; + case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9"; + case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11"; + case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4"; + case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6"; + case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1"; + case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3"; + case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5"; + case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7"; + case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9"; + case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11"; + case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13"; + case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15"; + case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17"; + case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19"; + case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21"; + case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23"; + case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25"; + case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27"; + case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29"; + case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31"; + default: return "UNKNOWN_REG"; + } +} + +// 打印栈帧信息的完整实现 +void MachineFunction::dumpStackFrameInfo(std::ostream& os) const { + const StackFrameInfo& info = frame_info; + + os << "--- Stack Frame Info for function '" << getName() << "' ---\n"; + + // 打印尺寸信息 + os << " Sizes:\n"; + os << " Total Size: " << info.total_size << " bytes\n"; + os << " Locals Size: " << info.locals_size << " bytes\n"; + os << " Spill Size: " << info.spill_size << " bytes\n"; + os << " Callee-Saved Size: " << info.callee_saved_size << " bytes\n"; + os << "\n"; + + // 打印 Alloca 变量的偏移量 + os << " Alloca Offsets (vreg -> offset from FP):\n"; + if (info.alloca_offsets.empty()) { + os << " (None)\n"; + } else { + for (const auto& pair : info.alloca_offsets) { + os << " %vreg" << pair.first << " -> " << pair.second << "\n"; + } + } + os << "\n"; + + // 打印溢出变量的偏移量 + os << " Spill Offsets (vreg -> offset from FP):\n"; + if (info.spill_offsets.empty()) { + os << " (None)\n"; + } else { + for (const auto& pair : info.spill_offsets) { + os << " %vreg" << pair.first << " -> " << pair.second << "\n"; + } + } + os << "\n"; + + // 打印使用的被调用者保存寄存器 + os << " Used Callee-Saved Registers:\n"; + if (info.used_callee_saved_regs.empty()) { + os << " (None)\n"; + } else { + os << " { "; + for (const auto& reg : info.used_callee_saved_regs) { + os << regToString(reg) << " "; + } + os << "}\n"; + } + os << "\n"; + + // 打印需要保存/恢复的被调用者保存寄存器 (有序) + os << " Callee-Saved Registers to Store/Restore:\n"; + if (info.callee_saved_regs_to_store.empty()) { + os << " (None)\n"; + } else { + os << " [ "; + for (const auto& reg : info.callee_saved_regs_to_store) { + os << regToString(reg) << " "; + } + os << "]\n"; + } + os << "\n"; + + // 打印最终的寄存器分配结果 + os << " Final Register Allocation Map (vreg -> preg):\n"; + if (info.vreg_to_preg_map.empty()) { + os << " (None)\n"; + } else { + for (const auto& pair : info.vreg_to_preg_map) { + os << " %vreg" << pair.first << " -> " << regToString(pair.second) << "\n"; + } + } + + os << "---------------------------------------------------\n"; +} + +} diff --git a/src/backend/RISCv64/RISCv64RegAlloc.cpp b/src/backend/RISCv64/RISCv64RegAlloc.cpp index cf73191..a1cd77c 100644 --- a/src/backend/RISCv64/RISCv64RegAlloc.cpp +++ b/src/backend/RISCv64/RISCv64RegAlloc.cpp @@ -1,128 +1,120 @@ #include "RISCv64RegAlloc.h" -#include "RISCv64ISel.h" -#include "RISCv64AsmPrinter.h" // For DEBUG output -#include "LegalizeImmediates.h" +#include "RISCv64AsmPrinter.h" #include -#include -#include // For DEBUG output -#include // For assert +#include +#include +#include namespace sysy { -RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) { +// 构造函数:初始化寄存器池和数据结构 +RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) + : MFunc(mfunc), + ISel(mfunc->getISel()), + vreg_to_value_map(ISel->getVRegValueMap()), + vreg_type_map(ISel->getVRegTypeMap()) { // 1. 初始化可分配的整数寄存器池 allocable_int_regs = { - PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, - PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6, // T5是大立即数传送寄存器 - 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::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4, /* T5保留 */ PhysicalReg::T6, + PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7, + PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7, PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11, + // S0 是帧指针,不参与分配 }; + K_int = allocable_int_regs.size(); // 2. 初始化可分配的浮点寄存器池 allocable_fp_regs = { - // 浮点临时寄存器 ft0-ft11 - PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, - PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7, + PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7, + PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17, + PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22, + PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27, PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31, - // 浮点参数/返回值寄存器 fa0-fa7 - PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, - PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17, - // 浮点保存寄存器 fs0-fs11 - PhysicalReg::F8, PhysicalReg::F9, - PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, - PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, - PhysicalReg::F26, PhysicalReg::F27 }; - - // 3. 映射所有物理寄存器(包括整数、浮点和特殊寄存器)到特殊的虚拟寄存器ID - // 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器 - for (int i = 0; i < static_cast(PhysicalReg::PHYS_REG_START_ID); ++i) { - auto preg = static_cast(i); - preg_to_vreg_id_map[preg] = static_cast(PhysicalReg::PHYS_REG_START_ID) + i; - } + K_fp = allocable_fp_regs.size(); + + // 3. 预着色所有物理寄存器 + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + for (const auto& reg : allocable_int_regs) precolored.insert(offset + static_cast(reg)); + for (const auto& reg : allocable_fp_regs) precolored.insert(offset + static_cast(reg)); + precolored.insert(offset + static_cast(PhysicalReg::S0)); + precolored.insert(offset + static_cast(PhysicalReg::RA)); + precolored.insert(offset + static_cast(PhysicalReg::SP)); + precolored.insert(offset + static_cast(PhysicalReg::ZERO)); } -// 寄存器分配的主入口点 +// 主入口: 迭代运行分配算法直到无溢出 void RISCv64RegAlloc::run() { - // --- 在所有流程开始前,构建完整的vreg到Value的反向映射 --- - const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap(); - for (const auto& pair : vreg_map_from_isel) { - Value* val = pair.first; - unsigned vreg = pair.second; - vreg_to_value_map[vreg] = val; + if (DEBUG) std::cerr << "===== LLIR Before Running Graph Coloring Register Allocation " << MFunc->getName() << " =====\n"; + std::stringstream ss_before_reg_alloc; + if (DEBUG) { + RISCv64AsmPrinter printer_reg_alloc(MFunc); + printer_reg_alloc.run(ss_before_reg_alloc, true); + std::cout << ss_before_reg_alloc.str(); } - // 阶段 1: 处理函数调用约定(参数寄存器预着色) - handleCallingConvention(); - // 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移) - eliminateFrameIndices(); - // 调试输出当前的LLIR状态 - { // 使用大括号创建一个局部作用域,避免printer变量泄露 - if (DEBUG) { - std::cerr << "\n===== LLIR after eliminateFrameIndices for function: " - << MFunc->getName() << " =====\n"; - // 1. 创建一个 AsmPrinter 实例,传入当前的 MachineFunction - RISCv64AsmPrinter printer(MFunc); - // 2. 调用 run 方法,将结果打印到标准错误流 (std::cerr) - // 3. 必须将 debug 参数设为 true! - // 因为此时指令中仍然包含虚拟寄存器 (%vreg), - // debug模式下的 AsmPrinter 才能正确处理它们而不会报错。 - printer.run(std::cerr, true); - std::cerr << "===== End of LLIR =====\n\n"; + if (DEBUG) std::cerr << "===== Running Graph Coloring Register Allocation for function: " << MFunc->getName() << " =====\n"; + + while (true) { + if (doAllocation()) { + break; + } else { + rewriteProgram(); + if (DEBUG) std::cerr << "--- Spilling detected, re-running allocation ---\n"; } } - // 阶段 3: 活跃性分析 - analyzeLiveness(); - // 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响) - buildInterferenceGraph(); - // 阶段 5: 图着色算法分配物理寄存器 - colorGraph(); - // 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器) - rewriteFunction(); + applyColoring(); - // 将最终的寄存器分配结果保存到MachineFunction的帧信息中,供后续Pass使用 MFunc->getFrameInfo().vreg_to_preg_map = this->color_map; + collectUsedCalleeSavedRegs(); + if (DEBUG) std::cerr << "===== Finished Graph Coloring Register Allocation =====\n\n"; } -/** - * @brief 处理调用约定,预先为函数参数和调用返回值分配物理寄存器。 - * 这个函数现在负责处理调用约定的两个方面: - * 1. 作为被调用者(callee),如何接收传入的参数。 - * 2. 作为调用者(caller),如何接收调用的其他函数的返回值。 - */ -void RISCv64RegAlloc::handleCallingConvention() { - Function* F = MFunc->getFunc(); - RISCv64ISel* isel = MFunc->getISel(); - - // --- 部分1:处理函数传入参数的预着色 --- - if (F) { - auto& args = F->getArguments(); - - // [修改] 为整数参数和浮点参数分别维护索引 - int int_arg_idx = 0; - int float_arg_idx = 0; +// 单次分配的核心流程 +bool RISCv64RegAlloc::doAllocation() { + initialize(); + precolorByCallingConvention(); + analyzeLiveness(); + build(); + makeWorklist(); - for (Argument* arg : args) { - // [修改] 根据参数类型决定使用哪个寄存器池和索引 - if (arg->getType()->isFloat()) { - // --- 处理浮点参数 --- - if (float_arg_idx >= 8) continue; // fa0-fa7 - - unsigned vreg = isel->getVReg(arg); - // 浮点参数使用 fa10-fa17 (在RISC-V ABI中对应F10-F17) + while (!simplifyWorklist.empty() || !worklistMoves.empty() || !freezeWorklist.empty() || !spillWorklist.empty()) { + if (DEEPDEBUG) dumpState("Loop Start"); + if (!simplifyWorklist.empty()) simplify(); + else if (!worklistMoves.empty()) coalesce(); + else if (!freezeWorklist.empty()) freeze(); + else if (!spillWorklist.empty()) selectSpill(); + } + + if (DEEPDEBUG) dumpState("Before AssignColors"); + assignColors(); + return spilledNodes.empty(); +} + +void RISCv64RegAlloc::precolorByCallingConvention() { + // 在处理前,先清空颜色相关的状态,确保重试时不会出错 + color_map.clear(); + coloredNodes.clear(); + + Function* F = MFunc->getFunc(); + if (!F) return; + + // --- 部分1:处理函数传入参数的预着色 --- + int int_arg_idx = 0; + int float_arg_idx = 0; + + for (Argument* arg : F->getArguments()) { + unsigned vreg = ISel->getVReg(arg); + + if (arg->getType()->isFloat()) { + if (float_arg_idx < 8) { // fa0-fa7 auto preg = static_cast(static_cast(PhysicalReg::F10) + float_arg_idx); color_map[vreg] = preg; float_arg_idx++; - - } else { - // --- 处理整数/指针参数 (原有逻辑) --- - if (int_arg_idx >= 8) continue; // a0-a7 - - unsigned vreg = isel->getVReg(arg); + } + } else { // 整数或指针 + if (int_arg_idx < 8) { // a0-a7 auto preg = static_cast(static_cast(PhysicalReg::A0) + int_arg_idx); color_map[vreg] = preg; int_arg_idx++; @@ -130,881 +122,1339 @@ void RISCv64RegAlloc::handleCallingConvention() { } } - // --- 部分2:为CALL指令的返回值预着色 --- - for (auto& mbb : MFunc->getBlocks()) { - for (auto& instr : mbb->getInstructions()) { - if (instr->getOpcode() == RVOpcodes::CALL) { - // 根据协议,如果CALL有返回值,其目标vreg是第一个操作数 - if (!instr->getOperands().empty() && - instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) - { - auto reg_op = static_cast(instr->getOperands().front().get()); - if (reg_op->isVirtual()) { - unsigned ret_vreg = reg_op->getVRegNum(); - - // [修改] 检查返回值的类型,预着色到 a0 或 fa0 - assert(MFunc->getISel()->getVRegValueMap().count(ret_vreg) && "Return vreg not found in value map!"); - Value* ret_val = MFunc->getISel()->getVRegValueMap().at(ret_vreg); + // // --- 部分2:为CALL指令的返回值预着色 --- + // for (auto& mbb : MFunc->getBlocks()) { + // for (auto& instr : mbb->getInstructions()) { + // if (instr->getOpcode() == RVOpcodes::CALL) { + // if (!instr->getOperands().empty() && + // instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) + // { + // auto reg_op = static_cast(instr->getOperands().front().get()); + // if (reg_op->isVirtual()) { + // unsigned ret_vreg = reg_op->getVRegNum(); + // assert(vreg_to_value_map.count(ret_vreg) && "Return vreg not found!"); + // Value* ret_val = vreg_to_value_map.at(ret_vreg); - if (ret_val->getType()->isFloat()) { - // 浮点返回值预着色到 fa0 (F10) - color_map[ret_vreg] = PhysicalReg::F10; - } else { - // 整数/指针返回值预着色到 a0 - color_map[ret_vreg] = PhysicalReg::A0; - } - } - } - } - } + // if (ret_val->getType()->isFloat()) { + // color_map[ret_vreg] = PhysicalReg::F10; // fa0 + // } else { + // color_map[ret_vreg] = PhysicalReg::A0; // a0 + // } + // } + // } + // } + // } + // } + + // 将所有预着色的vreg视为已着色节点 + for(const auto& pair : color_map) { + coloredNodes.insert(pair.first); + } + if (DEEPDEBUG) { + std::cerr << "Precolored registers: { "; + // 修改部分:将物理寄存器ID转换为其字符串名称 + for (unsigned v : precolored) std::cerr << regIdToString(v) << " "; + std::cerr << "}\nColored nodes: { "; + for (unsigned v : coloredNodes) std::cerr << "<%vreg" << v << ", " << regToString(color_map.at(v)) << "> "; + std::cerr << "}\n"; } } -/** - * @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。 - */ -void RISCv64RegAlloc::eliminateFrameIndices() { - StackFrameInfo& frame_info = MFunc->getFrameInfo(); - Function* F = MFunc->getFunc(); - RISCv64ISel* isel = MFunc->getISel(); - - // 在处理局部变量前,首先为栈参数计算偏移量。 - if (F) { - int arg_idx = 0; - for (Argument* arg : F->getArguments()) { - // 我们只关心第8个索引及之后的参数(即第9个参数开始) - if (arg_idx >= 8) { - // 计算偏移量:第一个栈参数(idx=8)在0(s0),第二个(idx=9)在8(s0),以此类推。 - int offset = (arg_idx - 8) * 8; - unsigned vreg = isel->getVReg(arg); +// 初始化/重置所有数据结构 +void RISCv64RegAlloc::initialize() { + initial.clear(); + simplifyWorklist.clear(); + freezeWorklist.clear(); + spillWorklist.clear(); + spilledNodes.clear(); + coalescedNodes.clear(); + coloredNodes.clear(); + selectStack.clear(); - // 将这个vreg和它的栈偏移存入map。 - // 我们可以复用alloca_offsets,因为它们都代表“vreg到栈偏移”的映射。 - frame_info.alloca_offsets[vreg] = offset; - } - arg_idx++; - } - } + coalescedMoves.clear(); + constrainedMoves.clear(); + frozenMoves.clear(); + worklistMoves.clear(); + activeMoves.clear(); - // [关键修改] 为局部变量分配空间时,起始点必须考虑为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())) { - Type* allocated_type = alloca->getType()->as()->getBaseType(); - int size = getTypeSizeInBytes(allocated_type); - - // RISC-V要求栈地址8字节对齐 - size = (size + 7) & ~7; - if (size == 0) size = 8; // 至少分配8字节 - - local_var_offset += size; - unsigned alloca_vreg = isel->getVReg(alloca); - // 局部变量使用相对于s0的负向偏移 - frame_info.alloca_offsets[alloca_vreg] = -local_var_offset; - } - } - } - - // [修复] 正确计算并设置locals_size - // 它只应该包含由AllocaInst分配的局部变量的总大小。 - frame_info.locals_size = local_var_offset - locals_start_offset; - - // 遍历所有机器指令,将伪指令展开为真实指令 - for (auto& mbb : MFunc->getBlocks()) { - std::vector> new_instructions; - for (auto& instr_ptr : mbb->getInstructions()) { - RVOpcodes opcode = instr_ptr->getOpcode(); - - // --- MODIFICATION START: 处理区分宽度的伪指令 --- - if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D) { - // 确定要生成的真实加载指令是 lw 还是 ld - RVOpcodes real_load_op = (opcode == RVOpcodes::FRAME_LOAD_W) ? RVOpcodes::LW : RVOpcodes::LD; - - auto& operands = instr_ptr->getOperands(); - unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); - int offset = frame_info.alloca_offsets.at(alloca_vreg); - auto addr_vreg = isel->getNewVReg(); - - // 展开为: addi addr_vreg, s0, offset - auto addi = std::make_unique(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: lw/ld dest_vreg, 0(addr_vreg) - auto load_instr = std::make_unique(real_load_op); - load_instr->addOperand(std::make_unique(dest_vreg)); - load_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(0))); - new_instructions.push_back(std::move(load_instr)); - - } else if (opcode == RVOpcodes::FRAME_LOAD_F) { - // 展开浮点加载伪指令 - RVOpcodes real_load_op = RVOpcodes::FLW; // 对应的真实指令是 flw - - auto& operands = instr_ptr->getOperands(); - unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); - int offset = frame_info.alloca_offsets.at(alloca_vreg); - auto addr_vreg = isel->getNewVReg(); - - // 展开为: addi addr_vreg, s0, offset - auto addi = std::make_unique(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: flw dest_vreg, 0(addr_vreg) - auto load_instr = std::make_unique(real_load_op); - load_instr->addOperand(std::make_unique(dest_vreg)); - load_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(0))); - new_instructions.push_back(std::move(load_instr)); - } else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D) { - // 确定要生成的真实存储指令是 sw 还是 sd - RVOpcodes real_store_op = (opcode == RVOpcodes::FRAME_STORE_W) ? RVOpcodes::SW : RVOpcodes::SD; - - auto& operands = instr_ptr->getOperands(); - unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); - int offset = frame_info.alloca_offsets.at(alloca_vreg); - auto addr_vreg = isel->getNewVReg(); - - // 展开为: addi addr_vreg, s0, offset - auto addi = std::make_unique(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: sw/sd src_vreg, 0(addr_vreg) - auto store_instr = std::make_unique(real_store_op); - store_instr->addOperand(std::make_unique(src_vreg)); - store_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(0))); - new_instructions.push_back(std::move(store_instr)); - - } else if (opcode == RVOpcodes::FRAME_STORE_F) { - // 展开浮点存储伪指令 - RVOpcodes real_store_op = RVOpcodes::FSW; // 对应的真实指令是 fsw - - auto& operands = instr_ptr->getOperands(); - unsigned src_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); - int offset = frame_info.alloca_offsets.at(alloca_vreg); - auto addr_vreg = isel->getNewVReg(); - - // 展开为: addi addr_vreg, s0, offset - auto addi = std::make_unique(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(addr_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - - // 展开为: fsw src_vreg, 0(addr_vreg) - auto store_instr = std::make_unique(real_store_op); - store_instr->addOperand(std::make_unique(src_vreg)); - store_instr->addOperand(std::make_unique( - std::make_unique(addr_vreg), - std::make_unique(0))); - new_instructions.push_back(std::move(store_instr)); - } else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { - auto& operands = instr_ptr->getOperands(); - unsigned dest_vreg = static_cast(operands[0].get())->getVRegNum(); - unsigned alloca_vreg = static_cast(operands[1].get())->getVRegNum(); - int offset = frame_info.alloca_offsets.at(alloca_vreg); - - // 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset` - auto addi = std::make_unique(RVOpcodes::ADDI); - addi->addOperand(std::make_unique(dest_vreg)); - addi->addOperand(std::make_unique(PhysicalReg::S0)); - addi->addOperand(std::make_unique(offset)); - new_instructions.push_back(std::move(addi)); - } else { - new_instructions.push_back(std::move(instr_ptr)); - } - // --- MODIFICATION END --- - } - mbb->getInstructions() = std::move(new_instructions); - } -} - -/** - * @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。 - * 这是活跃性分析的基础。 - * @param instr 要分析的机器指令。 - * @param use 存储 Use 寄存器(虚拟寄存器 ID)的集合。 - * @param def 存储 Def 寄存器(虚拟寄存器 ID)的集合。 - */ -void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) { - 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 || - opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE || - opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE || - opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU || - opcode == RVOpcodes::RET || opcode == RVOpcodes::J) { - first_reg_is_def = false; - } - - // JAL 和 JALR 指令定义 ra (x1) - if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) { - // 使用 ra 对应的特殊虚拟寄存器ID - def.insert(preg_to_vreg_id_map.at(PhysicalReg::RA)); - first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra,已经处理为 def - } - - // 2. CALL 指令的特殊处理 - if (opcode == RVOpcodes::CALL) { - // 根据 s1 分支 ISel 定义的协议来解析操作数列表 - bool first_reg_operand_is_def = true; - for (auto& op : instr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - if (reg_op->isVirtual()) { - // 协议:第一个寄存器操作数是返回值 (def) - if (first_reg_operand_is_def) { - def.insert(reg_op->getVRegNum()); - first_reg_operand_is_def = false; - } else { - // 后续所有寄存器操作数都是参数 (use) - use.insert(reg_op->getVRegNum()); - } - } else { // [修复] CALL指令也可能定义物理寄存器(如a0) - if (first_reg_operand_is_def) { - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - def.insert(it->second); - } - first_reg_operand_is_def = false; - } else { - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - } - } - } - return; // CALL 指令处理完毕 - } - - // 2.1 浮点比较指令添加特殊规则 - // 它们的源操作数是浮点寄存器,但目标操作数是整数寄存器 - if (opcode == RVOpcodes::FEQ_S || opcode == RVOpcodes::FLT_S || opcode == RVOpcodes::FLE_S) { - auto& operands = instr->getOperands(); - // Def: 第一个操作数 (整数vreg) - if (operands[0]->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(operands[0].get()); - if(reg_op->isVirtual()) def.insert(reg_op->getVRegNum()); - } - // Use: 第二、三个操作数 (浮点vreg) - if (operands[1]->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(operands[1].get()); - if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum()); - } - if (operands[2]->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(operands[2].get()); - if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum()); - } - return; // 处理完毕 - } - - // 3. 对其他所有指令的通用处理逻辑 [已重构和修复] - for (const auto& op : instr->getOperands()) { - if (op->getKind() == MachineOperand::KIND_REG) { - auto reg_op = static_cast(op.get()); - - if (first_reg_is_def) { - // --- 处理定义(Def) --- - if (reg_op->isVirtual()) { - def.insert(reg_op->getVRegNum()); - } else { // 物理寄存器也可以是 Def - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - def.insert(it->second); - } - } - first_reg_is_def = false; // **关键**:处理完第一个寄存器后,立即更新标志 - } else { - // --- 处理使用(Use) --- - if (reg_op->isVirtual()) { - use.insert(reg_op->getVRegNum()); - } else { // 物理寄存器也可以是 Use - auto it = preg_to_vreg_id_map.find(reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - } - } else if (op->getKind() == MachineOperand::KIND_MEM) { - // 内存操作数的处理逻辑看起来是正确的 - auto mem_op = static_cast(op.get()); - auto base_reg = mem_op->getBase(); - if (base_reg->isVirtual()) { - use.insert(base_reg->getVRegNum()); - } else { - PhysicalReg preg = base_reg->getPReg(); - auto it = preg_to_vreg_id_map.find(preg); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - - // 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use` - if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW) && - !instr->getOperands().empty() && - instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { - auto src_reg_op = static_cast(instr->getOperands().front().get()); - if (src_reg_op->isVirtual()) { - use.insert(src_reg_op->getVRegNum()); - } else { - auto it = preg_to_vreg_id_map.find(src_reg_op->getPReg()); - if (it != preg_to_vreg_id_map.end()) { - use.insert(it->second); - } - } - } - } - } -} - -/** - * @brief 计算一个类型在内存中占用的字节数。 - * @param type 需要计算大小的IR类型。 - * @return 该类型占用的字节数。 - */ -unsigned RISCv64RegAlloc::getTypeSizeInBytes(Type* type) { - if (!type) { - assert(false && "Cannot get size of a null type."); - return 0; - } - - switch (type->getKind()) { - // 对于SysY语言,基本类型int和float都占用4字节 - case Type::kInt: - case Type::kFloat: - return 4; - - // 指针类型在RISC-V 64位架构下占用8字节 - // 虽然SysY没有'int*'语法,但数组变量在IR层面本身就是指针类型 - case Type::kPointer: - return 8; - - // 数组类型的总大小 = 元素数量 * 单个元素的大小 - case Type::kArray: { - auto arrayType = type->as(); - // 递归调用以计算元素大小 - return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType()); - } - - // 其他类型,如Void, Label等不占用栈空间,或者不应该出现在这里 - default: - // 如果遇到未处理的类型,触发断言,方便调试 - assert(false && "Unsupported type for size calculation."); - return 0; - } + adjList.clear(); + degree.clear(); + moveList.clear(); + alias.clear(); + color_map.clear(); } +// 活跃性分析(此部分为标准数据流分析,与现有版本类似但更精细) void RISCv64RegAlloc::analyzeLiveness() { - // === 阶段 1: 预计算每个基本块的 use 和 def 集合 === - // 这样可以避免在主循环中重复计算 - std::map block_uses; - std::map block_defs; - for (auto& mbb_ptr : MFunc->getBlocks()) { - MachineBasicBlock* mbb = mbb_ptr.get(); - LiveSet uses, defs; - for (auto& instr_ptr : mbb->getInstructions()) { - LiveSet instr_use, instr_def; - getInstrUseDef(instr_ptr.get(), instr_use, instr_def); - // use[B] = use[B] U (instr_use - def[B]) + live_in_map.clear(); + live_out_map.clear(); + + std::map block_uses; + std::map block_defs; + + for (const auto& mbb_ptr : MFunc->getBlocks()) { + const MachineBasicBlock* mbb = mbb_ptr.get(); + VRegSet uses, defs; + for (const auto& instr_ptr : mbb->getInstructions()) { + VRegSet instr_use, instr_def; + getInstrUseDef_Liveness(instr_ptr.get(), instr_use, instr_def); for (unsigned u : instr_use) { - if (defs.find(u) == defs.end()) { - uses.insert(u); - } + if (defs.find(u) == defs.end()) uses.insert(u); } - // def[B] = def[B] U instr_def defs.insert(instr_def.begin(), instr_def.end()); } block_uses[mbb] = uses; block_defs[mbb] = defs; } - // === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 === - std::map block_live_in; - std::map block_live_out; bool changed = true; + std::map live_in, live_out; while (changed) { changed = false; - // 以逆后序遍历基本块,可以加速收敛,但简单的逆序对于大多数情况也有效 for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) { - auto& mbb = *it; - - // 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S] - LiveSet new_live_out; + const auto& mbb_ptr = *it; + const MachineBasicBlock* mbb = mbb_ptr.get(); + VRegSet new_out; for (auto succ : mbb->successors) { - new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end()); + new_out.insert(live_in[succ].begin(), live_in[succ].end()); } - - // 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B]) - LiveSet live_out_minus_def = new_live_out; - for (unsigned d : block_defs[mbb.get()]) { - live_out_minus_def.erase(d); - } - LiveSet new_live_in = block_uses[mbb.get()]; - new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end()); - - // 2.3 检查 live_in 和 live_out 是否变化,以判断是否达到不动点 - if (block_live_out[mbb.get()] != new_live_out) { + VRegSet new_in = block_uses[mbb]; + VRegSet out_minus_def = new_out; + for (unsigned d : block_defs[mbb]) out_minus_def.erase(d); + new_in.insert(out_minus_def.begin(), out_minus_def.end()); + if (live_out[mbb] != new_out || live_in[mbb] != new_in) { changed = true; - block_live_out[mbb.get()] = new_live_out; - } - if (block_live_in[mbb.get()] != new_live_in) { - changed = true; - block_live_in[mbb.get()] = new_live_in; + live_out[mbb] = new_out; + live_in[mbb] = new_in; } } } - // === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map === - // 此时块级别的活跃信息已经稳定,我们只需遍历一次即可 - for (auto& mbb_ptr : MFunc->getBlocks()) { - MachineBasicBlock* mbb = mbb_ptr.get(); - LiveSet live_out = block_live_out[mbb]; // 从已收敛的块级 live_out 开始 - + for (const auto& mbb_ptr : MFunc->getBlocks()) { + const MachineBasicBlock* mbb = mbb_ptr.get(); + VRegSet current_live = live_out[mbb]; for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) { - MachineInstr* instr = instr_it->get(); - live_out_map[instr] = live_out; + const MachineInstr* instr = instr_it->get(); + live_out_map[instr] = current_live; + VRegSet use, def; - LiveSet use, def; - getInstrUseDef(instr, use, def); - - LiveSet live_in = use; - LiveSet diff = live_out; - for (auto vreg : def) { - diff.erase(vreg); - } - live_in.insert(diff.begin(), diff.end()); - live_in_map[instr] = live_in; - - // 更新 live_out,为块内的上一条指令做准备 - live_out = live_in; + getInstrUseDef_Liveness(instr, use, def); + for(auto d : def) current_live.erase(d); + for(auto u : use) current_live.insert(u); + live_in_map[instr] = current_live; } } } -// 辅助函数,用于清晰地打印寄存器集合。可以放在 .cpp 文件的顶部。 -void RISCv64RegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os) { - os << " " << name << ": { "; - for (unsigned vreg : s) { - // 为了可读性,将物理寄存器对应的特殊ID进行转换 - if (vreg >= static_cast(sysy::PhysicalReg::PHYS_REG_START_ID)) { - os << "preg(" << (vreg - static_cast(sysy::PhysicalReg::PHYS_REG_START_ID)) << ") "; - } else { - os << "%vreg" << vreg << " "; - } - } - os << "}\n"; -} +void RISCv64RegAlloc::build() { + initial.clear(); + RISCv64AsmPrinter printer_inside_build(MFunc); + printer_inside_build.setStream(std::cerr); -void RISCv64RegAlloc::buildInterferenceGraph() { - std::set all_vregs; - // 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID - for (auto& mbb : MFunc->getBlocks()) { - for(auto& instr : mbb->getInstructions()) { - LiveSet use, def; - getInstrUseDef(instr.get(), use, def); - for(auto u : use) all_vregs.insert(u); - for(auto d : def) all_vregs.insert(d); - } - } - // 添加所有物理寄存器对应的特殊虚拟寄存器ID到all_vregs,作为干扰图节点 - for (auto preg : allocable_int_regs) { - all_vregs.insert(preg_to_vreg_id_map.at(preg)); - } + // 1. 收集所有待分配的(既非物理也非预着色)虚拟寄存器到 initial 集合 + for (const auto& mbb_ptr : MFunc->getBlocks()) { + for (const auto& instr_ptr : mbb_ptr->getInstructions()) { + const MachineInstr* instr = instr_ptr.get(); + VRegSet use, def; + getInstrUseDef_Liveness(instr, use, def); - // 初始化干扰图邻接表 - for (auto vreg : all_vregs) { interference_graph[vreg] = {}; } - - // 创建一个临时的AsmPrinter用于打印指令,方便调试 - RISCv64AsmPrinter temp_printer(MFunc); - temp_printer.setStream(std::cerr); - - for (auto& mbb : MFunc->getBlocks()) { - if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n"; - for (auto& instr_ptr : mbb->getInstructions()) { - MachineInstr* instr = instr_ptr.get(); - if (DEEPDEBUG) { - // 打印当前正在处理的指令 - std::cerr << " Instr: "; - temp_printer.printInstruction(instr, true); // 使用 true 来打印虚拟寄存器 - } - - LiveSet def, use; - getInstrUseDef(instr, use, def); - const LiveSet& live_out = live_out_map.at(instr); - - // [新增调试逻辑] 打印所有相关的寄存器集合 - if (DEEPDEBUG) { - printLiveSet(use, "Use ", std::cerr); - printLiveSet(def, "Def ", std::cerr); - printLiveSet(live_out, "Live_Out", std::cerr); // 这是我们最关心的信息 - } - - // 标准干扰图构建:def 与 live_out 中的其他变量干扰 - for (unsigned d : def) { - for (unsigned l : live_out) { - if (d != l) { - // [新增调试逻辑] 打印添加的干扰边及其原因 - if (DEEPDEBUG && interference_graph[d].find(l) == interference_graph[d].end()) { - std::cerr << " Edge (Def-LiveOut): %vreg" << d << " <-> %vreg" << l << "\n"; - } - interference_graph[d].insert(l); - interference_graph[l].insert(d); - } - } - } - - // 所有在某一点上同时活跃的寄存器(即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) { - for (unsigned u : use) { - if (d != u) { - // [新增调试逻辑] 打印添加的干扰边及其原因 - if (DEEPDEBUG && interference_graph[d].find(u) == interference_graph[d].end()) { - std::cerr << " Edge (Def-Use) : %vreg" << d << " <-> %vreg" << u << "\n"; - } - interference_graph[d].insert(u); - interference_graph[u].insert(d); - } - } - } - } - - // *** 处理 CALL 指令的隐式 def *** - if (instr->getOpcode() == RVOpcodes::CALL) { - // 你的原始CALL调试信息 - if (DEEPDEBUG) { - std::string live_out_str; - for (unsigned vreg : live_out) { - live_out_str += "%vreg" + std::to_string(vreg) + " "; - } - std::cerr << "[DEEPDEBUG] buildInterferenceGraph: CALL instruction found. Live out set is: {" - << live_out_str << "}" << std::endl; - } - // CALL 指令会定义(杀死)所有调用者保存的寄存器。 - // 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。 - - // 辅助函数,用于判断一个vreg是整数类型还是浮点类型 - auto is_fp_vreg = [&](unsigned vreg) { - if (vreg_to_value_map.count(vreg)) { - return vreg_to_value_map.at(vreg)->getType()->isFloat(); - } - // 对于ISel创建的、没有直接IR Value对应的临时vreg, - // 默认其为整数类型。这是一个合理的兜底策略。 - return false; + // 调试输出 use 和 def (保留您的调试逻辑) + if (DEEPERDEBUG) { + std::cerr << "Instr:"; + printer_inside_build.printInstruction(instr_ptr.get(), true); + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << " " << name << ": { "; + for(unsigned v : s) std::cerr << regIdToString(v) << " "; + std::cerr << "}\n"; }; + print_set(def, "Def "); + print_set(use, "Use "); + } - // --- 处理整数寄存器干扰 --- - const std::vector& caller_saved_int_regs = getCallerSavedIntRegs(); - for (PhysicalReg cs_reg : caller_saved_int_regs) { - // 确保物理寄存器在映射表中,我们已在构造函数中保证了这一点 - unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); - - for (unsigned live_vreg_out : live_out) { - // 只为整数vreg添加与整数preg的干扰 - if (!is_fp_vreg(live_vreg_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, Int): 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); - } - } - } - } - - // --- 处理浮点寄存器干扰 --- - const std::vector& caller_saved_fp_regs = getCallerSavedFpRegs(); - for (PhysicalReg cs_reg : caller_saved_fp_regs) { - unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); - - for (unsigned live_vreg_out : live_out) { - // 只为浮点vreg添加与浮点preg的干扰 - if (is_fp_vreg(live_vreg_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, FP): 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); - } - } + for (unsigned v : use) { + if (!coloredNodes.count(v) && !precolored.count(v)) { + initial.insert(v); + } else if ((DEEPDEBUG && initial.size() < DEBUGLENGTH) || DEEPERDEBUG) { + // 这里的调试信息可以更精确 + if (precolored.count(v)) { + std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; + } else { + std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register with " << regToString(color_map.at(v)) << "\n"; } } } - if (DEEPDEBUG) std::cerr << " ----------------\n"; - } - } -} - -void RISCv64RegAlloc::colorGraph() { - std::vector sorted_vregs; - for (auto const& [vreg, neighbors] : interference_graph) { - // 只为未预着色的虚拟寄存器排序和着色 - if (color_map.find(vreg) == color_map.end() && vreg < static_cast(PhysicalReg::PHYS_REG_START_ID)) { - sorted_vregs.push_back(vreg); - } - } - - // 排序 - std::sort(sorted_vregs.begin(), sorted_vregs.end(), [&](unsigned a, unsigned b) { - return interference_graph[a].size() > interference_graph[b].size(); - }); - - // [调试] 辅助函数,用于判断一个vreg是整数还是浮点类型,并打印详细诊断信息 - auto is_fp_vreg = [&](unsigned vreg) { - if (DEEPDEBUG) { - std::cout << " [Debug is_fp_vreg] Checking vreg" << vreg << ": "; - } - if (vreg_to_value_map.count(vreg)) { - Value* val = vreg_to_value_map.at(vreg); - bool is_float = val->getType()->isFloat(); - if (DEEPDEBUG) { - std::cout << "Found in map. Value is '" << val->getName() - << "', Type is " << (is_float ? "FLOAT" : "INT") - << ". Returning " << (is_float ? "true" : "false") << ".\n"; - } - return is_float; - } - - if (DEEPDEBUG) { - std::cout << "NOT found in vreg_to_value_map. Defaulting to INT. Returning false.\n"; - } - // 对于ISel创建的、没有直接IR Value对应的临时vreg,默认其为整数类型。 - return false; - }; - - // 着色 - for (unsigned vreg : sorted_vregs) { - std::set used_colors; - for (unsigned neighbor_id : interference_graph.at(vreg)) { - // 收集邻居颜色的逻辑保持不变 - if (color_map.count(neighbor_id)) { - used_colors.insert(color_map.at(neighbor_id)); - } - else if (neighbor_id >= static_cast(PhysicalReg::PHYS_REG_START_ID)) { - PhysicalReg neighbor_preg = static_cast(neighbor_id - static_cast(PhysicalReg::PHYS_REG_START_ID)); - used_colors.insert(neighbor_preg); - } - } - - bool is_float = is_fp_vreg(vreg); - const auto& allocable_regs = is_float ? allocable_fp_regs : allocable_int_regs; - - // [调试] 打印着色决策过程 - if (DEBUG) { - std::cout << "[DEBUG] Coloring %vreg" << vreg - << ": Type is " << (is_float ? "FLOAT" : "INT") - << ", choosing from " << (is_float ? "Float" : "Integer") << " pool.\n"; - } - - bool colored = false; - for (PhysicalReg preg : allocable_regs) { - if (used_colors.find(preg) == used_colors.end()) { - color_map[vreg] = preg; - colored = true; - if (DEBUG) { - RISCv64AsmPrinter p(MFunc); // For regToString - std::cout << " -> Assigned to physical register: " << p.regToString(preg) << "\n"; + for (unsigned v : def) { + if (!coloredNodes.count(v) && !precolored.count(v)) { + initial.insert(v); + } else if ((DEEPDEBUG && initial.size() < DEBUGLENGTH) || DEEPERDEBUG) { + if (precolored.count(v)) { + std::cerr << "Skipping " << regIdToString(v) << " because it is a physical register.\n"; + } else { + std::cerr << "Skipping " << regIdToString(v) << " because it is a pre-colored virtual register with " << regToString(color_map.at(v)) << ".\n"; + } } - break; } } - if (!colored) { - spilled_vregs.insert(vreg); - if (DEBUG) { - std::cout << " -> FAILED to color. Spilling.\n"; + } + + if (DEEPDEBUG) { + if (initial.size() > DEBUGLENGTH && !DEEPERDEBUG) { + std::cerr << "Initial set too large, showing first " << DEBUGLENGTH << " elements:\n"; + } + std::cerr << "Initial set (" << initial.size() << "): { "; + unsigned count = 0; + for (unsigned v : initial) { + if (count++ >= DEBUGLENGTH && !DEEPERDEBUG) break; // 限制输出数量 + std::cerr << regIdToString(v) << " "; + } + if (count < initial.size()) { + std::cerr << "... (total " << initial.size() << " elements)\n"; + } else { + std::cerr << "}\n"; + } + } + + // 2. 为所有参与图构建的虚拟寄存器(initial + coloredNodes)初始化数据结构 + VRegSet all_participating_vregs = initial; + all_participating_vregs.insert(coloredNodes.begin(), coloredNodes.end()); + + for (unsigned vreg : all_participating_vregs) { + // 物理寄存器ID不应作为key,此检查是安全的双重保障 + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + if (vreg >= offset) { + continue; + } + adjList[vreg] = {}; + degree[vreg] = 0; + } + + // 3. 构建冲突图 + for (const auto& mbb_ptr : MFunc->getBlocks()) { + if (DEEPDEBUG) std::cerr << "\n--- Building Graph for Basic Block: " << mbb_ptr->getName() << " ---\n"; + for (const auto& instr_ptr : mbb_ptr->getInstructions()) { + const MachineInstr* instr = instr_ptr.get(); + VRegSet use, def; + getInstrUseDef_Liveness(instr, use, def); + const VRegSet& live_out = live_out_map.at(instr); + + // 保留您的指令级调试输出 + if (DEEPERDEBUG) { + RISCv64AsmPrinter temp_printer(MFunc); + temp_printer.setStream(std::cerr); + std::cerr << "Instr: "; + temp_printer.printInstruction(const_cast(instr), true); + + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << " " << name << ": { "; + for(unsigned v : s) std::cerr << regIdToString(v) << " "; + std::cerr << "}\n"; + }; + print_set(def, "Def "); + print_set(use, "Use "); + print_set(live_out, "Live_Out"); + std::cerr << " ----------------\n"; + } + + bool is_move = instr->getOpcode() == RVOpcodes::MV; + + // 保留您处理 moveList 的逻辑 + if (is_move) { + worklistMoves.insert(instr); + VRegSet move_vregs; + for(const auto& op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op.get()); + if(reg_op->isVirtual()) move_vregs.insert(reg_op->getVRegNum()); + } + } + for (unsigned vreg : move_vregs) { + // 使用 operator[] 是安全的,如果vreg不存在会默认构造 + moveList[vreg].insert(instr); + } + } + + VRegSet live = live_out; + if (is_move) { + for (unsigned u_op : use) { + live.erase(u_op); + } + } + + // --- 规则 1 & 2: Def 与 Live/Use 变量干扰 --- + for (unsigned d : def) { + // 新逻辑:对于指令定义的所有寄存器d(无论是虚拟寄存器还是像call指令那样 + // 隐式定义的物理寄存器),它都与该指令之后的所有活跃寄存器l冲突。 + // addEdge函数内部会正确处理 vreg-vreg 和 vreg-preg 的情况, + // 并忽略 preg-preg 的情况。 + for (unsigned l : live) { + addEdge(d, l); + } + + // 对于非传送指令, Def还和Use冲突。 + // 这个逻辑主要用于确保在同一条指令内,例如 sub t0, t1, t0, + // 作为def的t0和作为use的t0被视为冲突。 + if (!is_move) { + for (unsigned u_op : use) { + addEdge(d, u_op); + } + } + } + + // --- 规则 3: Live_Out 集合内部的【虚拟寄存器】形成完全图 --- + // 使用更高效的遍历,避免重复调用 addEdge(A,B) 和 addEdge(B,A) + for (auto it1 = live_out.begin(); it1 != live_out.end(); ++it1) { + unsigned l1 = *it1; + // 只为虚拟寄存器 l1 添加边 + if (precolored.count(l1)) continue; + + for (auto it2 = std::next(it1); it2 != live_out.end(); ++it2) { + unsigned l2 = *it2; + addEdge(l1, l2); + } } } } } -void RISCv64RegAlloc::rewriteFunction() { +// 将节点放入初始工作列表 +void RISCv64RegAlloc::makeWorklist() { + for (unsigned n : initial) { + int K = isFPVReg(n) ? K_fp : K_int; + if (degree.count(n) == 0) { + std::cerr << "Error: degree not initialized for %vreg" << n << "\n"; + continue; + } + if ((DEEPDEBUG && initial.size() < DEBUGLENGTH) || DEEPERDEBUG) { + std::cerr << "Assigning %vreg" << n << " (degree=" << degree.at(n) + << ", moveRelated=" << moveRelated(n) << ")\n"; + } + if (degree.at(n) >= K) { + spillWorklist.insert(n); + } else if (moveRelated(n)) { + freezeWorklist.insert(n); + } else { + simplifyWorklist.insert(n); + } + } + if (DEEPDEBUG || DEEPERDEBUG) std::cerr << "--------------------------------\n"; + initial.clear(); +} + +// 简化阶段 +void RISCv64RegAlloc::simplify() { + unsigned n = *simplifyWorklist.begin(); + simplifyWorklist.erase(simplifyWorklist.begin()); + if (DEEPERDEBUG) std::cerr << "[Simplify] Popped %vreg" << n << ", pushing to stack.\n"; + selectStack.push_back(n); + for (unsigned m : adjacent(n)) { + decrementDegree(m); + } +} + +// 合并阶段 +void RISCv64RegAlloc::coalesce() { + const MachineInstr* move = *worklistMoves.begin(); + worklistMoves.erase(worklistMoves.begin()); + VRegSet use, def; + getInstrUseDef_Liveness(move, use, def); + unsigned x = getAlias(*def.begin()); + unsigned y = getAlias(*use.begin()); + unsigned u, v; + if (precolored.count(y)) { u = y; v = x; } else { u = x; v = y; } + + if (DEEPERDEBUG) std::cerr << "[Coalesce] Processing move between " << regIdToString(x) + << " and " << regIdToString(y) << " (aliases " << regIdToString(u) + << ", " << regIdToString(v) << ").\n"; + + if (u == v) { + if (DEEPERDEBUG) std::cerr << " -> Trivial coalesce (u == v).\n"; + coalescedMoves.insert(move); + addWorklist(u); + return; // 处理完毕,提前返回 + } + + if (isFPVReg(u) != isFPVReg(v)) { + if (DEEPERDEBUG) std::cerr << " -> Constrained (type mismatch: " << regIdToString(u) << " is " + << (isFPVReg(u) ? "float" : "int") << ", " << regIdToString(v) << " is " + << (isFPVReg(v) ? "float" : "int") << ").\n"; + constrainedMoves.insert(move); + addWorklist(u); + addWorklist(v); + return; // 立即返回,不再进行后续检查 + } + + bool pre_interfere = adjList.at(v).count(u); + + if (pre_interfere) { + if (DEEPERDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n"; + constrainedMoves.insert(move); + addWorklist(u); + addWorklist(v); + return; + } + + bool is_u_precolored = precolored.count(u); + bool can_coalesce = false; + + if (is_u_precolored) { + // --- 场景1:u是物理寄存器,使用 George 启发式 --- + if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is precolored)...\n"; + + // 步骤 1: 独立调用 adjacent(v) 获取邻居集合 + VRegSet neighbors_of_v = adjacent(v); + if (DEEPERDEBUG) { + std::cerr << " - Neighbors of " << regIdToString(v) << " to check are (" << neighbors_of_v.size() << "): { "; + for (unsigned id : neighbors_of_v) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + } + + // 步骤 2: 使用显式的 for 循环来代替 std::all_of + bool george_ok = true; // 默认假设成功,任何一个邻居失败都会将此设为 false + for (unsigned t : neighbors_of_v) { + if (DEEPERDEBUG) { + std::cerr << " - Checking neighbor " << regIdToString(t) << ":\n"; + } + + // 步骤 3: 独立调用启发式函数 + bool heuristic_result = georgeHeuristic(t, u); + + if (DEEPERDEBUG) { + std::cerr << " - georgeHeuristic(" << regIdToString(t) << ", " << regIdToString(u) << ") -> " << (heuristic_result ? "OK" : "FAIL") << "\n"; + } + + if (!heuristic_result) { + george_ok = false; // 只要有一个邻居不满足条件,整个检查就失败 + break; // 并且可以立即停止检查其他邻居 + } + } + + if (DEEPERDEBUG) { + std::cerr << " -> George Heuristic final result: " << (george_ok ? "OK" : "FAIL") << "\n"; + } + + if (george_ok) { + can_coalesce = true; + } + + } else { + // --- 场景2:u和v都是虚拟寄存器,使用 Briggs 启发式 --- + if (DEEPERDEBUG) std::cerr << " -> Trying Briggs Heuristic (u and v are virtual)...\n"; + + bool briggs_ok = briggsHeuristic(u, v); + if (DEEPERDEBUG) std::cerr << " - briggsHeuristic(" << regIdToString(u) << ", " << regIdToString(v) << ") -> " << (briggs_ok ? "OK" : "FAIL") << "\n"; + + if (briggs_ok) { + can_coalesce = true; + } + } + + // --- 根据启发式结果进行最终决策 --- + + if (can_coalesce) { + if (DEEPERDEBUG) std::cerr << " -> Heuristic OK. Combining " << regIdToString(v) << " into " << regIdToString(u) << ".\n"; + coalescedMoves.insert(move); + combine(u, v); + addWorklist(u); + } else { + if (DEEPERDEBUG) std::cerr << " -> Heuristic failed. Adding to active moves.\n"; + activeMoves.insert(move); + } +} + +// 冻结阶段 +void RISCv64RegAlloc::freeze() { + unsigned u = *freezeWorklist.begin(); + freezeWorklist.erase(freezeWorklist.begin()); + if (DEEPERDEBUG) std::cerr << "[Freeze] Freezing %vreg" << u << " and moving to simplify list.\n"; + simplifyWorklist.insert(u); + freezeMoves(u); +} + +// 选择溢出节点 +void RISCv64RegAlloc::selectSpill() { + auto it = std::max_element(spillWorklist.begin(), spillWorklist.end(), + [&](unsigned a, unsigned b){ return degree.at(a) < degree.at(b); }); + unsigned m = *it; + spillWorklist.erase(it); + if (DEEPERDEBUG) std::cerr << "[Spill] Selecting %vreg" << m << " to spill.\n"; + simplifyWorklist.insert(m); + freezeMoves(m); +} + +void RISCv64RegAlloc::assignColors() { + if (DEEPERDEBUG) std::cerr << "[AssignColors] Starting...\n"; + // 步骤 1: 为 selectStack 中的节点分配颜色 (此部分逻辑不变) + while (!selectStack.empty()) { + unsigned n = selectStack.back(); + selectStack.pop_back(); + bool is_fp = isFPVReg(n); + const auto& available_regs = is_fp ? allocable_fp_regs : allocable_int_regs; + std::set ok_colors(available_regs.begin(), available_regs.end()); + + 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)); + } + } + } + + if (ok_colors.empty()) { + spilledNodes.insert(n); + if (DEEPERDEBUG) std::cerr << " -> WARNING: No color for %vreg" << n << " from selectStack. Spilling.\n"; + } else { + PhysicalReg c = *ok_colors.begin(); + coloredNodes.insert(n); + color_map[n] = c; + if (DEEPERDEBUG) std::cerr << " -> Colored %vreg" << n << " with " << regToString(c) << ".\n"; + } + } + + // 步骤 2: 处理 coalescedNodes + for (unsigned n : coalescedNodes) { + unsigned root_alias = getAlias(n); + + // --- 处理所有三种可能性 --- + + // 情况 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 (DEEPERDEBUG) 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 (DEEPERDEBUG) std::cerr << " -> Coalesced %vreg" << n << " gets color from VIRTUAL alias " << regIdToString(root_alias) << ".\n"; + } + // 情况 3: 别名是被溢出的虚拟寄存器 + else { + spilledNodes.insert(n); + if (DEEPERDEBUG) std::cerr << " -> Alias " << regIdToString(root_alias) << " of %vreg" << n << " was SPILLED. Spilling %vreg" << n << " as well.\n"; + } + } +} + +// 重写程序,插入溢出代码 +void RISCv64RegAlloc::rewriteProgram() { StackFrameInfo& frame_info = MFunc->getFrameInfo(); - int current_offset = frame_info.locals_size; + // 使用 EFI Pass 确定的 locals_end_offset 作为溢出分配的基准。 + // locals_end_offset 本身是负数,代表局部变量区域的下边界地址。 + int spill_current_offset = frame_info.locals_end_offset; - // --- 动态计算溢出槽大小 --- - // 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。 - for (unsigned vreg : spilled_vregs) { - // 从反向映射中查找 vreg 对应的 IR Value - assert(vreg_to_value_map.count(vreg) && "Spilled vreg not found in map!"); - Value* val = vreg_to_value_map.at(vreg); - - // 使用辅助函数获取类型大小 - int size = getTypeSizeInBytes(val->getType()); - - // 保持栈8字节对齐 - current_offset += size; - current_offset = (current_offset + 7) & ~7; + // 保存溢出区域的起始点,用于最后计算总的 spill_size + const int spill_start_offset = frame_info.locals_end_offset; - frame_info.spill_offsets[vreg] = -current_offset; + for (unsigned vreg : spilledNodes) { + if (frame_info.spill_offsets.count(vreg)) continue; + + int size = 4; + if (isFPVReg(vreg)) { + size = 4; // float + } else if (vreg_type_map.count(vreg) && vreg_type_map.at(vreg)->isPointer()) { + size = 8; // pointer + } + + // 在当前偏移基础上继续向下(地址变得更负)分配空间 + spill_current_offset -= size; + + // 对齐新的、更小的地址,RISC-V 要求8字节对齐 + spill_current_offset = spill_current_offset & ~7; + + // 将计算出的、不会冲突的正确偏移量存入 spill_offsets + frame_info.spill_offsets[vreg] = spill_current_offset; } - frame_info.spill_size = current_offset - frame_info.locals_size; - // 定义专用的溢出寄存器 - const PhysicalReg INT_SPILL_REG = PhysicalReg::T6; // t6 - const PhysicalReg FP_SPILL_REG = PhysicalReg::F7; // ft7 + // 更新总的溢出区域大小。 + // spill_size = -(结束偏移 - 开始偏移) + frame_info.spill_size = -(spill_current_offset - spill_start_offset); + // 2. 遍历所有指令,重写代码 for (auto& mbb : MFunc->getBlocks()) { std::vector> new_instructions; + for (auto& instr_ptr : mbb->getInstructions()) { - LiveSet use, def; - getInstrUseDef(instr_ptr.get(), use, def); + std::map use_remap; + std::map def_remap; + + VRegSet use, def; + getInstrUseDef_Liveness(instr_ptr.get(), use, def); + + // 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; - // --- 为溢出的 'use' 操作数插入正确的加载指令 --- - for (unsigned vreg : use) { - if (spilled_vregs.count(vreg)) { - // 同样地,根据 vreg 的类型决定使用 lw 还是 ld - assert(vreg_to_value_map.count(vreg)); - Value* val = vreg_to_value_map.at(vreg); - - // 根据vreg类型决定加载指令(lw/ld/flw)和目标物理寄存器(t6/ft7) RVOpcodes load_op; - PhysicalReg target_preg; - if (val->getType()->isFloat()) { - load_op = RVOpcodes::FLW; - target_preg = FP_SPILL_REG; - } else if (val->getType()->isPointer()) { - load_op = RVOpcodes::LD; - target_preg = INT_SPILL_REG; - } else { - load_op = RVOpcodes::LW; - target_preg = INT_SPILL_REG; - } + if (isFPVReg(old_vreg)) load_op = RVOpcodes::FLW; + else if (type->isPointer()) load_op = RVOpcodes::LD; + else load_op = RVOpcodes::LW; - int offset = frame_info.spill_offsets.at(vreg); auto load = std::make_unique(load_op); - load->addOperand(std::make_unique(target_preg)); // 加载到专用溢出寄存器 + load->addOperand(std::make_unique(new_temp_vreg)); load->addOperand(std::make_unique( std::make_unique(PhysicalReg::S0), - std::make_unique(offset) + std::make_unique(frame_info.spill_offsets.at(old_vreg)) )); new_instructions.push_back(std::move(load)); } } - new_instructions.push_back(std::move(instr_ptr)); - - // --- 为溢出的 'def' 操作数插入正确的存储指令 --- - for (unsigned vreg : def) { - if (spilled_vregs.count(vreg)) { - assert(vreg_to_value_map.count(vreg)); - Value* val = vreg_to_value_map.at(vreg); - - // 根据vreg类型决定存储指令(sw/sd/fsw)和源物理寄存器(t6/ft7) - RVOpcodes store_op; - PhysicalReg src_preg; - if (val->getType()->isFloat()) { - store_op = RVOpcodes::FSW; - src_preg = FP_SPILL_REG; - } else if (val->getType()->isPointer()) { - store_op = RVOpcodes::SD; - src_preg = INT_SPILL_REG; - } else { - store_op = RVOpcodes::SW; - src_preg = INT_SPILL_REG; - } - - int offset = frame_info.spill_offsets.at(vreg); - auto store = std::make_unique(store_op); - store->addOperand(std::make_unique(src_preg)); // 从专用溢出寄存器存储 - store->addOperand(std::make_unique( - std::make_unique(PhysicalReg::S0), - std::make_unique(offset) - )); - new_instructions.push_back(std::move(store)); + // 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; } } + + // 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()) { + unsigned old_vreg = reg_op->getVRegNum(); + 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); } - // 最后的虚拟寄存器到物理寄存器的替换过程保持不变 + // 清空溢出节点集合,为下一次迭代分配做准备 + spilledNodes.clear(); +} + +/** + * @brief 获取一条指令完整的【虚拟】使用/定义寄存器集合 + * 这个函数将服务于图的构建(收集initial节点等)。 + */ +void RISCv64RegAlloc::getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def) { + auto opcode = instr->getOpcode(); + const auto& operands = instr->getOperands(); + + static const std::map, std::vector>> op_info = { + {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::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::RET, {{}, {}}}, {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}}} + }; + + auto get_vreg_id_if_virtual = [&](const MachineOperand* op, VRegSet& 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); + } +} + +/** + * @brief 获取一条指令完整的、包含物理寄存器的Use/Def集合 + * 这个函数专门服务于活跃性分析,现已补全所有指令(包括伪指令)的逻辑。 + */ +void RISCv64RegAlloc::getInstrUseDef_Liveness(const MachineInstr* instr, VRegSet& use, VRegSet& def) { + auto opcode = instr->getOpcode(); + const auto& operands = instr->getOperands(); + + // 映射表:指令操作码 -> {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::ORI, {{0}, {1}}}, {RVOpcodes::ANDI, {{0}, {1}}}, + {RVOpcodes::SLTI, {{0}, {1}}}, {RVOpcodes::SLTIU, {{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::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::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(虚拟或物理) + 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) { + auto reg_op = static_cast(op); + return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast(reg_op->getPReg())); + } else if (op->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op); + auto reg_op = mem_op->getBase(); + return reg_op->isVirtual() ? reg_op->getVRegNum() : (offset + static_cast(reg_op->getPReg())); + } + return (unsigned)-1; + }; + + // --- 主要处理逻辑 --- + if (op_info.count(opcode)) { + const auto& info = op_info.at(opcode); + for (int idx : info.first) if (idx < operands.size()) { + unsigned reg_id = get_any_reg_id(operands[idx].get()); + if (reg_id != (unsigned)-1) def.insert(reg_id); + } + for (int idx : info.second) if (idx < operands.size()) { + unsigned reg_id = get_any_reg_id(operands[idx].get()); + if (reg_id != (unsigned)-1) use.insert(reg_id); + } + // 对于所有内存操作,基址寄存器都必须是 use + for (const auto& op : operands) { + if (op->getKind() == MachineOperand::KIND_MEM) { + unsigned reg_id = get_any_reg_id(op.get()); + if (reg_id != (unsigned)-1) use.insert(reg_id); + } + } + } + // --- 特殊指令处理逻辑 --- + else if (opcode == RVOpcodes::CALL) { + // 返回值是Def + if (!operands.empty() && operands[0]->getKind() == MachineOperand::KIND_REG) { + def.insert(get_any_reg_id(operands[0].get())); + } + // 函数名后的所有寄存器参数都是Use + for (size_t i = 1; i < operands.size(); ++i) { + if (operands[i]->getKind() == MachineOperand::KIND_REG) { + use.insert(get_any_reg_id(operands[i].get())); + } + } + // 所有调用者保存寄存器(caller-saved)被隐式定义(因为它们的值被破坏了) + for (auto preg : getCallerSavedIntRegs()) def.insert(offset + static_cast(preg)); + for (auto preg : getCallerSavedFpRegs()) def.insert(offset + static_cast(preg)); + // 返回地址寄存器RA也被隐式定义 + def.insert(offset + static_cast(PhysicalReg::RA)); + } + else if (opcode == RVOpcodes::JALR) { + // JALR rd, rs1, imm. Def: rd, Use: rs1. + // 同时也隐式定义了ra(x1),但通常rd就是ra。为精确,我们只处理显式操作数。 + def.insert(get_any_reg_id(operands[0].get())); + use.insert(get_any_reg_id(operands[1].get())); + } + else if (opcode == RVOpcodes::RET) { + // 遵循调用约定,a0(整数/指针)和fa0(浮点)被隐式使用 + use.insert(offset + static_cast(PhysicalReg::A0)); + use.insert(offset + static_cast(PhysicalReg::F10)); // F10 is fa0 + } + // 添加对 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) { + if (u == v) return; + + // 检查两个节点是否都是虚拟寄存器 + if (!precolored.count(u) && !precolored.count(v) && !coloredNodes.count(u) && !coloredNodes.count(v)) { + // 只有当两个都是虚拟寄存器时,才为它们双方添加边和更新度数 + // 使用 operator[] 是安全的,如果键不存在,它会默认构造一个空的set + if (adjList[u].find(v) == adjList[u].end()) { + adjList[u].insert(v); + adjList[v].insert(u); + degree[u]++; + degree[v]++; + } + } + // 检查是否为 "虚拟-物理" 对 + else if (!precolored.count(u) && precolored.count(v) && !coloredNodes.count(u)) { + // u是虚拟寄存器,v是物理寄存器,只更新u的邻接表和度数 + if (adjList[u].find(v) == adjList[u].end()) { + adjList[u].insert(v); + degree[u]++; + } + } + // 检查是否为 "物理-虚拟" 对 + else if (precolored.count(u) && !precolored.count(v) && !coloredNodes.count(v)) { + // u是物理寄存器,v是虚拟寄存器,只更新v的邻接表和度数 + if (adjList[v].find(u) == adjList[v].end()) { + adjList[v].insert(u); + degree[v]++; + } + } + // 如果两个都是物理寄存器,则什么都不做,直接返回。 +} + +RISCv64RegAlloc::VRegSet RISCv64RegAlloc::adjacent(unsigned n) { + // 仅在 DEEPDEBUG 模式下启用详细日志 + if (DEEPERDEBUG) { + // 使用 regIdToString 打印节点 n,无论是物理还是虚拟 + std::cerr << "\n[adjacent] >>>>> Executing for node " << regIdToString(n) << " <<<<<\n"; + } + + // 1. 如果节点 n 是物理寄存器,它没有邻接表,直接返回空集 + if (precolored.count(n)) { + if (DEEPERDEBUG) { + std::cerr << "[adjacent] Node " << regIdToString(n) << " is precolored. Returning {}.\n"; + } + return {}; + } + + // 安全检查:确保 n 在 adjList 中存在,防止 map::at 崩溃 + if (adjList.count(n) == 0) { + if (DEEPERDEBUG) { + std::cerr << "[adjacent] WARNING: Node " << regIdToString(n) << " not found in adjList. Returning {}.\n"; + } + return {}; + } + + // 2. 获取 n 在冲突图中的所有邻居 + VRegSet result = adjList.at(n); + + if (DEEPERDEBUG) { + // 定义一个局部的 lambda 方便打印集合 + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << "[adjacent] " << name << " (" << s.size() << "): { "; + for (unsigned id : s) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + }; + print_set(result, "Initial full neighbors"); + } + + // 3. 过滤掉那些已经在 selectStack 或 coalescedNodes 中的邻居 + // 这些节点被认为是“已移除”的,不参与当前的启发式判断 + + // 3a. 从 selectStack 中移除 + VRegSet removed_from_stack; // 仅用于调试打印 + for (auto it = selectStack.rbegin(); it != selectStack.rend(); ++it) { + if (result.count(*it)) { + if (DEEPERDEBUG) removed_from_stack.insert(*it); + result.erase(*it); + } + } + if (DEEPERDEBUG && !removed_from_stack.empty()) { + std::cerr << "[adjacent] - Removed from selectStack: { "; + for(unsigned id : removed_from_stack) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + } + + // 3b. 从 coalescedNodes 中移除 + VRegSet removed_from_coalesced; // 仅用于调试打印 + for (unsigned cn : coalescedNodes) { + if (result.count(cn)) { + if (DEEPERDEBUG) removed_from_coalesced.insert(cn); + result.erase(cn); + } + } + if (DEEPERDEBUG && !removed_from_coalesced.empty()) { + std::cerr << "[adjacent] - Removed from coalescedNodes: { "; + for(unsigned id : removed_from_coalesced) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + } + + // 4. 返回最终的、过滤后的“有效”邻居集合 + if (DEEPERDEBUG) { + std::cerr << "[adjacent] >>>>> Returning final adjacent set (" << result.size() << "): { "; + for (unsigned id : result) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n\n"; + } + + return result; +} + +RISCv64RegAlloc::VRegMoveSet RISCv64RegAlloc::nodeMoves(unsigned n) { + if (precolored.count(n) || !moveList.count(n)) { + return {}; + } + + VRegMoveSet result; + const VRegMoveSet& moves = moveList.at(n); + for (const auto& move : moves) { + if (activeMoves.count(move) || worklistMoves.count(move)) { + result.insert(move); + } + } + return result; +} + +bool RISCv64RegAlloc::moveRelated(unsigned n) { + return !nodeMoves(n).empty(); +} + +void RISCv64RegAlloc::decrementDegree(unsigned m) { + if (precolored.count(m)) { + return; + } + + int K = isFPVReg(m) ? K_fp : K_int; + int d = degree.at(m); + degree.at(m)--; + if (d == K) { + VRegSet nodes_to_enable = adjacent(m); + nodes_to_enable.insert(m); + enableMoves(nodes_to_enable); + spillWorklist.erase(m); + if (moveRelated(m)) { + if (DEEPERDEBUG) { + std::cerr << "[decrementDegree] Node " << regIdToString(m) << " has degree " << d << ", now decremented to " << degree.at(m) << ". Added to freezeWorklist.\n"; + } + freezeWorklist.insert(m); + } else { + if (DEEPERDEBUG) { + std::cerr << "[decrementDegree] Node " << regIdToString(m) << " has degree " << d << ", now decremented to " << degree.at(m) << ". Added to simplifyWorklist.\n"; + } + simplifyWorklist.insert(m); + } + } +} + +void RISCv64RegAlloc::enableMoves(const VRegSet& nodes) { + for (unsigned n : nodes) { + VRegMoveSet moves = nodeMoves(n); + for (const auto& move : moves) { + if (activeMoves.count(move)) { + activeMoves.erase(move); + worklistMoves.insert(move); + } + } + } +} + +unsigned RISCv64RegAlloc::getAlias(unsigned n) { + if (precolored.count(n)) { + return n; + } + if (alias.count(n)) { + // 路径压缩 + alias.at(n) = getAlias(alias.at(n)); + return alias.at(n); + } + return n; +} + +void RISCv64RegAlloc::addWorklist(unsigned u) { + if (precolored.count(u)) return; + + int K = isFPVReg(u) ? K_fp : K_int; + if (!moveRelated(u) && degree.at(u) < K) { + freezeWorklist.erase(u); + simplifyWorklist.insert(u); + if (DEEPERDEBUG) { + std::cerr << "[addWorklist] Node " << regIdToString(u) << " added to simplifyWorklist (degree: " << degree.at(u) << ", K: " << K << ").\n"; + } + } +} + +// Briggs启发式 +bool RISCv64RegAlloc::briggsHeuristic(unsigned u, unsigned v) { + if (DEEPERDEBUG) { + std::cerr << "\n[Briggs] >>>>> Checking coalesce between " << regIdToString(u) << " and " << regIdToString(v) << " <<<<<\n"; + } + + // 步骤 1: 分别获取 u 和 v 的邻居 + VRegSet u_adj = adjacent(u); + VRegSet v_adj = adjacent(v); + + // 步骤 2: 合并两个邻居集合 + VRegSet all_adj = u_adj; + all_adj.insert(v_adj.begin(), v_adj.end()); + + if (DEEPERDEBUG) { + auto print_set = [this](const VRegSet& s, const std::string& name) { + std::cerr << "[Briggs] " << name << " (" << s.size() << "): { "; + for (unsigned id : s) std::cerr << regIdToString(id) << " "; + std::cerr << "}\n"; + }; + print_set(u_adj, "Neighbors of u"); + print_set(v_adj, "Neighbors of v"); + print_set(all_adj, "Combined neighbors"); + } + + // 步骤 3: 遍历合并后的邻居集合,计算度数 >= K 的节点数量 + int k = 0; + if (DEEPERDEBUG) std::cerr << "[Briggs] Checking significance of combined neighbors:\n"; + for (unsigned n : all_adj) { + // 关键修正:只考虑那些在工作集中的邻居节点 n + if (degree.count(n) > 0) { + int K = isFPVReg(n) ? K_fp : K_int; + if (degree.at(n) >= K) { + k++; + if (DEEPERDEBUG) { + std::cerr << "[Briggs] - Node " << regIdToString(n) << " is significant (degree " << degree.at(n) << " >= " << K << "). Count k is now " << k << ".\n"; + } + } + } + } + + // 步骤 4: 比较 "重要" 邻居的数量是否小于 K + int K_u = isFPVReg(u) ? K_fp : K_int; + bool result = (k < K_u); + + if (DEEPERDEBUG) { + std::cerr << "[Briggs] Final count of significant neighbors (k) = " << k << ".\n"; + std::cerr << "[Briggs] K value for node " << regIdToString(u) << " is " << K_u << ".\n"; + std::cerr << "[Briggs] >>>>> Result (k < K): " << (result ? "OK (can coalesce)" : "FAIL (cannot coalesce)") << "\n\n"; + } + return result; +} + +// George启发式 +bool RISCv64RegAlloc::georgeHeuristic(unsigned t, unsigned u) { + // 如果 t 不是一个待分配的虚拟寄存器(即它是物理寄存器), + // 那么它已经被预着色,总是满足 George 启发式条件。 + // 我们通过检查 degree.count(t) 来判断 t 是否在我们的虚拟寄存器工作集中。 + if (degree.count(t) == 0) { + return true; + } + + int K = isFPVReg(t) ? K_fp : K_int; + // adjList.at(t) 现在是安全的,因为 degree.count(t) > 0 保证了 adjList.count(t) > 0 + return degree.at(t) < K || precolored.count(u) || adjList.at(t).count(u); +} + +void RISCv64RegAlloc::combine(unsigned u, unsigned v) { + freezeWorklist.erase(v); + spillWorklist.erase(v); + coalescedNodes.insert(v); + alias[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); + } + enableMoves({v}); + for (unsigned t : adjList.at(v)) { + addEdge(t, u); + decrementDegree(t); + } + + 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::freezeMoves(unsigned u) { + if (precolored.count(u)) return; + + VRegMoveSet moves = nodeMoves(u); + for (const auto& move : moves) { + VRegSet use, def; + getInstrUseDef_Liveness(move, use, def); + unsigned x = *def.begin(); + unsigned y = *use.begin(); + unsigned v_alias; + + if (getAlias(y) == getAlias(u)) { + v_alias = getAlias(x); + } else { + v_alias = getAlias(y); + } + + activeMoves.erase(move); + frozenMoves.insert(move); + + if (!precolored.count(v_alias) && nodeMoves(v_alias).empty() && degree.at(v_alias) < (isFPVReg(v_alias) ? K_fp : K_int)) { + freezeWorklist.erase(v_alias); + simplifyWorklist.insert(v_alias); + if (DEEPERDEBUG) { + std::cerr << "[freezeMoves] Node " << regIdToString(v_alias) << " moved to simplifyWorklist (degree: " << degree.at(v_alias) << ").\n"; + } + } + } +} + +// 检查vreg是否为浮点类型 +bool RISCv64RegAlloc::isFPVReg(unsigned vreg) const { + // 1. 检查是否为虚拟寄存器 + if (vreg_type_map.count(vreg)) { + return vreg_type_map.at(vreg)->isFloat(); + } + + // 2. 检查是否为物理寄存器 (ID >= 100000) + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + if (vreg >= offset) { + // 先减去偏移,还原成原始的、小的枚举值 + unsigned raw_preg_id = vreg - offset; + + // 再用原始枚举值判断是否在浮点寄存器范围内 + if (raw_preg_id >= static_cast(PhysicalReg::F0) && raw_preg_id <= static_cast(PhysicalReg::F31)) { + return true; + } + } + + // 3. 其他所有情况(如未知的vreg,或整数物理寄存器)都默认为整数 + return false; +} + +// 收集被使用的被调用者保存寄存器 +void RISCv64RegAlloc::collectUsedCalleeSavedRegs() { + StackFrameInfo& frame_info = MFunc->getFrameInfo(); + frame_info.used_callee_saved_regs.clear(); + + const auto& callee_saved_int = getCalleeSavedIntRegs(); + const auto& callee_saved_fp = getCalleeSavedFpRegs(); + std::set callee_saved_set(callee_saved_int.begin(), callee_saved_int.end()); + callee_saved_set.insert(callee_saved_fp.begin(), callee_saved_fp.end()); + // s0总是被使用作为帧指针 + callee_saved_set.insert(PhysicalReg::S0); + + + for(const auto& pair : color_map) { + PhysicalReg preg = pair.second; + if(callee_saved_set.count(preg)) { + frame_info.used_callee_saved_regs.insert(preg); + } + } +} + +/** + * @brief 将最终的寄存器分配结果应用到所有机器指令上。 + * 遍历所有操作数,将虚拟寄存器替换为分配到的物理寄存器。 + */ +void RISCv64RegAlloc::applyColoring() { for (auto& mbb : MFunc->getBlocks()) { for (auto& instr_ptr : mbb->getInstructions()) { for (auto& op_ptr : instr_ptr->getOperands()) { - // 定义一个处理寄存器操作数的 lambda 函数 - auto process_reg_op = [&](RegOperand* reg_op) { + if (op_ptr->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(op_ptr.get()); + if (reg_op->isVirtual()) { + unsigned vreg = reg_op->getVRegNum(); + if (color_map.count(vreg)) { + // 使用 setPReg 将虚拟寄存器转换为物理寄存器 + reg_op->setPReg(color_map.at(vreg)); + } else { + // 如果一个vreg在成功分配后仍然没有颜色,这是一个错误 + std::cerr << "FATAL: Virtual register %vreg" << vreg << " has no color after allocation!\n"; + assert(false && "Virtual register has no color after allocation!"); + reg_op->setPReg(PhysicalReg::T6); + } + } + } else if (op_ptr->getKind() == MachineOperand::KIND_MEM) { + auto mem_op = static_cast(op_ptr.get()); + auto reg_op = mem_op->getBase(); if (reg_op->isVirtual()) { unsigned vreg = reg_op->getVRegNum(); if (color_map.count(vreg)) { reg_op->setPReg(color_map.at(vreg)); - } else if (spilled_vregs.count(vreg)) { - // 根据vreg类型,替换为对应的专用溢出寄存器 - assert(vreg_to_value_map.count(vreg)); - Value* val = vreg_to_value_map.at(vreg); - if (val->getType()->isFloat()) { - reg_op->setPReg(FP_SPILL_REG); - } else { - reg_op->setPReg(INT_SPILL_REG); - } + } else { + assert(false && "Virtual register in memory operand has no color!"); + reg_op->setPReg(PhysicalReg::T6); } } - }; - - if(op_ptr->getKind() == MachineOperand::KIND_REG) { - process_reg_op(static_cast(op_ptr.get())); - } else if (op_ptr->getKind() == MachineOperand::KIND_MEM) { - process_reg_op(static_cast(op_ptr.get())->getBase()); } } } } } +void RISCv64RegAlloc::dumpState(const std::string& stage) { + if (!DEEPDEBUG) return; + std::cerr << "\n=============== STATE DUMP (" << stage << ") ===============\n"; + auto print_vreg_set = [&](const VRegSet& s, const std::string& name){ + if (s.size() > DEBUGLENGTH) { + std::cerr << name << " (" << s.size() << ")\n"; + } + else { + std::cerr << name << " (" << s.size() << "): { "; + for(unsigned v : s) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + } + + }; + auto print_vreg_stack = [&](const VRegStack& s, const std::string& name){ + if (s.size() > DEBUGLENGTH) { + std::cerr << name << " (" << s.size() << ")\n"; + } + else { + std::cerr << name << " (" << s.size() << "): { "; + for(unsigned v : s) std::cerr << "%vreg" << v << " "; + std::cerr << "}\n"; + } + + }; + print_vreg_set(simplifyWorklist, "SimplifyWorklist"); + print_vreg_set(freezeWorklist, "FreezeWorklist"); + print_vreg_set(spillWorklist, "SpillWorklist"); + print_vreg_set(coalescedNodes, "CoalescedNodes"); + print_vreg_set(spilledNodes, "SpilledNodes"); + + print_vreg_stack(selectStack, "SelectStack"); + + std::cerr << "WorklistMoves (" << worklistMoves.size() << ")\n"; + std::cerr << "ActiveMoves (" << activeMoves.size() << ")\n"; + + size_t final_nodes = coalescedNodes.size() + spilledNodes.size() + selectStack.size(); + std::cerr << "Total Final Nodes: " << final_nodes << "\n"; + std::cerr << "=======================================================\n"; +} + +std::string RISCv64RegAlloc::regToString(PhysicalReg reg) { + switch (reg) { + case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra"; + case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp"; + case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0"; + case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2"; + case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1"; + case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1"; + case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3"; + case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5"; + case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7"; + case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3"; + case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5"; + case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7"; + case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9"; + case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11"; + case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4"; + case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6"; + case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1"; + case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3"; + case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5"; + case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7"; + case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9"; + case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11"; + case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13"; + case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15"; + case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17"; + case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19"; + case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21"; + case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23"; + case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25"; + case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27"; + case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29"; + case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31"; + default: return "UNKNOWN_REG"; + } +} + +std::string RISCv64RegAlloc::regIdToString(unsigned id) { + const unsigned offset = static_cast(PhysicalReg::PHYS_REG_START_ID); + + if (id >= offset && precolored.count(id)) { + // 先减去偏移量,得到原始的、小的枚举值 + PhysicalReg reg = static_cast(id - offset); + // 再将原始枚举值传给 regToString + return regToString(reg); + } else { + return "%vreg" + std::to_string(id); + } +} + } // namespace sysy \ No newline at end of file diff --git a/src/include/backend/RISCv64/Handler/EliminateFrameIndices.h b/src/include/backend/RISCv64/Handler/EliminateFrameIndices.h new file mode 100644 index 0000000..155bdba --- /dev/null +++ b/src/include/backend/RISCv64/Handler/EliminateFrameIndices.h @@ -0,0 +1,20 @@ +#ifndef ELIMINATE_FRAME_INDICES_H +#define ELIMINATE_FRAME_INDICES_H + +#include "RISCv64LLIR.h" + +namespace sysy { + +class EliminateFrameIndicesPass { +public: + // Pass 的主入口函数 + void runOnMachineFunction(MachineFunction* mfunc); + +private: + // 帮助计算类型大小的辅助函数,从原RegAlloc中移出 + unsigned getTypeSizeInBytes(Type* type); +}; + +} // namespace sysy + +#endif // ELIMINATE_FRAME_INDICES_H \ No newline at end of file diff --git a/src/include/backend/RISCv64/RISCv64Backend.h b/src/include/backend/RISCv64/RISCv64Backend.h index 9e179d9..4f8ebf0 100644 --- a/src/include/backend/RISCv64/RISCv64Backend.h +++ b/src/include/backend/RISCv64/RISCv64Backend.h @@ -22,7 +22,6 @@ private: // 函数级代码生成 (实现新的流水线) std::string function_gen(Function* func); - // 私有辅助函数,用于根据类型计算其占用的字节数。 unsigned getTypeSizeInBytes(Type* type); diff --git a/src/include/backend/RISCv64/RISCv64LLIR.h b/src/include/backend/RISCv64/RISCv64LLIR.h index 3c8710e..b2111ff 100644 --- a/src/include/backend/RISCv64/RISCv64LLIR.h +++ b/src/include/backend/RISCv64/RISCv64LLIR.h @@ -3,6 +3,7 @@ #include "IR.h" // 确保包含了您自己的IR头文件 #include +#include #include #include #include @@ -38,7 +39,7 @@ enum class PhysicalReg { // 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突) // 假设 vreg_counter 不会达到这么大的值 - PHYS_REG_START_ID = 100000, + PHYS_REG_START_ID = 1000000, PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间 }; @@ -195,6 +196,11 @@ public: preg = new_preg; is_virtual = false; } + + void setVRegNum(unsigned new_vreg_num) { + vreg_num = new_vreg_num; + is_virtual = true; // 确保设置vreg时,操作数状态正确 + } private: unsigned vreg_num = 0; PhysicalReg preg = PhysicalReg::ZERO; @@ -274,14 +280,15 @@ private: // 栈帧信息 struct StackFrameInfo { int locals_size = 0; // 仅为AllocaInst分配的大小 + int locals_end_offset = 0; // 记录局部变量分配结束后的偏移量(相对于s0,为负) int spill_size = 0; // 仅为溢出分配的大小 int total_size = 0; // 总大小 int callee_saved_size = 0; // 保存寄存器的大小 std::map alloca_offsets; // std::map spill_offsets; // <溢出vreg, 栈偏移> std::set used_callee_saved_regs; // 使用的保存寄存器 - std::map vreg_to_preg_map; - std::vector callee_saved_regs; // 用于存储需要保存的被调用者保存寄存器列表 + std::map vreg_to_preg_map; // RegAlloc最终的分配结果 + std::vector callee_saved_regs_to_store; // 已排序的、需要存取的被调用者保存寄存器 }; // 机器函数 @@ -295,7 +302,7 @@ public: StackFrameInfo& getFrameInfo() { return frame_info; } const std::vector>& getBlocks() const { return blocks; } std::vector>& getBlocks() { return blocks; } - + void dumpStackFrameInfo(std::ostream& os = std::cerr) const; void addBlock(std::unique_ptr block) { blocks.push_back(std::move(block)); } diff --git a/src/include/backend/RISCv64/RISCv64Passes.h b/src/include/backend/RISCv64/RISCv64Passes.h index b456994..b6a5427 100644 --- a/src/include/backend/RISCv64/RISCv64Passes.h +++ b/src/include/backend/RISCv64/RISCv64Passes.h @@ -8,6 +8,7 @@ #include "CalleeSavedHandler.h" #include "LegalizeImmediates.h" #include "PrologueEpilogueInsertion.h" +#include "EliminateFrameIndices.h" #include "Pass.h" #include "DivStrengthReduction.h" diff --git a/src/include/backend/RISCv64/RISCv64RegAlloc.h b/src/include/backend/RISCv64/RISCv64RegAlloc.h index 992aa5c..bea9ddc 100644 --- a/src/include/backend/RISCv64/RISCv64RegAlloc.h +++ b/src/include/backend/RISCv64/RISCv64RegAlloc.h @@ -3,9 +3,15 @@ #include "RISCv64LLIR.h" #include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型 +#include +#include +#include +#include extern int DEBUG; extern int DEEPDEBUG; +extern int DEBUGLENGTH; // 用于限制调试输出的长度 +extern int DEEPERDEBUG; // 用于更深层次的调试输出 namespace sysy { @@ -17,58 +23,98 @@ public: void run(); private: - using LiveSet = std::set; // 活跃虚拟寄存器集合 - using InterferenceGraph = std::map>; + // 类型定义,与Python版本对应 + using VRegSet = std::set; + using InterferenceGraph = std::map; + using VRegStack = std::vector; // 使用vector模拟栈,方便遍历 + using MoveList = std::map>; + using AliasMap = std::map; + using ColorMap = std::map; + using VRegMoveSet = std::set; - // 栈帧管理 - void eliminateFrameIndices(); - - // 活跃性分析 + // --- 核心算法流程 --- + void initialize(); + void build(); + void makeWorklist(); + void simplify(); + void coalesce(); + void freeze(); + void selectSpill(); + void assignColors(); + void rewriteProgram(); + bool doAllocation(); + void applyColoring(); + + void dumpState(const std::string &stage); + + void precolorByCallingConvention(); + + // --- 辅助函数 --- + void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def); + void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def); + void addEdge(unsigned u, unsigned v); + VRegSet adjacent(unsigned n); + VRegMoveSet nodeMoves(unsigned n); + bool moveRelated(unsigned n); + void decrementDegree(unsigned m); + void enableMoves(const VRegSet& nodes); + unsigned getAlias(unsigned n); + void addWorklist(unsigned u); + bool briggsHeuristic(unsigned u, unsigned v); + bool georgeHeuristic(unsigned u, unsigned v); + void combine(unsigned u, unsigned v); + void freezeMoves(unsigned u); + void collectUsedCalleeSavedRegs(); + bool isFPVReg(unsigned vreg) const; + std::string regToString(PhysicalReg reg); + std::string regIdToString(unsigned id); + + // --- 活跃性分析 --- void analyzeLiveness(); - // 构建干扰图 - void buildInterferenceGraph(); - - // 图着色分配寄存器 - void colorGraph(); - - // 重写函数,替换vreg并插入溢出代码 - void rewriteFunction(); - - // 辅助函数,获取指令的Use/Def集合 - void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def); - - // 辅助函数,处理调用约定 - void handleCallingConvention(); - MachineFunction* MFunc; - - // 活跃性分析结果 - std::map live_in_map; - std::map live_out_map; + RISCv64ISel* ISel; - // 干扰图 - InterferenceGraph interference_graph; - - // 图着色结果 - std::map color_map; // vreg -> preg - std::set spilled_vregs; // 被溢出的vreg集合 - - // 可用的物理寄存器池 + // --- 算法数据结构 --- + // 寄存器池 std::vector allocable_int_regs; std::vector allocable_fp_regs; + int K_int; // 整数寄存器数量 + int K_fp; // 浮点寄存器数量 - // 存储vreg到IR Value*的反向映射 - // 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。 - std::map vreg_to_value_map; - std::map preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射 - - // 用于计算类型大小的辅助函数 - unsigned getTypeSizeInBytes(Type* type); + // 节点集合 + VRegSet precolored; // 预着色的节点 (物理寄存器) + VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点 + VRegSet simplifyWorklist; + VRegSet freezeWorklist; + VRegSet spillWorklist; + VRegSet spilledNodes; + VRegSet coalescedNodes; + VRegSet coloredNodes; + VRegStack selectStack; - // 辅助函数,用于打印集合 - static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os); + // Move指令相关 + std::set coalescedMoves; + std::set constrainedMoves; + std::set frozenMoves; + std::set worklistMoves; + std::set activeMoves; + + // 数据结构 + InterferenceGraph adjSet; + std::map adjList; // 邻接表 + std::map degree; + MoveList moveList; + AliasMap alias; + ColorMap color_map; + + // 活跃性分析结果 + std::map live_in_map; + std::map live_out_map; + // VReg -> Value* 和 VReg -> Type* 的映射 + const std::map& vreg_to_value_map; + const std::map& vreg_type_map; }; } // namespace sysy diff --git a/src/sysyc.cpp b/src/sysyc.cpp index 04da485..747eb89 100644 --- a/src/sysyc.cpp +++ b/src/sysyc.cpp @@ -21,6 +21,8 @@ using namespace sysy; int DEBUG = 0; int DEEPDEBUG = 0; +int DEEPERDEBUG = 0; +int DEBUGLENGTH = 50; static string argStopAfter; static string argInputFile;