Files
mysysy/src/backend/RISCv64/RISCv64RegAlloc.cpp

1010 lines
47 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "RISCv64RegAlloc.h"
#include "RISCv64ISel.h"
#include "RISCv64AsmPrinter.h" // For DEBUG output
#include "LegalizeImmediates.h"
#include <algorithm>
#include <vector>
#include <iostream> // For DEBUG output
#include <cassert> // For assert
namespace sysy {
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
// 1. 初始化可分配的整数寄存器池
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, /*PhysicalReg::T5,*/ PhysicalReg::T6, // T5是大立即数传送寄存器
PhysicalReg::A0, PhysicalReg::A1, PhysicalReg::A2, PhysicalReg::A3,
PhysicalReg::A4, PhysicalReg::A5, PhysicalReg::A6, PhysicalReg::A7,
PhysicalReg::S0, PhysicalReg::S1, PhysicalReg::S2, PhysicalReg::S3,
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
};
// 2. 初始化可分配的浮点寄存器池
allocable_fp_regs = {
// 浮点临时寄存器 ft0-ft11
PhysicalReg::F0, PhysicalReg::F1, PhysicalReg::F2, PhysicalReg::F3,
PhysicalReg::F4, PhysicalReg::F5, PhysicalReg::F6, PhysicalReg::F7,
PhysicalReg::F28, PhysicalReg::F29, PhysicalReg::F30, PhysicalReg::F31,
// 浮点参数/返回值寄存器 fa0-fa7
PhysicalReg::F10, PhysicalReg::F11, PhysicalReg::F12, PhysicalReg::F13,
PhysicalReg::F14, PhysicalReg::F15, PhysicalReg::F16, PhysicalReg::F17,
// 浮点保存寄存器 fs0-fs11
PhysicalReg::F8, PhysicalReg::F9,
PhysicalReg::F18, PhysicalReg::F19, PhysicalReg::F20, PhysicalReg::F21,
PhysicalReg::F22, PhysicalReg::F23, PhysicalReg::F24, PhysicalReg::F25,
PhysicalReg::F26, PhysicalReg::F27
};
// 3. 映射所有物理寄存器包括整数、浮点和特殊寄存器到特殊的虚拟寄存器ID
// 这是为了让活跃性分析和干扰图构建能够统一处理所有类型的寄存器
for (int i = 0; i < static_cast<int>(PhysicalReg::PHYS_REG_START_ID); ++i) {
auto preg = static_cast<PhysicalReg>(i);
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + i;
}
}
// 寄存器分配的主入口点
void RISCv64RegAlloc::run() {
// --- 在所有流程开始前构建完整的vreg到Value的反向映射 ---
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
for (const auto& pair : vreg_map_from_isel) {
Value* val = pair.first;
unsigned vreg = pair.second;
vreg_to_value_map[vreg] = val;
}
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
eliminateFrameIndices();
// 调试输出当前的LLIR状态
{ // 使用大括号创建一个局部作用域避免printer变量泄露
if (DEBUG) {
std::cerr << "\n===== LLIR after eliminateFrameIndices for function: "
<< MFunc->getName() << " =====\n";
// 1. 创建一个 AsmPrinter 实例,传入当前的 MachineFunction
RISCv64AsmPrinter printer(MFunc);
// 2. 调用 run 方法,将结果打印到标准错误流 (std::cerr)
// 3. 必须将 debug 参数设为 true
// 因为此时指令中仍然包含虚拟寄存器 (%vreg)
// debug模式下的 AsmPrinter 才能正确处理它们而不会报错。
printer.run(std::cerr, true);
std::cerr << "===== End of LLIR =====\n\n";
}
}
// 阶段 3: 活跃性分析
analyzeLiveness();
// 阶段 4: 构建干扰图包含CALL指令对调用者保存寄存器的影响
buildInterferenceGraph();
// 阶段 5: 图着色算法分配物理寄存器
colorGraph();
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
rewriteFunction();
// 将最终的寄存器分配结果保存到MachineFunction的帧信息中供后续Pass使用
MFunc->getFrameInfo().vreg_to_preg_map = this->color_map;
}
/**
* @brief 处理调用约定,预先为函数参数和调用返回值分配物理寄存器。
* 这个函数现在负责处理调用约定的两个方面:
* 1. 作为被调用者(callee),如何接收传入的参数。
* 2. 作为调用者(caller),如何接收调用的其他函数的返回值。
*/
void RISCv64RegAlloc::handleCallingConvention() {
Function* F = MFunc->getFunc();
RISCv64ISel* isel = MFunc->getISel();
// --- 部分1处理函数传入参数的预着色 ---
if (F) {
auto& args = F->getArguments();
// [修改] 为整数参数和浮点参数分别维护索引
int int_arg_idx = 0;
int float_arg_idx = 0;
for (Argument* arg : args) {
// [修改] 根据参数类型决定使用哪个寄存器池和索引
if (arg->getType()->isFloat()) {
// --- 处理浮点参数 ---
if (float_arg_idx >= 8) continue; // fa0-fa7
unsigned vreg = isel->getVReg(arg);
// 浮点参数使用 fa10-fa17 (在RISC-V ABI中对应F10-F17)
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::F10) + float_arg_idx);
color_map[vreg] = preg;
float_arg_idx++;
} else {
// --- 处理整数/指针参数 (原有逻辑) ---
if (int_arg_idx >= 8) continue; // a0-a7
unsigned vreg = isel->getVReg(arg);
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + int_arg_idx);
color_map[vreg] = preg;
int_arg_idx++;
}
}
}
// --- 部分2为CALL指令的返回值预着色 ---
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
if (instr->getOpcode() == RVOpcodes::CALL) {
// 根据协议如果CALL有返回值其目标vreg是第一个操作数
if (!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG)
{
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (reg_op->isVirtual()) {
unsigned ret_vreg = reg_op->getVRegNum();
// [修改] 检查返回值的类型,预着色到 a0 或 fa0
assert(MFunc->getISel()->getVRegValueMap().count(ret_vreg) && "Return vreg not found in value map!");
Value* ret_val = MFunc->getISel()->getVRegValueMap().at(ret_vreg);
if (ret_val->getType()->isFloat()) {
// 浮点返回值预着色到 fa0 (F10)
color_map[ret_vreg] = PhysicalReg::F10;
} else {
// 整数/指针返回值预着色到 a0
color_map[ret_vreg] = PhysicalReg::A0;
}
}
}
}
}
}
}
/**
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
*/
void RISCv64RegAlloc::eliminateFrameIndices() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
Function* F = MFunc->getFunc();
RISCv64ISel* isel = MFunc->getISel();
// 在处理局部变量前,首先为栈参数计算偏移量。
if (F) {
int arg_idx = 0;
for (Argument* arg : F->getArguments()) {
// 我们只关心第8个索引及之后的参数即第9个参数开始
if (arg_idx >= 8) {
// 计算偏移量:第一个栈参数(idx=8)在0(s0),第二个(idx=9)在8(s0),以此类推。
int offset = (arg_idx - 8) * 8;
unsigned vreg = isel->getVReg(arg);
// 将这个vreg和它的栈偏移存入map。
// 我们可以复用alloca_offsets因为它们都代表“vreg到栈偏移”的映射。
frame_info.alloca_offsets[vreg] = offset;
}
arg_idx++;
}
}
// [关键修改] 为局部变量分配空间时起始点必须考虑为ra, s0以及所有callee-saved寄存器预留的空间。
// 布局顺序为: [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& 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;
}
}
}
// [修复] 正确计算并设置locals_size
// 它只应该包含由AllocaInst分配的局部变量的总大小。
frame_info.locals_size = local_var_offset - locals_start_offset;
// 遍历所有机器指令,将伪指令展开为真实指令
for (auto& mbb : MFunc->getBlocks()) {
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
for (auto& instr_ptr : mbb->getInstructions()) {
RVOpcodes opcode = instr_ptr->getOpcode();
// --- MODIFICATION START: 处理区分宽度的伪指令 ---
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D) {
// 确定要生成的真实加载指令是 lw 还是 ld
RVOpcodes real_load_op = (opcode == RVOpcodes::FRAME_LOAD_W) ? RVOpcodes::LW : RVOpcodes::LD;
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();
// 展开为: 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 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_LOAD_F) {
// 展开浮点加载伪指令
RVOpcodes real_load_op = RVOpcodes::FLW; // 对应的真实指令是 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();
// 展开为: 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));
// 展开为: 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) {
// 确定要生成的真实存储指令是 sw 还是 sd
RVOpcodes real_store_op = (opcode == RVOpcodes::FRAME_STORE_W) ? RVOpcodes::SW : RVOpcodes::SD;
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();
// 展开为: 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 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 (opcode == RVOpcodes::FRAME_STORE_F) {
// 展开浮点存储伪指令
RVOpcodes real_store_op = RVOpcodes::FSW; // 对应的真实指令是 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();
// 展开为: 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));
// 展开为: 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));
}
// --- MODIFICATION END ---
}
mbb->getInstructions() = std::move(new_instructions);
}
}
/**
* @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。
* 这是活跃性分析的基础。
* @param instr 要分析的机器指令。
* @param use 存储 Use 寄存器(虚拟寄存器 ID的集合。
* @param def 存储 Def 寄存器(虚拟寄存器 ID的集合。
*/
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
auto opcode = instr->getOpcode();
if (opcode == RVOpcodes::PSEUDO_KEEPALIVE) {
for (auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) {
use.insert(reg_op->getVRegNum()); // 它的所有操作数都是 "use"
}
}
}
return; // 处理完毕
}
// 1. 特殊指令的 `is_def` 标志调整
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW ||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
first_reg_is_def = false;
}
// JAL 和 JALR 指令定义 ra (x1)
if (opcode == RVOpcodes::JAL || opcode == RVOpcodes::JALR) {
// 使用 ra 对应的特殊虚拟寄存器ID
def.insert(preg_to_vreg_id_map.at(PhysicalReg::RA));
first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra已经处理为 def
}
// 2. CALL 指令的特殊处理
if (opcode == RVOpcodes::CALL) {
// 根据 s1 分支 ISel 定义的协议来解析操作数列表
bool first_reg_operand_is_def = true;
for (auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) {
// 协议:第一个寄存器操作数是返回值 (def)
if (first_reg_operand_is_def) {
def.insert(reg_op->getVRegNum());
first_reg_operand_is_def = false;
} else {
// 后续所有寄存器操作数都是参数 (use)
use.insert(reg_op->getVRegNum());
}
} else { // [修复] CALL指令也可能定义物理寄存器如a0
if (first_reg_operand_is_def) {
auto it = preg_to_vreg_id_map.find(reg_op->getPReg());
if (it != preg_to_vreg_id_map.end()) {
def.insert(it->second);
}
first_reg_operand_is_def = false;
} else {
auto it = preg_to_vreg_id_map.find(reg_op->getPReg());
if (it != preg_to_vreg_id_map.end()) {
use.insert(it->second);
}
}
}
}
}
return; // CALL 指令处理完毕
}
// 2.1 浮点比较指令添加特殊规则
// 它们的源操作数是浮点寄存器,但目标操作数是整数寄存器
if (opcode == RVOpcodes::FEQ_S || opcode == RVOpcodes::FLT_S || opcode == RVOpcodes::FLE_S) {
auto& operands = instr->getOperands();
// Def: 第一个操作数 (整数vreg)
if (operands[0]->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(operands[0].get());
if(reg_op->isVirtual()) def.insert(reg_op->getVRegNum());
}
// Use: 第二、三个操作数 (浮点vreg)
if (operands[1]->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(operands[1].get());
if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum());
}
if (operands[2]->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(operands[2].get());
if(reg_op->isVirtual()) use.insert(reg_op->getVRegNum());
}
return; // 处理完毕
}
// 3. 对其他所有指令的通用处理逻辑 [已重构和修复]
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (first_reg_is_def) {
// --- 处理定义Def ---
if (reg_op->isVirtual()) {
def.insert(reg_op->getVRegNum());
} else { // 物理寄存器也可以是 Def
auto it = preg_to_vreg_id_map.find(reg_op->getPReg());
if (it != preg_to_vreg_id_map.end()) {
def.insert(it->second);
}
}
first_reg_is_def = false; // **关键**:处理完第一个寄存器后,立即更新标志
} else {
// --- 处理使用Use ---
if (reg_op->isVirtual()) {
use.insert(reg_op->getVRegNum());
} else { // 物理寄存器也可以是 Use
auto it = preg_to_vreg_id_map.find(reg_op->getPReg());
if (it != preg_to_vreg_id_map.end()) {
use.insert(it->second);
}
}
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
// 内存操作数的处理逻辑看起来是正确的
auto mem_op = static_cast<MemOperand*>(op.get());
auto base_reg = mem_op->getBase();
if (base_reg->isVirtual()) {
use.insert(base_reg->getVRegNum());
} else {
PhysicalReg preg = base_reg->getPReg();
auto it = preg_to_vreg_id_map.find(preg);
if (it != preg_to_vreg_id_map.end()) {
use.insert(it->second);
}
}
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD || opcode == RVOpcodes::FSW) &&
!instr->getOperands().empty() &&
instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
auto src_reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
if (src_reg_op->isVirtual()) {
use.insert(src_reg_op->getVRegNum());
} else {
auto it = preg_to_vreg_id_map.find(src_reg_op->getPReg());
if (it != preg_to_vreg_id_map.end()) {
use.insert(it->second);
}
}
}
}
}
}
/**
* @brief 计算一个类型在内存中占用的字节数。
* @param type 需要计算大小的IR类型。
* @return 该类型占用的字节数。
*/
unsigned RISCv64RegAlloc::getTypeSizeInBytes(Type* type) {
if (!type) {
assert(false && "Cannot get size of a null type.");
return 0;
}
switch (type->getKind()) {
// 对于SysY语言基本类型int和float都占用4字节
case Type::kInt:
case Type::kFloat:
return 4;
// 指针类型在RISC-V 64位架构下占用8字节
// 虽然SysY没有'int*'语法但数组变量在IR层面本身就是指针类型
case Type::kPointer:
return 8;
// 数组类型的总大小 = 元素数量 * 单个元素的大小
case Type::kArray: {
auto arrayType = type->as<ArrayType>();
// 递归调用以计算元素大小
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
}
// 其他类型如Void, Label等不占用栈空间或者不应该出现在这里
default:
// 如果遇到未处理的类型,触发断言,方便调试
assert(false && "Unsupported type for size calculation.");
return 0;
}
}
void RISCv64RegAlloc::analyzeLiveness() {
// === 阶段 1: 预计算每个基本块的 use 和 def 集合 ===
// 这样可以避免在主循环中重复计算
std::map<MachineBasicBlock*, LiveSet> block_uses;
std::map<MachineBasicBlock*, LiveSet> block_defs;
for (auto& mbb_ptr : MFunc->getBlocks()) {
MachineBasicBlock* mbb = mbb_ptr.get();
LiveSet uses, defs;
for (auto& instr_ptr : mbb->getInstructions()) {
LiveSet instr_use, instr_def;
getInstrUseDef(instr_ptr.get(), instr_use, instr_def);
// use[B] = use[B] U (instr_use - def[B])
for (unsigned u : instr_use) {
if (defs.find(u) == defs.end()) {
uses.insert(u);
}
}
// def[B] = def[B] U instr_def
defs.insert(instr_def.begin(), instr_def.end());
}
block_uses[mbb] = uses;
block_defs[mbb] = defs;
}
// === 阶段 2: 在“块”粒度上进行迭代数据流分析,直到收敛 ===
std::map<MachineBasicBlock*, LiveSet> block_live_in;
std::map<MachineBasicBlock*, LiveSet> block_live_out;
bool changed = true;
while (changed) {
changed = false;
// 以逆后序遍历基本块,可以加速收敛,但简单的逆序对于大多数情况也有效
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
auto& mbb = *it;
// 2.1 计算 live_out[B] = U_{S in succ(B)} live_in[S]
LiveSet new_live_out;
for (auto succ : mbb->successors) {
new_live_out.insert(block_live_in[succ].begin(), block_live_in[succ].end());
}
// 2.2 计算 live_in[B] = use[B] U (live_out[B] - def[B])
LiveSet live_out_minus_def = new_live_out;
for (unsigned d : block_defs[mbb.get()]) {
live_out_minus_def.erase(d);
}
LiveSet new_live_in = block_uses[mbb.get()];
new_live_in.insert(live_out_minus_def.begin(), live_out_minus_def.end());
// 2.3 检查 live_in 和 live_out 是否变化,以判断是否达到不动点
if (block_live_out[mbb.get()] != new_live_out) {
changed = true;
block_live_out[mbb.get()] = new_live_out;
}
if (block_live_in[mbb.get()] != new_live_in) {
changed = true;
block_live_in[mbb.get()] = new_live_in;
}
}
}
// === 阶段 3: 进行一次指令粒度的遍历,填充最终的 live_in_map 和 live_out_map ===
// 此时块级别的活跃信息已经稳定,我们只需遍历一次即可
for (auto& mbb_ptr : MFunc->getBlocks()) {
MachineBasicBlock* mbb = mbb_ptr.get();
LiveSet live_out = block_live_out[mbb]; // 从已收敛的块级 live_out 开始
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
MachineInstr* instr = instr_it->get();
live_out_map[instr] = live_out;
LiveSet use, def;
getInstrUseDef(instr, use, def);
LiveSet live_in = use;
LiveSet diff = live_out;
for (auto vreg : def) {
diff.erase(vreg);
}
live_in.insert(diff.begin(), diff.end());
live_in_map[instr] = live_in;
// 更新 live_out为块内的上一条指令做准备
live_out = live_in;
}
}
}
// 辅助函数,用于清晰地打印寄存器集合。可以放在 .cpp 文件的顶部。
void RISCv64RegAlloc::printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os) {
os << " " << name << ": { ";
for (unsigned vreg : s) {
// 为了可读性将物理寄存器对应的特殊ID进行转换
if (vreg >= static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) {
os << "preg(" << (vreg - static_cast<unsigned>(sysy::PhysicalReg::PHYS_REG_START_ID)) << ") ";
} else {
os << "%vreg" << vreg << " ";
}
}
os << "}\n";
}
void RISCv64RegAlloc::buildInterferenceGraph() {
std::set<unsigned> all_vregs;
// 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID
for (auto& mbb : MFunc->getBlocks()) {
for(auto& instr : mbb->getInstructions()) {
LiveSet use, def;
getInstrUseDef(instr.get(), use, def);
for(auto u : use) all_vregs.insert(u);
for(auto d : def) all_vregs.insert(d);
}
}
// 添加所有物理寄存器对应的特殊虚拟寄存器ID到all_vregs作为干扰图节点
for (auto preg : allocable_int_regs) {
all_vregs.insert(preg_to_vreg_id_map.at(preg));
}
// 初始化干扰图邻接表
for (auto vreg : all_vregs) { interference_graph[vreg] = {}; }
// 创建一个临时的AsmPrinter用于打印指令方便调试
RISCv64AsmPrinter temp_printer(MFunc);
temp_printer.setStream(std::cerr);
for (auto& mbb : MFunc->getBlocks()) {
if (DEEPDEBUG) std::cerr << "--- Building Graph for Basic Block: " << mbb->getName() << " ---\n";
for (auto& instr_ptr : mbb->getInstructions()) {
MachineInstr* instr = instr_ptr.get();
if (DEEPDEBUG) {
// 打印当前正在处理的指令
std::cerr << " Instr: ";
temp_printer.printInstruction(instr, true); // 使用 true 来打印虚拟寄存器
}
LiveSet def, use;
getInstrUseDef(instr, use, def);
const LiveSet& live_out = live_out_map.at(instr);
// [新增调试逻辑] 打印所有相关的寄存器集合
if (DEEPDEBUG) {
printLiveSet(use, "Use ", std::cerr);
printLiveSet(def, "Def ", std::cerr);
printLiveSet(live_out, "Live_Out", std::cerr); // 这是我们最关心的信息
}
// 标准干扰图构建def 与 live_out 中的其他变量干扰
for (unsigned d : def) {
for (unsigned l : live_out) {
if (d != l) {
// [新增调试逻辑] 打印添加的干扰边及其原因
if (DEEPDEBUG && interference_graph[d].find(l) == interference_graph[d].end()) {
std::cerr << " Edge (Def-LiveOut): %vreg" << d << " <-> %vreg" << l << "\n";
}
interference_graph[d].insert(l);
interference_graph[l].insert(d);
}
}
}
// 所有在某一点上同时活跃的寄存器即live_out集合中的所有成员
// 它们之间必须两两互相干扰。
// 这会根据我们修正后的 liveness 信息在所有参数vreg之间构建一个完全图clique
std::vector<unsigned> live_out_vec(live_out.begin(), live_out.end());
for (size_t i = 0; i < live_out_vec.size(); ++i) {
for (size_t j = i + 1; j < live_out_vec.size(); ++j) {
unsigned u = live_out_vec[i];
unsigned v = live_out_vec[j];
if (DEEPDEBUG && interference_graph[u].find(v) == interference_graph[u].end()) {
std::cerr << " Edge (Live-Live): %vreg" << u << " <-> %vreg" << v << "\n";
}
interference_graph[u].insert(v);
interference_graph[v].insert(u);
}
}
// 在非move指令中def 与 use 互相干扰
if (instr->getOpcode() != RVOpcodes::MV) {
for (unsigned d : def) {
for (unsigned u : use) {
if (d != u) {
// [新增调试逻辑] 打印添加的干扰边及其原因
if (DEEPDEBUG && interference_graph[d].find(u) == interference_graph[d].end()) {
std::cerr << " Edge (Def-Use) : %vreg" << d << " <-> %vreg" << u << "\n";
}
interference_graph[d].insert(u);
interference_graph[u].insert(d);
}
}
}
}
// *** 处理 CALL 指令的隐式 def ***
if (instr->getOpcode() == RVOpcodes::CALL) {
// 你的原始CALL调试信息
if (DEEPDEBUG) {
std::string live_out_str;
for (unsigned vreg : live_out) {
live_out_str += "%vreg" + std::to_string(vreg) + " ";
}
std::cerr << "[DEEPDEBUG] buildInterferenceGraph: CALL instruction found. Live out set is: {"
<< live_out_str << "}" << std::endl;
}
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
// 辅助函数用于判断一个vreg是整数类型还是浮点类型
auto is_fp_vreg = [&](unsigned vreg) {
if (vreg_to_value_map.count(vreg)) {
return vreg_to_value_map.at(vreg)->getType()->isFloat();
}
// 对于ISel创建的、没有直接IR Value对应的临时vreg
// 默认其为整数类型。这是一个合理的兜底策略。
return false;
};
// --- 处理整数寄存器干扰 ---
const std::vector<PhysicalReg>& caller_saved_int_regs = getCallerSavedIntRegs();
for (PhysicalReg cs_reg : caller_saved_int_regs) {
// 确保物理寄存器在映射表中,我们已在构造函数中保证了这一点
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
for (unsigned live_vreg_out : live_out) {
// 只为整数vreg添加与整数preg的干扰
if (!is_fp_vreg(live_vreg_out)) {
if (cs_vreg_id != live_vreg_out) {
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
std::cerr << " Edge (CALL, Int): preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
}
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
}
}
// --- 处理浮点寄存器干扰 ---
const std::vector<PhysicalReg>& caller_saved_fp_regs = getCallerSavedFpRegs();
for (PhysicalReg cs_reg : caller_saved_fp_regs) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg);
for (unsigned live_vreg_out : live_out) {
// 只为浮点vreg添加与浮点preg的干扰
if (is_fp_vreg(live_vreg_out)) {
if (cs_vreg_id != live_vreg_out) {
// 添加与整数版本一致的调试代码
if (DEEPDEBUG && interference_graph[cs_vreg_id].find(live_vreg_out) == interference_graph[cs_vreg_id].end()) {
std::cerr << " Edge (CALL, FP): preg(" << static_cast<int>(cs_reg) << ") <-> %vreg" << live_vreg_out << "\n";
}
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
}
}
}
if (DEEPDEBUG) std::cerr << " ----------------\n";
}
}
}
void RISCv64RegAlloc::colorGraph() {
std::vector<unsigned> sorted_vregs;
for (auto const& [vreg, neighbors] : interference_graph) {
// 只为未预着色的虚拟寄存器排序和着色
if (color_map.find(vreg) == color_map.end() && vreg < static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
sorted_vregs.push_back(vreg);
}
}
// 排序
std::sort(sorted_vregs.begin(), sorted_vregs.end(), [&](unsigned a, unsigned b) {
return interference_graph[a].size() > interference_graph[b].size();
});
// [调试] 辅助函数用于判断一个vreg是整数还是浮点类型并打印详细诊断信息
auto is_fp_vreg = [&](unsigned vreg) {
if (DEEPDEBUG) {
std::cout << " [Debug is_fp_vreg] Checking vreg" << vreg << ": ";
}
if (vreg_to_value_map.count(vreg)) {
Value* val = vreg_to_value_map.at(vreg);
bool is_float = val->getType()->isFloat();
if (DEEPDEBUG) {
std::cout << "Found in map. Value is '" << val->getName()
<< "', Type is " << (is_float ? "FLOAT" : "INT")
<< ". Returning " << (is_float ? "true" : "false") << ".\n";
}
return is_float;
}
if (DEEPDEBUG) {
std::cout << "NOT found in vreg_to_value_map. Defaulting to INT. Returning false.\n";
}
// 对于ISel创建的、没有直接IR Value对应的临时vreg默认其为整数类型。
return false;
};
// 着色
for (unsigned vreg : sorted_vregs) {
std::set<PhysicalReg> used_colors;
for (unsigned neighbor_id : interference_graph.at(vreg)) {
// 收集邻居颜色的逻辑保持不变
if (color_map.count(neighbor_id)) {
used_colors.insert(color_map.at(neighbor_id));
}
else if (neighbor_id >= static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID)) {
PhysicalReg neighbor_preg = static_cast<PhysicalReg>(neighbor_id - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID));
used_colors.insert(neighbor_preg);
}
}
bool is_float = is_fp_vreg(vreg);
const auto& allocable_regs = is_float ? allocable_fp_regs : allocable_int_regs;
// [调试] 打印着色决策过程
if (DEBUG) {
std::cout << "[DEBUG] Coloring %vreg" << vreg
<< ": Type is " << (is_float ? "FLOAT" : "INT")
<< ", choosing from " << (is_float ? "Float" : "Integer") << " pool.\n";
}
bool colored = false;
for (PhysicalReg preg : allocable_regs) {
if (used_colors.find(preg) == used_colors.end()) {
color_map[vreg] = preg;
colored = true;
if (DEBUG) {
RISCv64AsmPrinter p(MFunc); // For regToString
std::cout << " -> Assigned to physical register: " << p.regToString(preg) << "\n";
}
break;
}
}
if (!colored) {
spilled_vregs.insert(vreg);
if (DEBUG) {
std::cout << " -> FAILED to color. Spilling.\n";
}
}
}
}
void RISCv64RegAlloc::rewriteFunction() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = frame_info.locals_size;
// --- 动态计算溢出槽大小 ---
// 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。
for (unsigned vreg : spilled_vregs) {
// 从反向映射中查找 vreg 对应的 IR Value
assert(vreg_to_value_map.count(vreg) && "Spilled vreg not found in map!");
Value* val = vreg_to_value_map.at(vreg);
// 使用辅助函数获取类型大小
int size = getTypeSizeInBytes(val->getType());
// 保持栈8字节对齐
current_offset += size;
current_offset = (current_offset + 7) & ~7;
frame_info.spill_offsets[vreg] = -current_offset;
}
frame_info.spill_size = current_offset - frame_info.locals_size;
// 定义专用的溢出寄存器
const PhysicalReg INT_SPILL_REG = PhysicalReg::T6; // t6
const PhysicalReg FP_SPILL_REG = PhysicalReg::F7; // ft7
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);
// --- 为溢出的 'use' 操作数插入正确的加载指令 ---
for (unsigned vreg : use) {
if (spilled_vregs.count(vreg)) {
// 同样地,根据 vreg 的类型决定使用 lw 还是 ld
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
// 根据vreg类型决定加载指令(lw/ld/flw)和目标物理寄存器(t6/ft7)
RVOpcodes load_op;
PhysicalReg target_preg;
if (val->getType()->isFloat()) {
load_op = RVOpcodes::FLW;
target_preg = FP_SPILL_REG;
} else if (val->getType()->isPointer()) {
load_op = RVOpcodes::LD;
target_preg = INT_SPILL_REG;
} else {
load_op = RVOpcodes::LW;
target_preg = INT_SPILL_REG;
}
int offset = frame_info.spill_offsets.at(vreg);
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<ImmOperand>(offset)
));
new_instructions.push_back(std::move(load));
}
}
new_instructions.push_back(std::move(instr_ptr));
// --- 为溢出的 'def' 操作数插入正确的存储指令 ---
for (unsigned vreg : def) {
if (spilled_vregs.count(vreg)) {
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
// 根据vreg类型决定存储指令(sw/sd/fsw)和源物理寄存器(t6/ft7)
RVOpcodes store_op;
PhysicalReg src_preg;
if (val->getType()->isFloat()) {
store_op = RVOpcodes::FSW;
src_preg = FP_SPILL_REG;
} else if (val->getType()->isPointer()) {
store_op = RVOpcodes::SD;
src_preg = INT_SPILL_REG;
} else {
store_op = RVOpcodes::SW;
src_preg = INT_SPILL_REG;
}
int offset = frame_info.spill_offsets.at(vreg);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(src_preg)); // 从专用溢出寄存器存储
store->addOperand(std::make_unique<MemOperand>(
std::make_unique<RegOperand>(PhysicalReg::S0),
std::make_unique<ImmOperand>(offset)
));
new_instructions.push_back(std::move(store));
}
}
}
mbb->getInstructions() = std::move(new_instructions);
}
// 最后的虚拟寄存器到物理寄存器的替换过程保持不变
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr_ptr : mbb->getInstructions()) {
for (auto& op_ptr : instr_ptr->getOperands()) {
// 定义一个处理寄存器操作数的 lambda 函数
auto process_reg_op = [&](RegOperand* reg_op) {
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (color_map.count(vreg)) {
reg_op->setPReg(color_map.at(vreg));
} else if (spilled_vregs.count(vreg)) {
// 根据vreg类型替换为对应的专用溢出寄存器
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
if (val->getType()->isFloat()) {
reg_op->setPReg(FP_SPILL_REG);
} else {
reg_op->setPReg(INT_SPILL_REG);
}
}
}
};
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
process_reg_op(static_cast<RegOperand*>(op_ptr.get()));
} else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
process_reg_op(static_cast<MemOperand*>(op_ptr.get())->getBase());
}
}
}
}
}
} // namespace sysy