合并backend、backend-IRC到midend

This commit is contained in:
Lixuanwang
2025-08-03 15:18:52 +08:00
parent 5b43f208ac
commit f8e423f579
17 changed files with 1966 additions and 1135 deletions

View File

@@ -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<PhysicalReg> 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<RegOperand*>(op.get()));
} else if (op->getKind() == MachineOperand::KIND_MEM) {
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
}
}
}
}
const std::set<PhysicalReg>& 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<PhysicalReg> 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<PhysicalReg> regs_to_save = used_callee_saved;
if (regs_to_save.count(PhysicalReg::S0)) {
regs_to_save.erase(PhysicalReg::S0);
}
std::vector<std::unique_ptr<MachineInstr>> 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<PhysicalReg> 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<int>(a) < static_cast<int>(b);
});
frame_info.callee_saved_regs_to_store = sorted_regs;
auto save_instr = std::make_unique<MachineInstr>(save_op);
save_instr->addOperand(std::make_unique<RegOperand>(reg));
save_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
std::make_unique<ImmOperand>(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<std::unique_ptr<MachineInstr>> 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<MachineInstr>(restore_op);
restore_instr->addOperand(std::make_unique<RegOperand>(reg));
restore_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(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
} // namespace sysy

View File

@@ -0,0 +1,231 @@
#include "EliminateFrameIndices.h"
#include "RISCv64ISel.h"
#include <cassert>
#include <vector>
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<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();
// 在这里处理栈传递的参数以便在寄存器分配前就将数据流显式化修复溢出逻辑的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<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;
// 记录局部变量区域分配结束的最终偏移量
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<std::unique_ptr<MachineInstr>> 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<MachineInstr>(load_op);
load_instr->addOperand(std::make_unique<RegOperand>(arg_vreg));
load_instr->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
std::make_unique<ImmOperand>(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<RegOperand*>(operands[0].get())->getVRegNum();
Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr;
if (auto ir_arg = dynamic_cast<Argument*>(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<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

View File

@@ -1,17 +1,22 @@
#include "PrologueEpilogueInsertion.h"
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
#include "RISCv64ISel.h"
#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果
#include <algorithm>
#include <vector>
#include <set>
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<MachineInstr>& 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<PhysicalReg> 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<std::unique_ptr<MachineInstr>> prologue_instrs;
// 1. addi sp, sp, -aligned_stack_size
// 4.1. 分配栈帧
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));
// 2. sd ra, (aligned_stack_size - 8)(sp)
// 4.2. 保存 ra 和 s0
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>(
@@ -62,8 +77,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::make_unique<ImmOperand>(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<MachineInstr>(RVOpcodes::SD);
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
save_fp->addOperand(std::make_unique<MemOperand>(
@@ -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<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));
// --- 在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<MachineInstr>(RVOpcodes::FLW);
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));
} else {
RVOpcodes load_op = 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));
}
}
}
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<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>(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<std::unique_ptr<MachineInstr>> 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<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>(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<MachineInstr>(RVOpcodes::LD);
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
restore_ra->addOperand(std::make_unique<MemOperand>(
@@ -139,8 +140,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
std::make_unique<ImmOperand>(aligned_stack_size - 8)
));
epilogue_instrs.push_back(std::move(restore_ra));
// 2. 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>(
@@ -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<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));
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;
}
}