#include "EliminateFrameIndices.h" #include "RISCv64ISel.h" #include namespace sysy { 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(); // 1. 为栈传递的参数计算偏移量 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); frame_info.alloca_offsets[vreg] = offset; } arg_idx++; } } // 2. 为局部变量分配空间,起始点在 [ra, s0] (16字节) 之后 int local_var_offset = 16; // 处理局部变量 (AllocaInst) 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; // 3. 遍历所有机器指令,将伪指令展开为真实指令 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