[backend]解决了栈地址计算对齐逻辑错误的问题

This commit is contained in:
Lixuanwang
2025-08-16 18:31:45 +08:00
parent 072cd3e9b5
commit 5ef01ada90

View File

@ -14,26 +14,26 @@ namespace sysy {
RISCv64SimpleRegAlloc::RISCv64SimpleRegAlloc(MachineFunction* mfunc) : MFunc(mfunc), ISel(mfunc->getISel()) {
// 1. 初始化可分配的整数寄存器池
// 保留 t0, t1 用于其他目的, t2, t3, t4 作为溢出寄存器
// T5 被大立即数传送逻辑保留
// T2, T3, T4 被本分配器保留为专用的溢出/临时寄存器
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6,
PhysicalReg::T0, PhysicalReg::T1, /* T2,T3,T4,T5 reserved */ PhysicalReg::T6,
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3, PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3, PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 2. 初始化可分配的浮点寄存器池
// 保留 f4 作为溢出寄存器
// F0, F1, F2 被本分配器保留为专用的溢出/临时寄存器
allocable_fp_regs = {
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3, /* F4保留 */ PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
/* F0,F1,F2 reserved */ PhysicalReg::F3, PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13, PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
PhysicalReg::F8, PhysicalReg::F9, PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21, PhysicalReg::F22,
PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25, PhysicalReg::F26, PhysicalReg::F27,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
};
// 3. 映射所有物理寄存器(包括整数、浮点和特殊寄存器)到特殊的虚拟寄存器ID
// 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器
// 3. 映射所有物理寄存器到特殊的虚拟寄存器ID (保持不变)
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
for (unsigned i = 0; i < static_cast<unsigned>(PhysicalReg::INVALID); ++i) {
auto preg = static_cast<PhysicalReg>(i);
@ -49,6 +49,12 @@ void RISCv64SimpleRegAlloc::run() {
RISCv64AsmPrinter printer(MFunc);
printer.setStream(std::cerr);
if (DEBUG) {
std::cerr << "\n===== LLIR after VReg Unification =====\n";
printer.run(std::cerr, true);
std::cerr << "===== End of Unified LLIR =====\n\n";
}
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
if (DEBUG) {
@ -494,58 +500,109 @@ void RISCv64SimpleRegAlloc::rewriteFunction() {
if (DEBUG) std::cerr << "\n--- Starting Function Rewrite (Spilling & Substitution) ---\n";
StackFrameInfo& frame_info = MFunc->getFrameInfo();
// 1. 为所有溢出的vreg计算栈偏移量
// 溢出区域紧跟在局部变量区域之后
// 步骤 1: 为所有溢出的vreg计算唯一的栈偏移量
int current_offset = frame_info.locals_end_offset;
for (unsigned vreg : spilled_vregs) {
if (frame_info.spill_offsets.count(vreg)) continue; // 避免重复分配
auto [type, size] = getTypeAndSize(vreg);
// 按变量大小对齐
current_offset -= size;
current_offset = current_offset & -size;
current_offset = current_offset & ~7;
frame_info.spill_offsets[vreg] = current_offset;
}
// 更新总的溢出区域大小
frame_info.spill_size = -(current_offset - frame_info.locals_end_offset);
// 2. 插入加载/存储指令
// 步骤 2: 遍历所有指令,插入加载/存储并替换所有虚拟寄存器
for (auto& mbb : MFunc->getBlocks()) {
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
LiveSet use, def;
getInstrUseDef(instr_ptr.get(), use, def); // 这里用不含物理寄存器的版本
// 为本条指令动态管理可用的专用溢出寄存器
std::vector<PhysicalReg> int_spill_pool = {PhysicalReg::T2, PhysicalReg::T3, PhysicalReg::T4};
std::vector<PhysicalReg> fp_spill_pool = {PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2};
// 映射: <vreg, 在本指令中代表它的物理寄存器>
std::map<unsigned, PhysicalReg> vreg_to_preg_map_for_this_instr;
// a. 为溢出的 'use' 操作数插入加载指令
LiveSet use, def;
getInstrUseDef(instr_ptr.get(), use, def);
// a. 预处理:为本指令所有 vreg 操作数确定其最终的物理寄存器
LiveSet all_vregs_in_instr = use;
all_vregs_in_instr.insert(def.begin(), def.end());
for(unsigned vreg : all_vregs_in_instr) {
if (color_map.count(vreg)) {
// 情况1: VReg 已成功着色
vreg_to_preg_map_for_this_instr[vreg] = color_map.at(vreg);
} else if (spilled_vregs.count(vreg)) {
// 情况2: VReg 被溢出, 从池中分配一个专用寄存器
auto [type, size] = getTypeAndSize(vreg);
if (type == Type::kFloat) {
assert(!fp_spill_pool.empty() && "FP spill pool exhausted!");
vreg_to_preg_map_for_this_instr[vreg] = fp_spill_pool.front();
fp_spill_pool.erase(fp_spill_pool.begin());
} else {
assert(!int_spill_pool.empty() && "Int spill pool exhausted!");
vreg_to_preg_map_for_this_instr[vreg] = int_spill_pool.front();
int_spill_pool.erase(int_spill_pool.begin());
}
}
}
// b. 为所有溢出的 use vreg 生成加载指令
for (unsigned vreg : use) {
if (spilled_vregs.count(vreg)) {
PhysicalReg target_preg = vreg_to_preg_map_for_this_instr.at(vreg);
auto [type, size] = getTypeAndSize(vreg);
RVOpcodes load_op;
PhysicalReg target_preg;
if (type == Type::kFloat) { load_op = RVOpcodes::FLW; target_preg = FP_SPILL_REG; }
else if (type == Type::kPointer) { load_op = RVOpcodes::LD; target_preg = PTR_SPILL_REG; }
else { load_op = RVOpcodes::LW; target_preg = INT_SPILL_REG; }
RVOpcodes load_op = (type == Type::kFloat) ? RVOpcodes::FLW : ((type == Type::kPointer) ? RVOpcodes::LD : RVOpcodes::LW);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(target_preg));
load->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(frame_info.spill_offsets.at(vreg))
));
new_instructions.push_back(std::move(load));
}
}
// c. 克隆并用物理寄存器重写原始指令
auto new_instr = std::make_unique<MachineInstr>(instr_ptr->getOpcode());
for (const auto& op : instr_ptr->getOperands()) {
const RegOperand* reg_op = nullptr;
if (op->getKind() == MachineOperand::KIND_REG) reg_op = static_cast<const RegOperand*>(op.get());
else if (op->getKind() == MachineOperand::KIND_MEM) reg_op = static_cast<const MemOperand*>(op.get())->getBase();
// b. 放入原始指令
new_instructions.push_back(std::move(instr_ptr));
if (reg_op) { // 是寄存器或内存操作数
PhysicalReg final_preg;
if (reg_op->isVirtual()) {
// vreg必须在预处理的map中或者在color_map中
assert(vreg_to_preg_map_for_this_instr.count(reg_op->getVRegNum()) || color_map.count(reg_op->getVRegNum()));
final_preg = vreg_to_preg_map_for_this_instr.count(reg_op->getVRegNum()) ? vreg_to_preg_map_for_this_instr.at(reg_op->getVRegNum()) : color_map.at(reg_op->getVRegNum());
} else {
final_preg = reg_op->getPReg();
}
auto new_reg_op = std::make_unique<RegOperand>(final_preg);
// c. 为溢出的 'def' 操作数插入存储指令
if (op->getKind() == MachineOperand::KIND_REG) {
new_instr->addOperand(std::move(new_reg_op));
} else {
auto mem_op = static_cast<const MemOperand*>(op.get());
new_instr->addOperand(std::make_unique<MemOperand>(std::move(new_reg_op), std::make_unique<ImmOperand>(*mem_op->getOffset())));
}
} else { // 非寄存器操作数 (立即数、标签)
if(op->getKind() == MachineOperand::KIND_IMM) new_instr->addOperand(std::make_unique<ImmOperand>(*static_cast<const ImmOperand*>(op.get())));
else if (op->getKind() == MachineOperand::KIND_LABEL) new_instr->addOperand(std::make_unique<LabelOperand>(*static_cast<const LabelOperand*>(op.get())));
}
}
new_instructions.push_back(std::move(new_instr));
// d. 为所有溢出的 def vreg 生成存储指令
for (unsigned vreg : def) {
if (spilled_vregs.count(vreg)) {
PhysicalReg src_preg = vreg_to_preg_map_for_this_instr.at(vreg);
auto [type, size] = getTypeAndSize(vreg);
RVOpcodes store_op;
PhysicalReg src_preg;
if (type == Type::kFloat) { store_op = RVOpcodes::FSW; src_preg = FP_SPILL_REG; }
else if (type == Type::kPointer) { store_op = RVOpcodes::SD; src_preg = PTR_SPILL_REG; }
else { store_op = RVOpcodes::SW; src_preg = INT_SPILL_REG; }
RVOpcodes store_op = (type == Type::kFloat) ? RVOpcodes::FSW : ((type == Type::kPointer) ? RVOpcodes::SD : RVOpcodes::SW);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(src_preg));
@ -559,26 +616,6 @@ void RISCv64SimpleRegAlloc::rewriteFunction() {
}
mbb->getInstructions() = std::move(new_instructions);
}
// 3. 最后,将所有指令中的虚拟寄存器替换为物理寄存器
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr_ptr : mbb->getInstructions()) {
instr_ptr->replaceVRegWithPReg(0, PhysicalReg::ZERO); // 保底处理
// 为已着色的vreg替换
for(const auto& color_pair : color_map) {
instr_ptr->replaceVRegWithPReg(color_pair.first, color_pair.second);
}
// 为溢出的vreg替换
for (unsigned vreg : spilled_vregs) {
auto [type, size] = getTypeAndSize(vreg);
PhysicalReg spill_preg;
if (type == Type::kFloat) spill_preg = FP_SPILL_REG;
else if (type == Type::kPointer) spill_preg = PTR_SPILL_REG;
else spill_preg = INT_SPILL_REG;
instr_ptr->replaceVRegWithPReg(vreg, spill_preg);
}
}
}
}
// --- 辅助函数实现 ---