[backend]添加了一个Pass,将调用者、被调用者寄存器实现转移到其中
This commit is contained in:
@ -46,46 +46,6 @@ void RISCv64AsmPrinter::printPrologue() {
|
||||
*OS << " sd s0, " << (aligned_stack_size - 16) << "(sp)\n";
|
||||
*OS << " addi s0, sp, " << aligned_stack_size << "\n";
|
||||
}
|
||||
|
||||
// // 为函数参数分配寄存器
|
||||
// Function* F = MFunc->getFunc();
|
||||
// if (F && F->getEntryBlock()) {
|
||||
// int arg_idx = 0;
|
||||
// RISCv64ISel* isel = MFunc->getISel();
|
||||
|
||||
// // 获取函数所有参数的类型列表
|
||||
// auto param_types = F->getParamTypes();
|
||||
|
||||
// for (AllocaInst* alloca_for_param : F->getEntryBlock()->getArguments()) {
|
||||
// if (arg_idx >= 8) break;
|
||||
|
||||
// unsigned vreg = isel->getVReg(alloca_for_param);
|
||||
// if (frame_info.alloca_offsets.count(vreg)) {
|
||||
// int offset = frame_info.alloca_offsets.at(vreg);
|
||||
// auto arg_reg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
|
||||
|
||||
// // 1. 获取当前参数的真实类型
|
||||
// // 注意:F->getParamTypes() 返回的是一个 range-based view,需要转换为vector或直接使用
|
||||
// Type* current_param_type = nullptr;
|
||||
// int temp_idx = 0;
|
||||
// for(auto p_type : param_types) {
|
||||
// if (temp_idx == arg_idx) {
|
||||
// current_param_type = p_type;
|
||||
// break;
|
||||
// }
|
||||
// temp_idx++;
|
||||
// }
|
||||
// assert(current_param_type && "Could not find parameter type.");
|
||||
|
||||
// // 2. 根据类型决定使用 "sw" 还是 "sd"
|
||||
// const char* store_op = current_param_type->isPointer() ? "sd" : "sw";
|
||||
|
||||
// // 3. 打印正确的存储指令
|
||||
// *OS << " " << store_op << " " << regToString(arg_reg) << ", " << offset << "(s0)\n";
|
||||
// }
|
||||
// arg_idx++;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void RISCv64AsmPrinter::printEpilogue() {
|
||||
|
||||
@ -73,6 +73,10 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||
reg_alloc.run();
|
||||
|
||||
// 阶段 3.5: 处理被调用者保存寄存器
|
||||
CalleeSavedHandler callee_handler;
|
||||
callee_handler.runOnMachineFunction(mfunc.get());
|
||||
|
||||
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||
PeepholeOptimizer peephole;
|
||||
peephole.runOnMachineFunction(mfunc.get());
|
||||
|
||||
@ -51,4 +51,99 @@ void PostRA_Scheduler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
// std::cout << "Running Post-RA Local Scheduler..." << std::endl;
|
||||
}
|
||||
|
||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||
std::set<PhysicalReg> used_callee_saved;
|
||||
|
||||
// 1. 扫描所有指令,找出被使用的s寄存器
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto& instr : mbb->getInstructions()) {
|
||||
for (auto& op : instr->getOperands()) {
|
||||
|
||||
// 辅助Lambda,用于检查和插入寄存器
|
||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||
if (!reg_op->isVirtual()) {
|
||||
PhysicalReg preg = reg_op->getPReg();
|
||||
// --- 关键检查点 ---
|
||||
// 必须严格判断是否在 s0-s11 的范围内。
|
||||
// a0, t0 等寄存器绝对不应被视为被调用者保存寄存器。
|
||||
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有使用s寄存器(除了可能作为帧指针的s0),则无需操作
|
||||
if (used_callee_saved.empty() || (used_callee_saved.size() == 1 && used_callee_saved.count(PhysicalReg::S0))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 将结果存入StackFrameInfo,供后续使用
|
||||
frame_info.used_callee_saved_regs = used_callee_saved;
|
||||
|
||||
// 2. 在函数序言插入保存指令
|
||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||
auto& entry_instrs = entry_block->getInstructions();
|
||||
auto prologue_end = entry_instrs.begin();
|
||||
|
||||
// 找到序言结束的位置(通常是addi s0, sp, size之后)
|
||||
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::ADDI &&
|
||||
(*it)->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||
static_cast<RegOperand*>((*it)->getOperands()[0].get())->getPReg() == PhysicalReg::S0)
|
||||
{
|
||||
prologue_end = std::next(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 为了栈帧布局确定性,对寄存器进行排序
|
||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||
|
||||
int current_offset = -16; // ra和s0已经占用了-8和-16的位置
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
if (reg == PhysicalReg::S0) continue; // s0已经在序言中处理
|
||||
current_offset -= 8;
|
||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
||||
sd->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 假设s0是帧指针
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
entry_instrs.insert(prologue_end, std::move(sd));
|
||||
}
|
||||
|
||||
// 3. 在函数结尾(ret之前)插入恢复指令
|
||||
for (auto& mbb : mfunc->getBlocks()) {
|
||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||
// 以相反的顺序恢复
|
||||
current_offset = -16;
|
||||
for (PhysicalReg reg : sorted_regs) {
|
||||
if (reg == PhysicalReg::S0) continue;
|
||||
current_offset -= 8;
|
||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
||||
ld->addOperand(std::make_unique<MemOperand>(
|
||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||
std::make_unique<ImmOperand>(current_offset)
|
||||
));
|
||||
mbb->getInstructions().insert(it, std::move(ld));
|
||||
}
|
||||
break; // 处理完一个基本块的ret即可
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sysy
|
||||
@ -36,7 +36,6 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
||||
// 获取函数的Argument对象列表
|
||||
if (F) {
|
||||
auto& args = F->getArguments();
|
||||
|
||||
// RISC-V RV64G调用约定:前8个整型/指针参数通过 a0-a7 传递
|
||||
int arg_idx = 0;
|
||||
// 遍历 AllocaInst* 列表
|
||||
@ -494,10 +493,6 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
if (color_map.count(vreg)) {
|
||||
PhysicalReg preg = color_map.at(vreg);
|
||||
reg_op->setPReg(preg);
|
||||
// 检查这个物理寄存器是否是 s0-s11
|
||||
if (preg >= PhysicalReg::S0 && preg <= PhysicalReg::S11) {
|
||||
used_callee_saved_regs.insert(preg);
|
||||
}
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果vreg被溢出,替换为专用的溢出物理寄存器t6
|
||||
reg_op->setPReg(PhysicalReg::T6);
|
||||
@ -512,14 +507,16 @@ void RISCv64RegAlloc::rewriteFunction() {
|
||||
|
||||
// 对这个基址寄存器,执行与情况一完全相同的替换逻辑
|
||||
if(base_reg_op->isVirtual()){
|
||||
unsigned vreg = base_reg_op->getVRegNum();
|
||||
if(color_map.count(vreg)) {
|
||||
// 如果基址vreg被成功着色,替换
|
||||
base_reg_op->setPReg(color_map.at(vreg));
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果基址vreg被溢出,替换为t6
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
unsigned vreg = base_reg_op->getVRegNum();
|
||||
if(color_map.count(vreg)) {
|
||||
// 如果基址vreg被成功着色,替换
|
||||
PhysicalReg preg = color_map.at(vreg);
|
||||
base_reg_op->setPReg(preg);
|
||||
|
||||
} else if (spilled_vregs.count(vreg)) {
|
||||
// 如果基址vreg被溢出,替换为t6
|
||||
base_reg_op->setPReg(PhysicalReg::T6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,8 +18,24 @@ namespace sysy {
|
||||
|
||||
// 物理寄存器定义
|
||||
enum class PhysicalReg {
|
||||
ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6,
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
||||
// --- 特殊功能寄存器 ---
|
||||
ZERO, RA, SP, GP, TP,
|
||||
|
||||
// --- 整数寄存器 (按调用约定分组) ---
|
||||
// 临时寄存器 (调用者保存)
|
||||
T0, T1, T2, T3, T4, T5, T6,
|
||||
|
||||
// 保存寄存器 (被调用者保存)
|
||||
S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11,
|
||||
|
||||
// 参数/返回值寄存器 (调用者保存)
|
||||
A0, A1, A2, A3, A4, A5, A6, A7,
|
||||
|
||||
// --- 浮点寄存器 ---
|
||||
// (保持您原有的 F0-F31 命名)
|
||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
||||
};
|
||||
|
||||
// RISC-V 指令操作码枚举
|
||||
@ -173,6 +189,7 @@ struct StackFrameInfo {
|
||||
int total_size = 0; // 总大小
|
||||
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
||||
};
|
||||
|
||||
// 机器函数
|
||||
|
||||
@ -31,6 +31,20 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class CalleeSavedHandler
|
||||
* @brief 处理被调用者保存寄存器(Callee-Saved Registers)的Pass。
|
||||
* * 这个Pass在寄存器分配之后运行。它的主要职责是:
|
||||
* 1. 扫描整个函数,找出所有被使用的 `s` 系列寄存器。
|
||||
* 2. 在函数序言中插入 `sd` 指令来保存这些寄存器。
|
||||
* 3. 在函数结尾(ret指令前)插入 `ld` 指令来恢复这些寄存器。
|
||||
* 4. 正确计算因保存这些寄存器而需要的额外栈空间,并更新StackFrameInfo。
|
||||
*/
|
||||
class CalleeSavedHandler : public BackendPass {
|
||||
public:
|
||||
void runOnMachineFunction(MachineFunction* mfunc) override;
|
||||
};
|
||||
|
||||
// --- 寄存器分配后优化 ---
|
||||
|
||||
/**
|
||||
|
||||
@ -56,8 +56,6 @@ private:
|
||||
// 存储vreg到IR Value*的反向映射
|
||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||
std::map<unsigned, Value*> vreg_to_value_map;
|
||||
|
||||
std::set<PhysicalReg> used_callee_saved_regs;
|
||||
|
||||
// 用于计算类型大小的辅助函数
|
||||
unsigned getTypeSizeInBytes(Type* type);
|
||||
|
||||
Reference in New Issue
Block a user