合并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