Files
mysysy/src/RISCv64RegAlloc.cpp

595 lines
27 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 <algorithm>
#include <vector>
#include <iostream> // For DEBUG output
#include <cassert> // For assert
namespace sysy {
RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
allocable_int_regs = {
PhysicalReg::T0, PhysicalReg::T1, PhysicalReg::T2, PhysicalReg::T3,
PhysicalReg::T4, PhysicalReg::T5, PhysicalReg::T6,
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,
};
// 映射物理寄存器到特殊的虚拟寄存器ID用于干扰图中的物理寄存器节点
// 确保这些特殊ID不会与vreg_counter生成的常规虚拟寄存器ID冲突
for (PhysicalReg preg : allocable_int_regs) {
preg_to_vreg_id_map[preg] = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(preg);
}
}
// 寄存器分配的主入口点
void RISCv64RegAlloc::run() {
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
handleCallingConvention();
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
eliminateFrameIndices();
// 阶段 3: 活跃性分析
analyzeLiveness();
// 阶段 4: 构建干扰图包含CALL指令对调用者保存寄存器的影响
buildInterferenceGraph();
// 阶段 5: 图着色算法分配物理寄存器
colorGraph();
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
rewriteFunction();
}
/**
* @brief 处理调用约定,预先为函数参数分配物理寄存器。
*/
void RISCv64RegAlloc::handleCallingConvention() {
Function* F = MFunc->getFunc();
RISCv64ISel* isel = MFunc->getISel();
// 获取函数的Argument对象列表
if (F) {
auto& args = F->getArguments();
// RISC-V RV64G调用约定前8个整型/指针参数通过 a0-a7 传递
int arg_idx = 0;
// 遍历 AllocaInst* 列表
for (Argument* arg : args) {
if (arg_idx >= 8) {
break;
}
// 获取该 Argument 对象对应的虚拟寄存器ID
// 通过 MachineFunction -> RISCv64ISel -> vreg_map 来获取
const auto& vreg_map_from_isel = MFunc->getISel()->getVRegMap();
assert(vreg_map_from_isel.count(arg) && "Argument not found in ISel's vreg_map!");
// 1. 获取该 Argument 对象对应的虚拟寄存器
unsigned vreg = isel->getVReg(arg);
// 2. 根据参数索引,确定对应的物理寄存器 (a0, a1, ...)
auto preg = static_cast<PhysicalReg>(static_cast<int>(PhysicalReg::A0) + arg_idx);
// 3. 在 color_map 中,将 vreg "预着色" 为对应的物理寄存器
color_map[vreg] = preg;
arg_idx++;
}
}
}
/**
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
*/
void RISCv64RegAlloc::eliminateFrameIndices() {
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();
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++;
}
}
// 处理局部变量
// 遍历AllocaInst来计算局部变量所需的总空间
for (auto& bb : F->getBasicBlocks()) {
for (auto& inst : bb->getInstructions()) {
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
// 获取Alloca指令指向的类型 (例如 alloca i32* 中,获取 i32)
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字节
current_offset += size;
unsigned alloca_vreg = isel->getVReg(alloca);
// 局部变量使用相对于s0的负向偏移
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
}
}
}
frame_info.locals_size = current_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_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 (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();
// 1. 特殊指令的 `is_def` 标志调整
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
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(static_cast<unsigned>(PhysicalReg::RA));
first_reg_is_def = false; // JAL/JALR 的第一个操作数是 ra已经处理为 def
}
// 2. CALL 指令的特殊处理
if (opcode == RVOpcodes::CALL) {
// 1.1 处理返回值 (def)
// 约定如果CALL指令有返回值IR阶段会将返回值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()) {
def.insert(reg_op->getVRegNum());
}
}
// 1.2 处理参数 (use)
// 参数通常是指令的后续操作数
bool first_operand_processed = false; // 用于跳过已作为def处理的返回值
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
if (!first_operand_processed) { // 如果是第一个操作数
first_operand_processed = true;
// 如果第一个操作数是返回值已被加入def则跳过
if (def.count(static_cast<RegOperand*>(op.get())->getVRegNum())) {
continue;
}
}
// 否则,该寄存器是 use
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) {
use.insert(reg_op->getVRegNum());
}
}
}
// **重要**: CALL指令隐式定义杀死了所有调用者保存的寄存器。
// **这部分逻辑不在getInstrUseDef中直接处理**。
// 而是通过`buildInterferenceGraph`中添加物理寄存器节点与活跃虚拟寄存器之间的干扰边来完成。
// 这样 Liveness Analysis 可以在虚拟寄存器层面进行,而物理寄存器干扰的复杂性则留给干扰图。
return; // CALL 指令处理完毕,直接返回
}
// 3. 对其他所有指令的通用处理逻辑
for (const auto& op : instr->getOperands()) {
if (op->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op.get());
if (reg_op->isVirtual()) { // 只有虚拟寄存器才需要处理 Use/Def
// 如果是第一个寄存器操作数,且指令类型表明它是定义 (def),则加入 def 集合
// 否则,它是 use (读取)
if (first_reg_is_def) {
def.insert(reg_op->getVRegNum());
first_reg_is_def = false; // 确保每条指令只定义一个目标寄存器
} else {
use.insert(reg_op->getVRegNum());
}
}
} else if (op->getKind() == MachineOperand::KIND_MEM) {
// 内存操作数 `offset(base)` 中的 `base` 寄存器是 `use`
auto mem_op = static_cast<MemOperand*>(op.get());
if (mem_op->getBase()->isVirtual()) {
use.insert(mem_op->getBase()->getVRegNum());
}
// 对于存储内存指令 (SW, SD),要存储的值(第一个操作数)也是 `use`
if ((opcode == RVOpcodes::SW || opcode == RVOpcodes::SD) &&
!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());
}
}
}
}
}
/**
* @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() {
bool changed = true;
while (changed) {
changed = false;
for (auto it = MFunc->getBlocks().rbegin(); it != MFunc->getBlocks().rend(); ++it) {
auto& mbb = *it;
LiveSet live_out;
for (auto succ : mbb->successors) {
if (!succ->getInstructions().empty()) {
auto first_instr = succ->getInstructions().front().get();
if (live_in_map.count(first_instr)) {
live_out.insert(live_in_map.at(first_instr).begin(), live_in_map.at(first_instr).end());
}
}
}
for (auto instr_it = mbb->getInstructions().rbegin(); instr_it != mbb->getInstructions().rend(); ++instr_it) {
MachineInstr* instr = instr_it->get();
LiveSet old_live_in = live_in_map[instr];
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_in;
if (live_in_map[instr] != old_live_in) {
changed = true;
}
}
}
}
}
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] = {}; }
for (auto& mbb : MFunc->getBlocks()) {
for (auto& instr : mbb->getInstructions()) {
LiveSet def, use;
getInstrUseDef(instr.get(), use, def);
const LiveSet& live_out = live_out_map.at(instr.get());
// 标准干扰图构建def 与 live_out 中的其他变量干扰
for (unsigned d : def) {
for (unsigned l : live_out) {
if (d != l) {
interference_graph[d].insert(l);
interference_graph[l].insert(d);
}
}
}
// *** 核心修改点:处理 CALL 指令的隐式 def ***
if (instr->getOpcode() == RVOpcodes::CALL) {
// CALL 指令会定义(杀死)所有调用者保存的寄存器。
// 因此,所有调用者保存的物理寄存器都与 CALL 指令的 live_out 中的所有变量冲突。
const std::vector<PhysicalReg>& caller_saved_regs = getCallerSavedIntRegs();
for (PhysicalReg cs_reg : caller_saved_regs) {
unsigned cs_vreg_id = preg_to_vreg_id_map.at(cs_reg); // 获取物理寄存器对应的特殊vreg ID
// 将这个物理寄存器节点与 CALL 指令的 live_out 中的所有虚拟寄存器添加干扰边。
for (unsigned live_vreg_out : live_out) {
if (cs_vreg_id != live_vreg_out) { // 避免自己和自己干扰
interference_graph[cs_vreg_id].insert(live_vreg_out);
interference_graph[live_vreg_out].insert(cs_vreg_id);
}
}
}
}
}
}
}
void RISCv64RegAlloc::colorGraph() {
std::vector<unsigned> sorted_vregs;
for (auto const& [vreg, neighbors] : interference_graph) {
if (color_map.find(vreg) == color_map.end()) {
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();
});
// 着色
for (unsigned vreg : sorted_vregs) {
std::set<PhysicalReg> used_colors;
for (unsigned neighbor : interference_graph.at(vreg)) {
if (color_map.count(neighbor)) {
used_colors.insert(color_map.at(neighbor));
}
}
bool colored = false;
for (PhysicalReg preg : allocable_int_regs) {
if (used_colors.find(preg) == used_colors.end()) {
color_map[vreg] = preg;
colored = true;
break;
}
}
if (!colored) {
spilled_vregs.insert(vreg);
}
}
}
void RISCv64RegAlloc::rewriteFunction() {
StackFrameInfo& frame_info = MFunc->getFrameInfo();
int current_offset = frame_info.locals_size;
// --- FIX 1: 动态计算溢出槽大小 ---
// 根据溢出虚拟寄存器的真实类型,为其在栈上分配正确大小的空间。
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;
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);
// --- FIX 2: 为溢出的 '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);
RVOpcodes load_op = val->getType()->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
int offset = frame_info.spill_offsets.at(vreg);
auto load = std::make_unique<MachineInstr>(load_op);
load->addOperand(std::make_unique<RegOperand>(vreg));
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));
// --- FIX 3: 为溢出的 'def' 操作数插入正确的存储指令 ---
for (unsigned vreg : def) {
if (spilled_vregs.count(vreg)) {
// 根据 vreg 的类型决定使用 sw 还是 sd
assert(vreg_to_value_map.count(vreg));
Value* val = vreg_to_value_map.at(vreg);
RVOpcodes store_op = val->getType()->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
int offset = frame_info.spill_offsets.at(vreg);
auto store = std::make_unique<MachineInstr>(store_op);
store->addOperand(std::make_unique<RegOperand>(vreg));
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()) {
// 情况一:操作数本身就是一个寄存器 (例如 add rd, rs1, rs2 中的所有操作数)
if(op_ptr->getKind() == MachineOperand::KIND_REG) {
auto reg_op = static_cast<RegOperand*>(op_ptr.get());
if (reg_op->isVirtual()) {
unsigned vreg = reg_op->getVRegNum();
if (color_map.count(vreg)) {
PhysicalReg preg = color_map.at(vreg);
reg_op->setPReg(preg);
} else if (spilled_vregs.count(vreg)) {
// 如果vreg被溢出替换为专用的溢出物理寄存器t6
reg_op->setPReg(PhysicalReg::T6);
}
}
}
// 情况二:操作数是一个内存地址 (例如 lw rd, offset(rs1) 中的 offset(rs1))
else if (op_ptr->getKind() == MachineOperand::KIND_MEM) {
auto mem_op = static_cast<MemOperand*>(op_ptr.get());
// 获取内存操作数内部的“基址寄存器”
auto base_reg_op = mem_op->getBase();
// 对这个基址寄存器,执行与情况一完全相同的替换逻辑
if(base_reg_op->isVirtual()){
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);
}
}
}
}
}
}
}
} // namespace sysy