[backend]尝试在寄存器分配逻辑中区分调用者保存、被调用者保存寄存器
This commit is contained in:
@@ -34,6 +34,7 @@ add_executable(sysyc
|
|||||||
RISCv64RegAlloc.cpp
|
RISCv64RegAlloc.cpp
|
||||||
RISCv64AsmPrinter.cpp
|
RISCv64AsmPrinter.cpp
|
||||||
RISCv64Passes.cpp
|
RISCv64Passes.cpp
|
||||||
|
RISCv64LLIR.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
# 设置 include 路径,包含 ANTLR 运行时库和项目头文件
|
||||||
|
|||||||
6
src/RISCv64LLIR.cpp
Normal file
6
src/RISCv64LLIR.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "RISCv64ISel.h"
|
#include "RISCv64ISel.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iostream> // For DEBUG output
|
||||||
|
#include <cassert> // For assert
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@@ -15,15 +17,28 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
|
|||||||
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
PhysicalReg::S4, PhysicalReg::S5, PhysicalReg::S6, PhysicalReg::S7,
|
||||||
PhysicalReg::S8, PhysicalReg::S9, PhysicalReg::S10, PhysicalReg::S11,
|
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() {
|
void RISCv64RegAlloc::run() {
|
||||||
handleCallingConvention();
|
// 阶段 1: 处理函数调用约定(参数寄存器预着色)
|
||||||
eliminateFrameIndices();
|
handleCallingConvention();
|
||||||
analyzeLiveness();
|
// 阶段 2: 消除帧索引(为局部变量和栈参数分配栈偏移)
|
||||||
buildInterferenceGraph();
|
eliminateFrameIndices();
|
||||||
colorGraph();
|
// 阶段 3: 活跃性分析
|
||||||
rewriteFunction();
|
analyzeLiveness();
|
||||||
|
// 阶段 4: 构建干扰图(包含CALL指令对调用者保存寄存器的影响)
|
||||||
|
buildInterferenceGraph();
|
||||||
|
// 阶段 5: 图着色算法分配物理寄存器
|
||||||
|
colorGraph();
|
||||||
|
// 阶段 6: 重写函数(插入溢出/填充代码,替换虚拟寄存器为物理寄存器)
|
||||||
|
rewriteFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +58,10 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
|||||||
if (arg_idx >= 8) {
|
if (arg_idx >= 8) {
|
||||||
break;
|
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 对象对应的虚拟寄存器
|
// 1. 获取该 Argument 对象对应的虚拟寄存器
|
||||||
unsigned vreg = isel->getVReg(arg);
|
unsigned vreg = isel->getVReg(arg);
|
||||||
|
|
||||||
@@ -58,6 +76,9 @@ void RISCv64RegAlloc::handleCallingConvention() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 消除帧索引,为局部变量和栈参数分配栈偏移量,并展开伪指令。
|
||||||
|
*/
|
||||||
void RISCv64RegAlloc::eliminateFrameIndices() {
|
void RISCv64RegAlloc::eliminateFrameIndices() {
|
||||||
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
StackFrameInfo& frame_info = MFunc->getFrameInfo();
|
||||||
// 初始偏移量,为保存ra和s0留出空间。
|
// 初始偏移量,为保存ra和s0留出空间。
|
||||||
@@ -185,30 +206,38 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计算给定 MachineInstr 的 Use (读取) 和 Def (写入) 寄存器集合。
|
||||||
|
* 这是活跃性分析的基础。
|
||||||
|
* @param instr 要分析的机器指令。
|
||||||
|
* @param use 存储 Use 寄存器(虚拟寄存器 ID)的集合。
|
||||||
|
* @param def 存储 Def 寄存器(虚拟寄存器 ID)的集合。
|
||||||
|
*/
|
||||||
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def) {
|
||||||
bool is_def = true;
|
bool first_reg_is_def = true; // 默认情况下,指令的第一个寄存器操作数是定义 (def)
|
||||||
auto opcode = instr->getOpcode();
|
auto opcode = instr->getOpcode();
|
||||||
|
|
||||||
// --- MODIFICATION START: 细化对指令的 use/def 定义 ---
|
// 1. 特殊指令的 `is_def` 标志调整
|
||||||
|
// 这些指令的第一个寄存器操作数是源操作数 (use),而不是目标操作数 (def)。
|
||||||
// 对于没有定义目标寄存器的指令,预先设置 is_def = false
|
|
||||||
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
if (opcode == RVOpcodes::SW || opcode == RVOpcodes::SD ||
|
||||||
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
opcode == RVOpcodes::BEQ || opcode == RVOpcodes::BNE ||
|
||||||
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
opcode == RVOpcodes::BLT || opcode == RVOpcodes::BGE ||
|
||||||
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
opcode == RVOpcodes::BLTU || opcode == RVOpcodes::BGEU ||
|
||||||
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
opcode == RVOpcodes::RET || opcode == RVOpcodes::J) {
|
||||||
is_def = false;
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对 CALL 指令进行特殊处理
|
// 2. CALL 指令的特殊处理
|
||||||
if (opcode == RVOpcodes::CALL) {
|
if (opcode == RVOpcodes::CALL) {
|
||||||
// CALL 指令的第一个操作数通常是目标函数标签,不是寄存器。
|
// 1.1 处理返回值 (def)
|
||||||
// 它可能会有一个可选的返回值(def),以及一系列参数(use)。
|
// 约定:如果CALL指令有返回值,IR阶段会将返回值vreg作为指令的第一个操作数。
|
||||||
// 这里的处理假定 CALL 的机器指令操作数布局是:
|
|
||||||
// [可选: dest_vreg (def)], [函数标签], [可选: arg1_vreg (use)], [可选: arg2_vreg (use)], ...
|
|
||||||
|
|
||||||
// 我们需要一种方法来识别哪些操作数是def,哪些是use。
|
|
||||||
// 一个简单的约定:如果第一个操作数是寄存器,则它是def(返回值)。
|
|
||||||
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
if (!instr->getOperands().empty() && instr->getOperands().front()->getKind() == MachineOperand::KIND_REG) {
|
||||||
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
auto reg_op = static_cast<RegOperand*>(instr->getOperands().front().get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) {
|
||||||
@@ -216,14 +245,19 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历所有操作数,非第一个寄存器操作数均视为use
|
// 1.2 处理参数 (use)
|
||||||
bool first_reg_skipped = false;
|
// 参数通常是指令的后续操作数
|
||||||
|
bool first_operand_processed = false; // 用于跳过已作为def处理的返回值
|
||||||
for (const auto& op : instr->getOperands()) {
|
for (const auto& op : instr->getOperands()) {
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
if (!first_reg_skipped) {
|
if (!first_operand_processed) { // 如果是第一个操作数
|
||||||
first_reg_skipped = true;
|
first_operand_processed = true;
|
||||||
continue; // 跳过我们已经作为def处理的返回值
|
// 如果第一个操作数是返回值(已被加入def),则跳过
|
||||||
|
if (def.count(static_cast<RegOperand*>(op.get())->getVRegNum())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// 否则,该寄存器是 use
|
||||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) {
|
||||||
use.insert(reg_op->getVRegNum());
|
use.insert(reg_op->getVRegNum());
|
||||||
@@ -231,34 +265,43 @@ void RISCv64RegAlloc::getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// **重要**: CALL指令还隐式定义(杀死)了所有调用者保存的寄存器。
|
// **重要**: CALL指令隐式定义(杀死)了所有调用者保存的寄存器。
|
||||||
// 一个完整的实现会在这里将所有caller-saved寄存器标记为def,
|
// **这部分逻辑不在getInstrUseDef中直接处理**。
|
||||||
// 以确保任何跨调用存活的变量都不会被分配到这些寄存器中。
|
// 而是通过`buildInterferenceGraph`中添加物理寄存器节点与活跃虚拟寄存器之间的干扰边来完成。
|
||||||
// 这个简化的实现暂不处理隐式def,但这是未来优化的关键点。
|
// 这样 Liveness Analysis 可以在虚拟寄存器层面进行,而物理寄存器干扰的复杂性则留给干扰图。
|
||||||
|
|
||||||
return; // CALL 指令处理完毕,直接返回
|
return; // CALL 指令处理完毕,直接返回
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MODIFICATION END ---
|
// 3. 对其他所有指令的通用处理逻辑
|
||||||
|
|
||||||
// 对其他所有指令的通用处理逻辑
|
|
||||||
for (const auto& op : instr->getOperands()) {
|
for (const auto& op : instr->getOperands()) {
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
if (op->getKind() == MachineOperand::KIND_REG) {
|
||||||
auto reg_op = static_cast<RegOperand*>(op.get());
|
auto reg_op = static_cast<RegOperand*>(op.get());
|
||||||
if (reg_op->isVirtual()) {
|
if (reg_op->isVirtual()) { // 只有虚拟寄存器才需要处理 Use/Def
|
||||||
if (is_def) {
|
// 如果是第一个寄存器操作数,且指令类型表明它是定义 (def),则加入 def 集合
|
||||||
|
// 否则,它是 use (读取)
|
||||||
|
if (first_reg_is_def) {
|
||||||
def.insert(reg_op->getVRegNum());
|
def.insert(reg_op->getVRegNum());
|
||||||
is_def = false; // 一条指令通常只有一个目标寄存ator
|
first_reg_is_def = false; // 确保每条指令只定义一个目标寄存器
|
||||||
} else {
|
} else {
|
||||||
use.insert(reg_op->getVRegNum());
|
use.insert(reg_op->getVRegNum());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
||||||
// 内存操作数 `offset(base)` 中的 base 寄存器是 use
|
// 内存操作数 `offset(base)` 中的 `base` 寄存器是 `use`
|
||||||
auto mem_op = static_cast<MemOperand*>(op.get());
|
auto mem_op = static_cast<MemOperand*>(op.get());
|
||||||
if (mem_op->getBase()->isVirtual()) {
|
if (mem_op->getBase()->isVirtual()) {
|
||||||
use.insert(mem_op->getBase()->getVRegNum());
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,6 +387,7 @@ void RISCv64RegAlloc::analyzeLiveness() {
|
|||||||
|
|
||||||
void RISCv64RegAlloc::buildInterferenceGraph() {
|
void RISCv64RegAlloc::buildInterferenceGraph() {
|
||||||
std::set<unsigned> all_vregs;
|
std::set<unsigned> all_vregs;
|
||||||
|
// 收集所有虚拟寄存器和物理寄存器在干扰图中的节点ID
|
||||||
for (auto& mbb : MFunc->getBlocks()) {
|
for (auto& mbb : MFunc->getBlocks()) {
|
||||||
for(auto& instr : mbb->getInstructions()) {
|
for(auto& instr : mbb->getInstructions()) {
|
||||||
LiveSet use, def;
|
LiveSet use, def;
|
||||||
@@ -352,6 +396,11 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
for(auto d : def) all_vregs.insert(d);
|
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 vreg : all_vregs) { interference_graph[vreg] = {}; }
|
||||||
|
|
||||||
@@ -361,6 +410,7 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
getInstrUseDef(instr.get(), use, def);
|
getInstrUseDef(instr.get(), use, def);
|
||||||
const LiveSet& live_out = live_out_map.at(instr.get());
|
const LiveSet& live_out = live_out_map.at(instr.get());
|
||||||
|
|
||||||
|
// 标准干扰图构建:def 与 live_out 中的其他变量干扰
|
||||||
for (unsigned d : def) {
|
for (unsigned d : def) {
|
||||||
for (unsigned l : live_out) {
|
for (unsigned l : live_out) {
|
||||||
if (d != l) {
|
if (d != l) {
|
||||||
@@ -369,6 +419,24 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *** 核心修改点:处理 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public:
|
|||||||
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
// 公开接口,以便后续模块(如RegAlloc)可以查询或创建vreg
|
||||||
unsigned getVReg(Value* val);
|
unsigned getVReg(Value* val);
|
||||||
unsigned getNewVReg() { return vreg_counter++; }
|
unsigned getNewVReg() { return vreg_counter++; }
|
||||||
|
// 获取 vreg_map 的公共接口
|
||||||
|
const std::map<Value*, unsigned>& getVRegMap() const { return vreg_map; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DAG节点定义,作为ISel的内部实现细节
|
// DAG节点定义,作为ISel的内部实现细节
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ enum class PhysicalReg {
|
|||||||
// (保持您原有的 F0-F31 命名)
|
// (保持您原有的 F0-F31 命名)
|
||||||
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||||||
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
F12, F13, F14, F15, F16, F17, F18, F19, F20, F21,
|
||||||
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
|
F22, F23, F24, F25, F26, F27, F28, F29, F30, F31,
|
||||||
|
|
||||||
|
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
||||||
|
// 假设 vreg_counter 不会达到这么大的值
|
||||||
|
PHYS_REG_START_ID = 10000,
|
||||||
|
PHYS_REG_END_ID = PHYS_REG_START_ID + 32, // 预留足够的空间
|
||||||
};
|
};
|
||||||
|
|
||||||
// RISC-V 指令操作码枚举
|
// RISC-V 指令操作码枚举
|
||||||
@@ -67,6 +72,9 @@ enum class RVOpcodes {
|
|||||||
FRAME_ADDR, // 获取栈帧变量的地址
|
FRAME_ADDR, // 获取栈帧变量的地址
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 定义一个全局辅助函数或常量,提供调用者保存寄存器列表
|
||||||
|
const std::vector<PhysicalReg>& getCallerSavedIntRegs();
|
||||||
|
|
||||||
class MachineOperand;
|
class MachineOperand;
|
||||||
class RegOperand;
|
class RegOperand;
|
||||||
class ImmOperand;
|
class ImmOperand;
|
||||||
@@ -215,6 +223,15 @@ private:
|
|||||||
StackFrameInfo frame_info;
|
StackFrameInfo frame_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline const std::vector<PhysicalReg>& getCallerSavedIntRegs() {
|
||||||
|
static const std::vector<PhysicalReg> 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
|
||||||
|
};
|
||||||
|
return regs;
|
||||||
|
}
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|
||||||
#endif // RISCV64_LLIR_H
|
#endif // RISCV64_LLIR_H
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define RISCV64_REGALLOC_H
|
#define RISCV64_REGALLOC_H
|
||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ private:
|
|||||||
// 存储vreg到IR Value*的反向映射
|
// 存储vreg到IR Value*的反向映射
|
||||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
||||||
std::map<unsigned, Value*> vreg_to_value_map;
|
std::map<unsigned, Value*> vreg_to_value_map;
|
||||||
|
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
|
||||||
|
|
||||||
// 用于计算类型大小的辅助函数
|
// 用于计算类型大小的辅助函数
|
||||||
unsigned getTypeSizeInBytes(Type* type);
|
unsigned getTypeSizeInBytes(Type* type);
|
||||||
|
|||||||
Reference in New Issue
Block a user