From 14fb3dbe48f50287366742b6c7ffd9825e8736c7 Mon Sep 17 00:00:00 2001 From: Lixuanwang Date: Fri, 25 Jul 2025 22:23:26 +0800 Subject: [PATCH] =?UTF-8?q?[midend][backend-GEP]=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E4=BA=86=E4=B8=80=E4=B8=AA32/64=E4=BD=8D=E5=AE=BD=E7=9A=84?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/RISCv64AsmPrinter.cpp | 48 ++++++-- src/RISCv64Backend.cpp | 2 +- src/RISCv64ISel.cpp | 83 ++++++++------ src/RISCv64RegAlloc.cpp | 201 ++++++++++++++++++++++++++++------ src/include/RISCv64LLIR.h | 8 +- src/include/RISCv64RegAlloc.h | 7 ++ 6 files changed, 272 insertions(+), 77 deletions(-) diff --git a/src/RISCv64AsmPrinter.cpp b/src/RISCv64AsmPrinter.cpp index 1995024..65dbe5d 100644 --- a/src/RISCv64AsmPrinter.cpp +++ b/src/RISCv64AsmPrinter.cpp @@ -31,6 +31,8 @@ void RISCv64AsmPrinter::run(std::ostream& os, bool debug) { } } +// 在 RISCv64AsmPrinter.cpp 文件中 + void RISCv64AsmPrinter::printPrologue() { StackFrameInfo& frame_info = MFunc->getFrameInfo(); // 序言需要为保存ra和s0预留16字节 @@ -44,12 +46,16 @@ void RISCv64AsmPrinter::printPrologue() { *OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n"; *OS << " addi s0, sp, " << aligned_stack_size << "\n"; } - - // 忠实还原保存函数入口参数的逻辑 + + // 为函数参数分配寄存器 Function* F = MFunc->getFunc(); if (F && F->getEntryBlock()) { int arg_idx = 0; RISCv64ISel* isel = MFunc->getISel(); + + // 获取函数所有参数的类型列表 + auto param_types = F->getParamTypes(); + for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) { if (arg_idx >= 8) break; @@ -57,7 +63,25 @@ void RISCv64AsmPrinter::printPrologue() { if (frame_info.alloca_offsets.count(vreg)) { int offset = frame_info.alloca_offsets.at(vreg); auto arg_reg = static_cast(static_cast(PhysicalReg::A0) + arg_idx); - *OS << " sw " << regToString(arg_reg) << ", " << offset << "(s0)\n"; + + // 1. 获取当前参数的真实类型 + // 注意:F->getParamTypes() 返回的是一个 range-based view,需要转换为vector或直接使用 + Type* current_param_type = nullptr; + int temp_idx = 0; + for(auto p_type : param_types) { + if (temp_idx == arg_idx) { + current_param_type = p_type; + break; + } + temp_idx++; + } + assert(current_param_type && "Could not find parameter type."); + + // 2. 根据类型决定使用 "sw" 还是 "sd" + const char* store_op = current_param_type->isPointer() ? "sd" : "sw"; + + // 3. 打印正确的存储指令 + *OS << " " << store_op << " " << regToString(arg_reg) << ", " << offset << "(s0)\n"; } arg_idx++; } @@ -133,17 +157,23 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) { case RVOpcodes::SNEZ: *OS << "snez "; break; case RVOpcodes::CALL: *OS << "call "; break; case RVOpcodes::LABEL: - // printOperand(instr->getOperands()[0].get()); - // *OS << ":"; break; - case RVOpcodes::FRAME_LOAD: + case RVOpcodes::FRAME_LOAD_W: // It should have been eliminated by RegAlloc if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter"); - *OS << "frame_load "; break; - case RVOpcodes::FRAME_STORE: + *OS << "frame_load_w "; break; + case RVOpcodes::FRAME_LOAD_D: // It should have been eliminated by RegAlloc if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter"); - *OS << "frame_store "; break; + *OS << "frame_load_d "; break; + case RVOpcodes::FRAME_STORE_W: + // It should have been eliminated by RegAlloc + if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter"); + *OS << "frame_store_w "; break; + case RVOpcodes::FRAME_STORE_D: + // It should have been eliminated by RegAlloc + if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter"); + *OS << "frame_store_d "; break; case RVOpcodes::FRAME_ADDR: // It should have been eliminated by RegAlloc if (!debug) throw std::runtime_error("FRAME pseudo-instruction not eliminated before AsmPrinter"); diff --git a/src/RISCv64Backend.cpp b/src/RISCv64Backend.cpp index 4f45fde..c429a63 100644 --- a/src/RISCv64Backend.cpp +++ b/src/RISCv64Backend.cpp @@ -85,7 +85,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) { std::stringstream ss; RISCv64AsmPrinter printer(mfunc.get()); printer.run(ss); - if (DEBUG) ss << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中 + if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中 return ss.str(); } diff --git a/src/RISCv64ISel.cpp b/src/RISCv64ISel.cpp index b6ed7df..db07908 100644 --- a/src/RISCv64ISel.cpp +++ b/src/RISCv64ISel.cpp @@ -149,38 +149,51 @@ void RISCv64ISel::selectNode(DAGNode* node) { auto dest_vreg = getVReg(node->value); Value* ptr_val = node->operands[0]->value; - // [V1设计保留] 对于从栈变量加载,继续使用伪指令 FRAME_LOAD。 - // 这种设计将栈帧布局的具体计算推迟到后续的 `eliminateFrameIndices` 阶段,保持了模块化。 + // --- 修改点 --- + // 1. 获取加载结果的类型 (即这个LOAD指令自身的类型) + Type* loaded_type = node->value->getType(); + + // 2. 根据类型选择正确的伪指令或真实指令操作码 + RVOpcodes frame_opcode = loaded_type->isPointer() ? RVOpcodes::FRAME_LOAD_D : RVOpcodes::FRAME_LOAD_W; + RVOpcodes real_opcode = loaded_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW; + + if (auto alloca = dynamic_cast(ptr_val)) { - auto instr = std::make_unique(RVOpcodes::FRAME_LOAD); + // 3. 创建使用新的、区分宽度的伪指令 + auto instr = std::make_unique(frame_opcode); instr->addOperand(std::make_unique(dest_vreg)); instr->addOperand(std::make_unique(getVReg(alloca))); CurMBB->addInstruction(std::move(instr)); + } else if (auto global = dynamic_cast(ptr_val)) { - // 对于全局变量,先用 la 加载其地址,再用 lw 加载其值。 + // 对于全局变量,先用 la 加载其地址 auto addr_vreg = getNewVReg(); auto la = std::make_unique(RVOpcodes::LA); la->addOperand(std::make_unique(addr_vreg)); la->addOperand(std::make_unique(global->getName())); CurMBB->addInstruction(std::move(la)); - auto lw = std::make_unique(RVOpcodes::LW); - lw->addOperand(std::make_unique(dest_vreg)); - lw->addOperand(std::make_unique( + // 然后根据类型使用 ld 或 lw 加载其值 + auto load_instr = std::make_unique(real_opcode); + load_instr->addOperand(std::make_unique(dest_vreg)); + load_instr->addOperand(std::make_unique( std::make_unique(addr_vreg), std::make_unique(0) )); - CurMBB->addInstruction(std::move(lw)); + CurMBB->addInstruction(std::move(load_instr)); + } else { - // 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载。 + // 对于已经在虚拟寄存器中的指针地址,直接通过该地址加载 auto ptr_vreg = getVReg(ptr_val); - auto lw = std::make_unique(RVOpcodes::LW); - lw->addOperand(std::make_unique(dest_vreg)); - lw->addOperand(std::make_unique( + + // 根据类型使用 ld 或 lw + auto load_instr = std::make_unique(real_opcode); + load_instr->addOperand(std::make_unique(dest_vreg)); + load_instr->addOperand(std::make_unique( std::make_unique(ptr_vreg), std::make_unique(0) )); - CurMBB->addInstruction(std::move(lw)); + CurMBB->addInstruction(std::move(load_instr)); } break; } @@ -189,13 +202,8 @@ void RISCv64ISel::selectNode(DAGNode* node) { Value* val_to_store = node->operands[0]->value; Value* ptr_val = node->operands[1]->value; - // [V2优点] 在STORE节点内部负责加载作为源的常量。 - // 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它。 + // 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它 if (auto val_const = dynamic_cast(val_to_store)) { - if (DEBUG) { - std::cout << "[DEBUG] selectNode-BINARY: Found constant operand with value " << val_const->getInt() - << ". Generating LI instruction." << std::endl; - } auto li = std::make_unique(RVOpcodes::LI); li->addOperand(std::make_unique(getVReg(val_const))); li->addOperand(std::make_unique(val_const->getInt())); @@ -203,37 +211,50 @@ void RISCv64ISel::selectNode(DAGNode* node) { } auto val_vreg = getVReg(val_to_store); - // [V1设计保留] 同样,对于向栈变量的存储,使用 FRAME_STORE 伪指令。 + // --- 修改点 --- + // 1. 获取被存储的值的类型 + Type* stored_type = val_to_store->getType(); + + // 2. 根据类型选择正确的伪指令或真实指令操作码 + RVOpcodes frame_opcode = stored_type->isPointer() ? RVOpcodes::FRAME_STORE_D : RVOpcodes::FRAME_STORE_W; + RVOpcodes real_opcode = stored_type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW; + if (auto alloca = dynamic_cast(ptr_val)) { - auto instr = std::make_unique(RVOpcodes::FRAME_STORE); + // 3. 创建使用新的、区分宽度的伪指令 + auto instr = std::make_unique(frame_opcode); instr->addOperand(std::make_unique(val_vreg)); instr->addOperand(std::make_unique(getVReg(alloca))); CurMBB->addInstruction(std::move(instr)); + } else if (auto global = dynamic_cast(ptr_val)) { - // 向全局变量存储。 + // 向全局变量存储 auto addr_vreg = getNewVReg(); auto la = std::make_unique(RVOpcodes::LA); la->addOperand(std::make_unique(addr_vreg)); la->addOperand(std::make_unique(global->getName())); CurMBB->addInstruction(std::move(la)); - auto sw = std::make_unique(RVOpcodes::SW); - sw->addOperand(std::make_unique(val_vreg)); - sw->addOperand(std::make_unique( + // 根据类型使用 sd 或 sw + auto store_instr = std::make_unique(real_opcode); + store_instr->addOperand(std::make_unique(val_vreg)); + store_instr->addOperand(std::make_unique( std::make_unique(addr_vreg), std::make_unique(0) )); - CurMBB->addInstruction(std::move(sw)); + CurMBB->addInstruction(std::move(store_instr)); + } else { - // 向一个指针(存储在虚拟寄存器中)指向的地址存储。 + // 向一个指针(存储在虚拟寄存器中)指向的地址存储 auto ptr_vreg = getVReg(ptr_val); - auto sw = std::make_unique(RVOpcodes::SW); - sw->addOperand(std::make_unique(val_vreg)); - sw->addOperand(std::make_unique( + + // 根据类型使用 sd 或 sw + auto store_instr = std::make_unique(real_opcode); + store_instr->addOperand(std::make_unique(val_vreg)); + store_instr->addOperand(std::make_unique( std::make_unique(ptr_vreg), std::make_unique(0) )); - CurMBB->addInstruction(std::move(sw)); + CurMBB->addInstruction(std::move(store_instr)); } break; } diff --git a/src/RISCv64RegAlloc.cpp b/src/RISCv64RegAlloc.cpp index 0c0a4a3..5edcf98 100644 --- a/src/RISCv64RegAlloc.cpp +++ b/src/RISCv64RegAlloc.cpp @@ -27,24 +27,26 @@ void RISCv64RegAlloc::run() { void RISCv64RegAlloc::eliminateFrameIndices() { StackFrameInfo& frame_info = MFunc->getFrameInfo(); - int current_offset = 20; // 这里写20是为了在$s0和第一个变量之间留出20字节的安全区, - // 以防止一些函数调用方面的恶性bug。 + // 初始偏移量,为保存ra和s0留出空间。可以根据你的函数序言调整。 + // 假设序言是 addi sp, sp, -stack_size; sd ra, stack_size-8(sp); sd s0, stack_size-16(sp); + int current_offset = 16; + Function* F = MFunc->getFunc(); RISCv64ISel* isel = MFunc->getISel(); + // --- MODIFICATION START: 动态计算栈帧大小 --- + // 遍历AllocaInst来计算局部变量所需的总空间 for (auto& bb : F->getBasicBlocks()) { for (auto& inst : bb->getInstructions()) { if (auto alloca = dynamic_cast(inst.get())) { - int size = 4; - if (!alloca->getDims().empty()) { - int num_elements = 1; - for (const auto& dim_use : alloca->getDims()) { - if (auto const_dim = dynamic_cast(dim_use->getValue())) { - num_elements *= const_dim->getInt(); - } - } - size *= num_elements; - } + // 获取Alloca指令指向的类型 (例如 alloca i32* 中,获取 i32) + 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字节 + current_offset += size; unsigned alloca_vreg = isel->getVReg(alloca); frame_info.alloca_offsets[alloca_vreg] = -current_offset; @@ -52,50 +54,66 @@ void RISCv64RegAlloc::eliminateFrameIndices() { } } frame_info.locals_size = current_offset; + // --- MODIFICATION END --- + // 遍历所有机器指令,将伪指令展开为真实指令 for (auto& mbb : MFunc->getBlocks()) { std::vector> new_instructions; for (auto& instr_ptr : mbb->getInstructions()) { - if (instr_ptr->getOpcode() == RVOpcodes::FRAME_LOAD) { + 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)); - auto lw = std::make_unique(RVOpcodes::LW); - lw->addOperand(std::make_unique(dest_vreg)); - lw->addOperand(std::make_unique( + // 展开为: 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(lw)); + 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; - } else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_STORE) { 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)); - auto sw = std::make_unique(RVOpcodes::SW); - sw->addOperand(std::make_unique(src_vreg)); - sw->addOperand(std::make_unique( + // 展开为: 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(sw)); - } else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) { // [新] 处理FRAME_ADDR + 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(); @@ -104,12 +122,13 @@ void RISCv64RegAlloc::eliminateFrameIndices() { // 将 `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)); // 基地址是帧指针 s0 + 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); } @@ -119,30 +138,72 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& bool is_def = true; auto opcode = instr->getOpcode(); - // 预定义def和use规则 + // --- MODIFICATION START: 细化对指令的 use/def 定义 --- + + // 对于没有定义目标寄存器的指令,预先设置 is_def = false if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE || opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE || + opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU || opcode == RVOpcodes::RET || opcode == RVOpcodes::J) { is_def = false; } + + // 对 CALL 指令进行特殊处理 if (opcode == RVOpcodes::CALL) { - // CALL会杀死所有调用者保存寄存器,这是一个简化处理 - // 同时也使用了传入a0-a7的参数 + // CALL 指令的第一个操作数通常是目标函数标签,不是寄存器。 + // 它可能会有一个可选的返回值(def),以及一系列参数(use)。 + // 这里的处理假定 CALL 的机器指令操作数布局是: + // [可选: dest_vreg (def)], [函数标签], [可选: arg1_vreg (use)], [可选: arg2_vreg (use)], ... + + // 我们需要一种方法来识别哪些操作数是def,哪些是use。 + // 一个简单的约定:如果第一个操作数是寄存器,则它是def(返回值)。 + if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) { + auto reg_op = static_cast(instr->getOperands().front().get()); + if (reg_op->isVirtual()) { + def.insert(reg_op->getVRegNum()); + } + } + + // 遍历所有操作数,非第一个寄存器操作数均视为use + bool first_reg_skipped = false; + for (const auto& op : instr->getOperands()) { + if (op->getKind() == MachineOperand::KIND_REG) { + if (!first_reg_skipped) { + first_reg_skipped = true; + continue; // 跳过我们已经作为def处理的返回值 + } + auto reg_op = static_cast(op.get()); + if (reg_op->isVirtual()) { + use.insert(reg_op->getVRegNum()); + } + } + } + + // **重要**: CALL指令还隐式定义(杀死)了所有调用者保存的寄存器。 + // 一个完整的实现会在这里将所有caller-saved寄存器标记为def, + // 以确保任何跨调用存活的变量都不会被分配到这些寄存器中。 + // 这个简化的实现暂不处理隐式def,但这是未来优化的关键点。 + + return; // CALL 指令处理完毕,直接返回 } + // --- MODIFICATION END --- + + // 对其他所有指令的通用处理逻辑 for (const auto& op : instr->getOperands()) { if (op->getKind() == MachineOperand::KIND_REG) { auto reg_op = static_cast(op.get()); if (reg_op->isVirtual()) { if (is_def) { def.insert(reg_op->getVRegNum()); - is_def = false; + is_def = false; // 一条指令通常只有一个目标寄存ator } else { use.insert(reg_op->getVRegNum()); } } } else if (op->getKind() == MachineOperand::KIND_MEM) { + // 内存操作数 `offset(base)` 中的 base 寄存器是 use auto mem_op = static_cast(op.get()); if (mem_op->getBase()->isVirtual()) { use.insert(mem_op->getBase()->getVRegNum()); @@ -151,6 +212,43 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& } } +/** + * @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; + } +} + void RISCv64RegAlloc::analyzeLiveness() { bool changed = true; while (changed) { @@ -259,8 +357,21 @@ void RISCv64RegAlloc::colorGraph() { void RISCv64RegAlloc::rewriteFunction() { StackFrameInfo& frame_info = MFunc->getFrameInfo(); int current_offset = frame_info.locals_size; + + // --- FIX 1: 动态计算溢出槽大小 --- + // 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。 for (unsigned vreg : spilled_vregs) { - current_offset += 4; + // 从反向映射中查找 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; + frame_info.spill_offsets[vreg] = -current_offset; } frame_info.spill_size = current_offset - frame_info.locals_size; @@ -271,10 +382,16 @@ void RISCv64RegAlloc::rewriteFunction() { LiveSet use, def; getInstrUseDef(instr_ptr.get(), use, def); + // --- FIX 2: 为溢出的 '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); + RVOpcodes load_op = val->getType()->isPointer() ? RVOpcodes::LD : RVOpcodes::LW; + int offset = frame_info.spill_offsets.at(vreg); - auto load = std::make_unique(RVOpcodes::LW); + auto load = std::make_unique(load_op); load->addOperand(std::make_unique(vreg)); load->addOperand(std::make_unique( std::make_unique(PhysicalReg::S0), @@ -286,10 +403,16 @@ void RISCv64RegAlloc::rewriteFunction() { new_instructions.push_back(std::move(instr_ptr)); + // --- FIX 3: 为溢出的 'def' 操作数插入正确的存储指令 --- for (unsigned vreg : def) { if (spilled_vregs.count(vreg)) { + // 根据 vreg 的类型决定使用 sw 还是 sd + assert(vreg_to_value_map.count(vreg)); + Value* val = vreg_to_value_map.at(vreg); + RVOpcodes store_op = val->getType()->isPointer() ? RVOpcodes::SD : RVOpcodes::SW; + int offset = frame_info.spill_offsets.at(vreg); - auto store = std::make_unique(RVOpcodes::SW); + auto store = std::make_unique(store_op); store->addOperand(std::make_unique(vreg)); store->addOperand(std::make_unique( std::make_unique(PhysicalReg::S0), @@ -302,27 +425,39 @@ void RISCv64RegAlloc::rewriteFunction() { mbb->getInstructions() = std::move(new_instructions); } + // 最后的虚拟寄存器到物理寄存器的替换过程保持不变 for (auto& mbb : MFunc->getBlocks()) { for (auto& instr_ptr : mbb->getInstructions()) { for (auto& op_ptr : instr_ptr->getOperands()) { + + // 情况一:操作数本身就是一个寄存器 (例如 add rd, rs1, rs2 中的所有操作数) 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)) { + // 如果vreg被成功着色,替换为物理寄存器 reg_op->setPReg(color_map.at(vreg)); } else if (spilled_vregs.count(vreg)) { - reg_op->setPReg(PhysicalReg::T6); // 溢出统一用t6 + // 如果vreg被溢出,替换为专用的溢出物理寄存器t6 + reg_op->setPReg(PhysicalReg::T6); } } - } else if (op_ptr->getKind() == MachineOperand::KIND_MEM) { + } + // 情况二:操作数是一个内存地址 (例如 lw rd, offset(rs1) 中的 offset(rs1)) + else if (op_ptr->getKind() == MachineOperand::KIND_MEM) { auto mem_op = static_cast(op_ptr.get()); + // 获取内存操作数内部的“基址寄存器” auto base_reg_op = mem_op->getBase(); + + // 对这个基址寄存器,执行与情况一完全相同的替换逻辑 if(base_reg_op->isVirtual()){ unsigned vreg = base_reg_op->getVRegNum(); if(color_map.count(vreg)) { + // 如果基址vreg被成功着色,替换 base_reg_op->setPReg(color_map.at(vreg)); } else if (spilled_vregs.count(vreg)) { + // 如果基址vreg被溢出,替换为t6 base_reg_op->setPReg(PhysicalReg::T6); } } diff --git a/src/include/RISCv64LLIR.h b/src/include/RISCv64LLIR.h index 86de7d4..d8797bc 100644 --- a/src/include/RISCv64LLIR.h +++ b/src/include/RISCv64LLIR.h @@ -44,9 +44,11 @@ enum class RVOpcodes { // 特殊标记,非指令 LABEL, // 新增伪指令,用于解耦栈帧处理 - FRAME_LOAD, // 从栈帧加载 (AllocaInst) - FRAME_STORE, // 保存到栈帧 (AllocaInst) - FRAME_ADDR, // [新] 获取栈帧变量的地址 + FRAME_LOAD_W, // 从栈帧加载 32位 Word (对应 lw) + FRAME_LOAD_D, // 从栈帧加载 64位 Doubleword (对应 ld) + FRAME_STORE_W, // 保存 32位 Word 到栈帧 (对应 sw) + FRAME_STORE_D, // 保存 64位 Doubleword 到栈帧 (对应 sd) + FRAME_ADDR, // 获取栈帧变量的地址 }; class MachineOperand; diff --git a/src/include/RISCv64RegAlloc.h b/src/include/RISCv64RegAlloc.h index c786bde..724ad1c 100644 --- a/src/include/RISCv64RegAlloc.h +++ b/src/include/RISCv64RegAlloc.h @@ -49,6 +49,13 @@ private: // 可用的物理寄存器池 std::vector allocable_int_regs; + + // 存储vreg到IR Value*的反向映射 + // 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。 + std::map vreg_to_value_map; + + // 用于计算类型大小的辅助函数 + unsigned getTypeSizeInBytes(Type* type); }; } // namespace sysy