157 lines
7.3 KiB
C++
157 lines
7.3 KiB
C++
#include "EliminateFrameIndices.h"
|
|
#include "RISCv64ISel.h"
|
|
#include <cassert>
|
|
|
|
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<ArrayType>();
|
|
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<AllocaInst*>(inst.get())) {
|
|
Type* allocated_type = alloca->getType()->as<PointerType>()->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<std::unique_ptr<MachineInstr>> 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<RegOperand*>(operands[0].get())->getVRegNum();
|
|
unsigned alloca_vreg = static_cast<RegOperand*>(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<MachineInstr>(RVOpcodes::ADDI);
|
|
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
|
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
|
new_instructions.push_back(std::move(addi));
|
|
|
|
// 展开为: lw/ld/flw dest_vreg, 0(addr_vreg)
|
|
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
|
|
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
|
load_instr->addOperand(std::make_unique<MemOperand>(
|
|
std::make_unique<RegOperand>(addr_vreg),
|
|
std::make_unique<ImmOperand>(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<RegOperand*>(operands[0].get())->getVRegNum();
|
|
unsigned alloca_vreg = static_cast<RegOperand*>(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<MachineInstr>(RVOpcodes::ADDI);
|
|
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
|
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
|
new_instructions.push_back(std::move(addi));
|
|
|
|
// 展开为: sw/sd/fsw src_vreg, 0(addr_vreg)
|
|
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
|
|
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
|
store_instr->addOperand(std::make_unique<MemOperand>(
|
|
std::make_unique<RegOperand>(addr_vreg),
|
|
std::make_unique<ImmOperand>(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<RegOperand*>(operands[0].get())->getVRegNum();
|
|
unsigned alloca_vreg = static_cast<RegOperand*>(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<MachineInstr>(RVOpcodes::ADDI);
|
|
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
|
addi->addOperand(std::make_unique<ImmOperand>(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
|