[backend-IRC]修复了栈传递参数逻辑
This commit is contained in:
@ -4,6 +4,7 @@
|
||||
|
||||
namespace sysy {
|
||||
|
||||
// getTypeSizeInBytes 是一个通用辅助函数,保持不变
|
||||
unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) {
|
||||
if (!type) {
|
||||
assert(false && "Cannot get size of a null type.");
|
||||
@ -31,25 +32,14 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
// 1. [已移除] 不再处理栈传递的参数
|
||||
// 原先处理栈参数 (arg_idx >= 8) 的逻辑已被移除。
|
||||
// 这项职责已完全转移到 PrologueEpilogueInsertionPass,以避免逻辑冲突和错误。
|
||||
|
||||
// 2. 为局部变量分配空间,起始点在 [ra, s0] (16字节) 之后
|
||||
// 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量
|
||||
// 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后
|
||||
int local_var_offset = 16;
|
||||
|
||||
// 处理局部变量 (AllocaInst)
|
||||
if(F) { // 确保函数指针有效
|
||||
for (auto& bb : F->getBasicBlocks()) {
|
||||
for (auto& inst : bb->getInstructions()) {
|
||||
@ -73,7 +63,8 @@ void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// 记录仅由AllocaInst分配的局部变量的总大小
|
||||
frame_info.locals_size = local_var_offset - 16;
|
||||
|
||||
// 3. 遍历所有机器指令,将伪指令展开为真实指令
|
||||
// 3. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令
|
||||
// 由于处理参数的逻辑已移除,这里的展开现在只针对局部变量,因此是正确的。
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
#include "PrologueEpilogueInsertion.h"
|
||||
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
|
||||
#include "RISCv64ISel.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace sysy {
|
||||
|
||||
@ -10,8 +11,10 @@ char PrologueEpilogueInsertionPass::ID = 0;
|
||||
|
||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
|
||||
// 1. 删除 KEEPALIVE 伪指令
|
||||
Function* F = mfunc->getFunc();
|
||||
RISCv64ISel* isel = mfunc->getISel();
|
||||
|
||||
// 1. 清理 KEEPALIVE 伪指令
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
auto& instrs = mbb->getInstructions();
|
||||
instrs.erase(
|
||||
@ -23,200 +26,185 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
||||
instrs.end()
|
||||
);
|
||||
}
|
||||
|
||||
// 2. [新增] 确定需要保存的被调用者保存寄存器 (callee-saved)
|
||||
// 这部分逻辑从 CalleeSavedHandler Pass 移入,以集中管理序言生成
|
||||
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
|
||||
std::set<PhysicalReg> used_callee_saved_regs_set;
|
||||
const auto& callee_saved_int = getCalleeSavedIntRegs();
|
||||
const auto& callee_saved_fp = getCalleeSavedFpRegs();
|
||||
|
||||
// 2. 计算最终的、对齐后的栈帧总大小
|
||||
int total_stack_size = 16 + frame_info.callee_saved_size + frame_info.locals_size + frame_info.spill_size;
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||
for (const auto& pair : vreg_to_preg_map) {
|
||||
PhysicalReg preg = pair.second;
|
||||
// 检查是否在整数或浮点 callee-saved 集合中
|
||||
// 注意:s0作为帧指针,由序言/尾声逻辑特殊处理,不在此处保存
|
||||
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 供尾声使用
|
||||
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; // 每个寄存器8字节
|
||||
|
||||
// 3. 计算最终的栈帧总大小
|
||||
int total_stack_size = frame_info.locals_size +
|
||||
frame_info.spill_size +
|
||||
frame_info.callee_saved_size +
|
||||
16; // 为 ra 和 s0 固定的16字节
|
||||
|
||||
int aligned_stack_size = (total_stack_size + 15) & ~15; // 16字节对齐
|
||||
frame_info.total_size = aligned_stack_size;
|
||||
|
||||
if (aligned_stack_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 关键修正逻辑: 修正所有局部变量(即alloca)的偏移量 ---
|
||||
// 这是最关键的一步,它解决了栈帧区域重叠的问题。
|
||||
// 在 EliminateFrameIndicesPass 运行时,它不知道 CalleeSavedHandler 后来会识别出 s1, s2
|
||||
// 并为其分配栈空间。因此,EliminateFrameIndicesPass 计算的偏移量是错误的。
|
||||
// 在这里,我们将偏移量向低地址方向整体移动,为 callee-saved 寄存器和溢出槽腾出空间。
|
||||
int callee_saved_and_spill_size = frame_info.callee_saved_size + frame_info.spill_size;
|
||||
if (callee_saved_and_spill_size > 0) {
|
||||
// 遍历所有局部变量的偏移量 Map,并进行修正
|
||||
for (auto& pair : mfunc->getFrameInfo().alloca_offsets) {
|
||||
int old_offset = pair.second; // 初始偏移量(例如 -24)
|
||||
int new_offset = old_offset - callee_saved_and_spill_size;
|
||||
pair.second = new_offset; // 更新为修正后的偏移量
|
||||
}
|
||||
// 只有在需要分配栈空间时才生成序言和尾声
|
||||
if (aligned_stack_size > 0) {
|
||||
// --- 4. 插入完整的序言 ---
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||
|
||||
// 重新遍历函数中的所有指令,用修正后的偏移量替换旧的立即数
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
// 我们只修正那些使用立即数作为偏移量的内存访问指令
|
||||
if (instr->getOpcode() == RVOpcodes::ADDI) {
|
||||
// ADDI 指令可能有 `addi rd, s0, offset` 的形式
|
||||
// 操作数是 [rd, s0, offset],我们需要检查第2个操作数(s0)并修改第3个(offset)
|
||||
if (instr->getOperands().size() > 2) {
|
||||
if (auto reg_op = dynamic_cast<RegOperand*>(instr->getOperands()[1].get())) {
|
||||
if (reg_op->getPReg() == PhysicalReg::S0) {
|
||||
if (auto imm_op = dynamic_cast<ImmOperand*>(instr->getOperands()[2].get())) {
|
||||
// ImmOperand 是不可变的, 所以我们创建一个新的来替换它
|
||||
int64_t old_imm = imm_op->getValue();
|
||||
instr->getOperands()[2] = std::make_unique<ImmOperand>(old_imm - callee_saved_and_spill_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (instr->getOpcode() == RVOpcodes::LD || instr->getOpcode() == RVOpcodes::SD ||
|
||||
instr->getOpcode() == RVOpcodes::FLW || instr->getOpcode() == RVOpcodes::FSW ||
|
||||
instr->getOpcode() == RVOpcodes::FLD || instr->getOpcode() == RVOpcodes::FSD) {
|
||||
// Load/Store 指令的操作数是 [rd, MemOperand]
|
||||
// 我们需要检查 MemOperand 的基址寄存器是否为 s0
|
||||
if (instr->getOperands().size() > 1) {
|
||||
if (auto mem_op = dynamic_cast<MemOperand*>(instr->getOperands()[1].get())) {
|
||||
if (mem_op->getBase() && mem_op->getBase()->getPReg() == PhysicalReg::S0) {
|
||||
// MemOperand 和 ImmOperand 都是不可变的, 我们必须重新构建整个 MemOperand
|
||||
RegOperand* base_reg_op = mem_op->getBase();
|
||||
ImmOperand* offset_op = mem_op->getOffset();
|
||||
// 4.1. 分配栈帧: addi sp, sp, -aligned_stack_size
|
||||
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(alloc_stack));
|
||||
|
||||
if (base_reg_op && offset_op) {
|
||||
int64_t old_offset = offset_op->getValue();
|
||||
int64_t new_offset = old_offset - callee_saved_and_spill_size;
|
||||
|
||||
// 重新创建基址寄存器操作数 (必须处理虚拟/物理寄存器)
|
||||
std::unique_ptr<RegOperand> new_base;
|
||||
if (base_reg_op->isVirtual()) {
|
||||
new_base = std::make_unique<RegOperand>(base_reg_op->getVRegNum());
|
||||
} else {
|
||||
new_base = std::make_unique<RegOperand>(base_reg_op->getPReg());
|
||||
}
|
||||
|
||||
// 创建新的偏移立即数操作数
|
||||
auto new_offset_imm = std::make_unique<ImmOperand>(new_offset);
|
||||
|
||||
// 用新创建的 MemOperand 替换旧的
|
||||
instr->getOperands()[1] = std::make_unique<MemOperand>(std::move(new_base), std::move(new_offset_imm));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3. 插入完整的序言 ---
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||
|
||||
// a. addi sp, sp, -aligned_stack_size
|
||||
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(alloc_stack));
|
||||
|
||||
// b. sd ra, (aligned_stack_size - 8)(sp)
|
||||
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
save_ra->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_ra));
|
||||
|
||||
// c. sd s0, (aligned_stack_size - 16)(sp)
|
||||
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
save_fp->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 16)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_fp));
|
||||
|
||||
// d. 保存所有其他的被调用者保存寄存器,并记录它们的偏移量
|
||||
std::map<PhysicalReg, int> callee_saved_offsets;
|
||||
int current_offset = aligned_stack_size - 16;
|
||||
for (PhysicalReg reg : frame_info.callee_saved_regs_to_store) {
|
||||
current_offset -= 8;
|
||||
callee_saved_offsets[reg] = current_offset; // 记录偏移量
|
||||
RVOpcodes save_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD;
|
||||
|
||||
auto save_reg = std::make_unique<MachineInstr>(save_op);
|
||||
save_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
save_reg->addOperand(std::make_unique<MemOperand>(
|
||||
// 4.2. 保存 ra 和 s0
|
||||
// sd ra, (aligned_stack_size - 8)(sp)
|
||||
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
save_ra->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_reg));
|
||||
}
|
||||
prologue_instrs.push_back(std::move(save_ra));
|
||||
// sd s0, (aligned_stack_size - 16)(sp)
|
||||
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
save_fp->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 16)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_fp));
|
||||
|
||||
// 4.3. 设置新的帧指针 s0: addi s0, sp, aligned_stack_size
|
||||
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(set_fp));
|
||||
|
||||
// 4.4. [新增] 保存所有使用到的被调用者保存寄存器
|
||||
// 它们保存在 s0 下方,紧接着 ra/s0 的位置
|
||||
int callee_saved_offset = -16;
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
callee_saved_offset -= 8;
|
||||
RVOpcodes store_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FSD : RVOpcodes::SD;
|
||||
auto save_cs_reg = std::make_unique<MachineInstr>(store_op);
|
||||
save_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
save_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(callee_saved_offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(save_cs_reg));
|
||||
}
|
||||
|
||||
// e. addi s0, sp, aligned_stack_size
|
||||
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
prologue_instrs.push_back(std::move(set_fp));
|
||||
// 4.5. [核心] 加载所有通过栈传递的参数
|
||||
// 这些参数位于 s0 上方 (正偏移量)
|
||||
if (F && isel) {
|
||||
int arg_idx = 0;
|
||||
for (Argument* arg : F->getArguments()) {
|
||||
if (arg_idx >= 8) {
|
||||
unsigned vreg = isel->getVReg(arg);
|
||||
if (vreg_to_preg_map.count(vreg)) {
|
||||
// 计算正确的正偏移量
|
||||
int offset = (arg_idx - 8) * 8;
|
||||
PhysicalReg dest_preg = vreg_to_preg_map.at(vreg);
|
||||
Type* arg_type = arg->getType();
|
||||
|
||||
entry_instrs.insert(entry_instrs.begin(),
|
||||
std::make_move_iterator(prologue_instrs.begin()),
|
||||
std::make_move_iterator(prologue_instrs.end()));
|
||||
|
||||
// --- 4. 插入完整的尾声 ---
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||
|
||||
// a. [关键修正] 恢复所有其他的被调用者保存寄存器 (以相反顺序)
|
||||
const auto& regs_to_restore = frame_info.callee_saved_regs_to_store;
|
||||
for (auto reg_it = regs_to_restore.rbegin(); reg_it != regs_to_restore.rend(); ++reg_it) {
|
||||
PhysicalReg reg = *reg_it;
|
||||
int offset = callee_saved_offsets.at(reg); // 使用之前记录的正确偏移量
|
||||
RVOpcodes restore_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD;
|
||||
|
||||
auto restore_reg = std::make_unique<MachineInstr>(restore_op);
|
||||
restore_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
restore_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_reg));
|
||||
// 根据类型生成对应的加载指令
|
||||
RVOpcodes load_op = arg_type->isFloat() ? RVOpcodes::FLW : (arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW);
|
||||
auto load_arg = std::make_unique<MachineInstr>(load_op);
|
||||
load_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(offset)
|
||||
));
|
||||
prologue_instrs.push_back(std::move(load_arg));
|
||||
}
|
||||
}
|
||||
|
||||
// b. ld ra
|
||||
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
restore_ra->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_ra));
|
||||
|
||||
// c. ld s0
|
||||
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
restore_fp->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 16)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_fp));
|
||||
|
||||
// d. addi sp, sp, aligned_stack_size
|
||||
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
epilogue_instrs.push_back(std::move(dealloc_stack));
|
||||
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
|
||||
goto next_block;
|
||||
arg_idx++;
|
||||
}
|
||||
}
|
||||
next_block:;
|
||||
|
||||
// 4.6. 将所有生成的序言指令一次性插入到函数入口
|
||||
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()) {
|
||||
// [修正] 使用前向迭代器查找RET指令,以确保在正确的位置(RET之前)插入尾声。
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||
|
||||
// 5.1. [新增] 恢复被调用者保存寄存器
|
||||
callee_saved_offset = -16;
|
||||
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||
callee_saved_offset -= 8;
|
||||
RVOpcodes load_op = (reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31) ? RVOpcodes::FLD : RVOpcodes::LD;
|
||||
auto restore_cs_reg = std::make_unique<MachineInstr>(load_op);
|
||||
restore_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||
restore_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(callee_saved_offset)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_cs_reg));
|
||||
}
|
||||
|
||||
// 5.2. 恢复 ra 和 s0 (注意基址现在是sp)
|
||||
// ld ra, (aligned_stack_size - 8)(sp)
|
||||
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||
restore_ra->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_ra));
|
||||
// ld s0, (aligned_stack_size - 16)(sp)
|
||||
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||
restore_fp->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::SP),
|
||||
std::make_unique<ImmOperand>(aligned_stack_size - 16)
|
||||
));
|
||||
epilogue_instrs.push_back(std::move(restore_fp));
|
||||
|
||||
// 5.3. 释放栈帧: addi sp, sp, aligned_stack_size
|
||||
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||
epilogue_instrs.push_back(std::move(dealloc_stack));
|
||||
|
||||
// 将尾声指令插入到 RET 指令之前
|
||||
mbb->getInstructions().insert(it,
|
||||
std::make_move_iterator(epilogue_instrs.begin()),
|
||||
std::make_move_iterator(epilogue_instrs.end()));
|
||||
|
||||
// 一个基本块通常只有一个终止指令,处理完就可以跳到下一个块
|
||||
goto next_block;
|
||||
}
|
||||
}
|
||||
next_block:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
} // namespace sysy
|
||||
Reference in New Issue
Block a user