[backend]修复了一个栈管理问题
This commit is contained in:
@@ -1,45 +1,45 @@
|
|||||||
#include "CalleeSavedHandler.h"
|
#include "CalleeSavedHandler.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector> //
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator> //
|
#include <iterator>
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
char CalleeSavedHandler::ID = 0;
|
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) {
|
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
// This pass works on MachineFunction level, not IR level
|
// This pass works on MachineFunction level, not IR level
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
// 此 Pass 负责分析、分配栈空间并插入 callee-saved 寄存器的保存/恢复指令。
|
|
||||||
// 它通过与 FrameInfo 协作,确保为 callee-saved 寄存器分配的空间与局部变量/溢出槽的空间不冲突。
|
|
||||||
|
|
||||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||||
|
|
||||||
// [修改] 分别记录被使用的整数和浮点被调用者保存寄存器
|
std::set<PhysicalReg> used_callee_saved;
|
||||||
std::set<PhysicalReg> used_int_callee_saved;
|
|
||||||
std::set<PhysicalReg> used_fp_callee_saved;
|
|
||||||
|
|
||||||
// 1. 扫描所有指令,找出被使用的s寄存器 (s1-s11) 和 fs寄存器 (fs0-fs11)
|
// 1. 扫描所有指令,找出被使用的callee-saved寄存器
|
||||||
|
// 这个Pass在RegAlloc之后运行,所以可以访问到物理寄存器
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
for (auto& instr : mbb->getInstructions()) {
|
||||||
for (auto& op : instr->getOperands()) {
|
for (auto& op : instr->getOperands()) {
|
||||||
|
|
||||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
||||||
if (!reg_op->isVirtual()) {
|
if (reg_op && !reg_op->isVirtual()) {
|
||||||
PhysicalReg preg = reg_op->getPReg();
|
PhysicalReg preg = reg_op->getPReg();
|
||||||
|
|
||||||
// [修改] 区分整数和浮点被调用者保存寄存器
|
// 检查整数 s1-s11
|
||||||
// s0 由序言/尾声处理器专门处理,这里不计入
|
|
||||||
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
||||||
used_int_callee_saved.insert(preg);
|
used_callee_saved.insert(preg);
|
||||||
}
|
}
|
||||||
// fs0-fs11 在我们的枚举中对应 f8,f9,f18-f27
|
// 检查浮点 fs0-fs11 (f8,f9,f18-f27)
|
||||||
else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) {
|
else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) {
|
||||||
used_fp_callee_saved.insert(preg);
|
used_callee_saved.insert(preg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -53,60 +53,44 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有使用任何需要处理的 callee-saved 寄存器,则直接返回
|
if (used_callee_saved.empty()) {
|
||||||
if (used_int_callee_saved.empty() && used_fp_callee_saved.empty()) {
|
frame_info.callee_saved_size = 0;
|
||||||
frame_info.callee_saved_size = 0; // 确保大小被初始化
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 计算为 callee-saved 寄存器分配的栈空间大小
|
// 2. 计算并更新 frame_info
|
||||||
// 每个寄存器在RV64中都占用8字节
|
frame_info.callee_saved_size = used_callee_saved.size() * 8;
|
||||||
int callee_saved_size = (used_int_callee_saved.size() + used_fp_callee_saved.size()) * 8;
|
|
||||||
frame_info.callee_saved_size = callee_saved_size;
|
// 为了布局确定性和恢复顺序一致,对寄存器排序
|
||||||
|
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
||||||
|
std::sort(sorted_regs.begin(), sorted_regs.end());
|
||||||
|
|
||||||
// 3. 在函数序言中插入保存指令
|
// 3. 在函数序言中插入保存指令
|
||||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||||
auto& entry_instrs = entry_block->getInstructions();
|
auto& entry_instrs = entry_block->getInstructions();
|
||||||
// 插入点通常在函数入口标签之后
|
// 插入点在函数入口标签之后,或者就是最开始
|
||||||
auto insert_pos = entry_instrs.begin();
|
auto insert_pos = entry_instrs.begin();
|
||||||
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
|
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
|
||||||
insert_pos = std::next(insert_pos);
|
insert_pos = std::next(insert_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为了布局确定性,对寄存器进行排序并按序保存
|
|
||||||
std::vector<PhysicalReg> sorted_int_regs(used_int_callee_saved.begin(), used_int_callee_saved.end());
|
|
||||||
std::vector<PhysicalReg> sorted_fp_regs(used_fp_callee_saved.begin(), used_fp_callee_saved.end());
|
|
||||||
std::sort(sorted_int_regs.begin(), sorted_int_regs.end());
|
|
||||||
std::sort(sorted_fp_regs.begin(), sorted_fp_regs.end());
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<MachineInstr>> save_instrs;
|
std::vector<std::unique_ptr<MachineInstr>> save_instrs;
|
||||||
int current_offset = -16; // ra和s0已占用-8和-16,从-24开始分配
|
// [关键] 从局部变量区域之后开始分配空间
|
||||||
|
int current_offset = - (16 + frame_info.locals_size);
|
||||||
|
|
||||||
// 准备整数保存指令 (sd)
|
for (PhysicalReg reg : sorted_regs) {
|
||||||
for (PhysicalReg reg : sorted_int_regs) {
|
|
||||||
current_offset -= 8;
|
current_offset -= 8;
|
||||||
auto sd = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
RVOpcodes save_op = is_fp_reg(reg) ? RVOpcodes::FSD : RVOpcodes::SD;
|
||||||
sd->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
sd->addOperand(std::make_unique<MemOperand>(
|
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<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
std::make_unique<ImmOperand>(current_offset)
|
||||||
));
|
));
|
||||||
save_instrs.push_back(std::move(sd));
|
save_instrs.push_back(std::move(save_instr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备浮点保存指令 (fsd)
|
|
||||||
for (PhysicalReg reg : sorted_fp_regs) {
|
|
||||||
current_offset -= 8;
|
|
||||||
auto fsd = std::make_unique<MachineInstr>(RVOpcodes::FSD); // 使用浮点保存指令
|
|
||||||
fsd->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
fsd->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
|
||||||
));
|
|
||||||
save_instrs.push_back(std::move(fsd));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一次性插入所有保存指令
|
|
||||||
if (!save_instrs.empty()) {
|
if (!save_instrs.empty()) {
|
||||||
entry_instrs.insert(insert_pos,
|
entry_instrs.insert(insert_pos,
|
||||||
std::make_move_iterator(save_instrs.begin()),
|
std::make_move_iterator(save_instrs.begin()),
|
||||||
@@ -118,40 +102,27 @@ void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
|||||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||||
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
||||||
current_offset = -16; // 重置偏移量用于恢复
|
// [关键] 使用与保存时完全相同的逻辑来计算偏移量
|
||||||
|
current_offset = - (16 + frame_info.locals_size);
|
||||||
|
|
||||||
// 准备恢复整数寄存器 (ld) - 以与保存时相同的顺序
|
for (PhysicalReg reg : sorted_regs) {
|
||||||
for (PhysicalReg reg : sorted_int_regs) {
|
|
||||||
current_offset -= 8;
|
current_offset -= 8;
|
||||||
auto ld = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
RVOpcodes restore_op = is_fp_reg(reg) ? RVOpcodes::FLD : RVOpcodes::LD;
|
||||||
ld->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
ld->addOperand(std::make_unique<MemOperand>(
|
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<RegOperand>(PhysicalReg::S0),
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
std::make_unique<ImmOperand>(current_offset)
|
||||||
));
|
));
|
||||||
restore_instrs.push_back(std::move(ld));
|
restore_instrs.push_back(std::move(restore_instr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备恢复浮点寄存器 (fld)
|
|
||||||
for (PhysicalReg reg : sorted_fp_regs) {
|
|
||||||
current_offset -= 8;
|
|
||||||
auto fld = std::make_unique<MachineInstr>(RVOpcodes::FLD); // 使用浮点加载指令
|
|
||||||
fld->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
fld->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
|
||||||
));
|
|
||||||
restore_instrs.push_back(std::move(fld));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一次性插入所有恢复指令
|
|
||||||
if (!restore_instrs.empty()) {
|
if (!restore_instrs.empty()) {
|
||||||
mbb->getInstructions().insert(it,
|
mbb->getInstructions().insert(it,
|
||||||
std::make_move_iterator(restore_instrs.begin()),
|
std::make_move_iterator(restore_instrs.begin()),
|
||||||
std::make_move_iterator(restore_instrs.end()));
|
std::make_move_iterator(restore_instrs.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理完一个基本块的RET后,迭代器已失效,需跳出当前块的循环
|
|
||||||
goto next_block_label;
|
goto next_block_label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ std::string RISCv64CodeGen::code_gen() {
|
|||||||
return module_gen();
|
return module_gen();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模块级代码生成
|
|
||||||
std::string RISCv64CodeGen::module_gen() {
|
std::string RISCv64CodeGen::module_gen() {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
// --- 步骤1:将全局变量分为.data和.bss两组 ---
|
// --- 步骤1:将全局变量(GlobalValue)分为.data和.bss两组 ---
|
||||||
std::vector<GlobalValue*> data_globals;
|
std::vector<GlobalValue*> data_globals;
|
||||||
std::vector<GlobalValue*> bss_globals;
|
std::vector<GlobalValue*> bss_globals;
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ std::string RISCv64CodeGen::module_gen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 步骤2:生成 .bss 段的代码 ---
|
// --- 步骤2:生成 .bss 段的代码 (这部分不变) ---
|
||||||
if (!bss_globals.empty()) {
|
if (!bss_globals.empty()) {
|
||||||
ss << ".bss\n";
|
ss << ".bss\n";
|
||||||
for (GlobalValue* global : bss_globals) {
|
for (GlobalValue* global : bss_globals) {
|
||||||
@@ -57,9 +56,12 @@ std::string RISCv64CodeGen::module_gen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 步骤3:生成 .data 段的代码 ---
|
// --- [修改] 步骤3:生成 .data 段的代码 ---
|
||||||
if (!data_globals.empty()) {
|
// 我们需要检查 data_globals 和 常量列表是否都为空
|
||||||
ss << ".data\n"; // 切换到 .data 段
|
if (!data_globals.empty() || !module->getConsts().empty()) {
|
||||||
|
ss << ".data\n";
|
||||||
|
|
||||||
|
// a. 先处理普通的全局变量 (GlobalValue)
|
||||||
for (GlobalValue* global : data_globals) {
|
for (GlobalValue* global : data_globals) {
|
||||||
ss << ".globl " << global->getName() << "\n";
|
ss << ".globl " << global->getName() << "\n";
|
||||||
ss << global->getName() << ":\n";
|
ss << global->getName() << ":\n";
|
||||||
@@ -106,7 +108,7 @@ std::string RISCv64CodeGen::module_gen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 处理函数 (.text段) ---
|
// --- 处理函数 (.text段) 的逻辑保持不变 ---
|
||||||
if (!module->getFunctions().empty()) {
|
if (!module->getFunctions().empty()) {
|
||||||
ss << ".text\n";
|
ss << ".text\n";
|
||||||
for (const auto& func_pair : module->getFunctions()) {
|
for (const auto& func_pair : module->getFunctions()) {
|
||||||
|
|||||||
@@ -165,10 +165,6 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
|||||||
*/
|
*/
|
||||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||||
// 初始偏移量,为保存ra和s0留出空间。
|
|
||||||
// 假设序言是 addi sp, sp, -stack_size; sd ra, stack_size-8(sp); sd s0, stack_size-16(sp);
|
|
||||||
int current_offset = 16;
|
|
||||||
|
|
||||||
Function* F = MFunc->getFunc();
|
Function* F = MFunc->getFunc();
|
||||||
RISCv64ISel* isel = MFunc->getISel();
|
RISCv64ISel* isel = MFunc->getISel();
|
||||||
|
|
||||||
@@ -190,12 +186,15 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理局部变量
|
// [关键修改] 为局部变量分配空间时,起始点必须考虑为ra, s0以及所有callee-saved寄存器预留的空间。
|
||||||
// 遍历AllocaInst来计算局部变量所需的总空间
|
// 布局顺序为: [s0/ra, 16字节] -> [callee-saved, callee_saved_size字节] -> [局部变量...]
|
||||||
|
int local_var_offset = 16 + frame_info.callee_saved_size;
|
||||||
|
int locals_start_offset = local_var_offset; // 记录局部变量区域的起始点,用于计算总大小
|
||||||
|
|
||||||
|
// 处理局部变量 (AllocaInst)
|
||||||
for (auto& bb : F->getBasicBlocks()) {
|
for (auto& bb : F->getBasicBlocks()) {
|
||||||
for (auto& inst : bb->getInstructions()) {
|
for (auto& inst : bb->getInstructions()) {
|
||||||
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||||
// 获取Alloca指令指向的类型 (例如 alloca i32* 中,获取 i32)
|
|
||||||
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
||||||
int size = getTypeSizeInBytes(allocated_type);
|
int size = getTypeSizeInBytes(allocated_type);
|
||||||
|
|
||||||
@@ -203,14 +202,17 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
|||||||
size = (size + 7) & ~7;
|
size = (size + 7) & ~7;
|
||||||
if (size == 0) size = 8; // 至少分配8字节
|
if (size == 0) size = 8; // 至少分配8字节
|
||||||
|
|
||||||
current_offset += size;
|
local_var_offset += size;
|
||||||
unsigned alloca_vreg = isel->getVReg(alloca);
|
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||||
// 局部变量使用相对于s0的负向偏移
|
// 局部变量使用相对于s0的负向偏移
|
||||||
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
|
frame_info.alloca_offsets[alloca_vreg] = -local_var_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame_info.locals_size = current_offset;
|
|
||||||
|
// [修复] 正确计算并设置locals_size
|
||||||
|
// 它只应该包含由AllocaInst分配的局部变量的总大小。
|
||||||
|
frame_info.locals_size = local_var_offset - locals_start_offset;
|
||||||
|
|
||||||
// 遍历所有机器指令,将伪指令展开为真实指令
|
// 遍历所有机器指令,将伪指令展开为真实指令
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ struct StackFrameInfo {
|
|||||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||||
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
||||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
|
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
|
||||||
|
std::vector<PhysicalReg> callee_saved_regs; // 用于存储需要保存的被调用者保存寄存器列表
|
||||||
};
|
};
|
||||||
|
|
||||||
// 机器函数
|
// 机器函数
|
||||||
|
|||||||
Reference in New Issue
Block a user