[midend][backend]补全了符合RV64调用约定的寄存器着色规则

This commit is contained in:
Lixuanwang
2025-07-26 17:35:08 +08:00
parent 828515bc2f
commit a616ec085e
2 changed files with 65 additions and 6 deletions

View File

@ -18,6 +18,7 @@ RISCv64RegAlloc::RISCv64RegAlloc(MachineFunction* mfunc) : MFunc(mfunc) {
}
void RISCv64RegAlloc::run() {
handleCallingConvention();
eliminateFrameIndices();
analyzeLiveness();
buildInterferenceGraph();
@ -25,16 +26,67 @@ void RISCv64RegAlloc::run() {
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;
}
// 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++;
}
}
}
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;
// 初始偏移量为保存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);
// --- MODIFICATION START: 动态计算栈帧大小 ---
// 将这个vreg和它的栈偏移存入map。
// 我们可以复用alloca_offsets因为它们都代表“vreg到栈偏移”的映射。
frame_info.alloca_offsets[vreg] = offset;
}
arg_idx++;
}
}
// 处理局部变量
// 遍历AllocaInst来计算局部变量所需的总空间
for (auto& bb : F->getBasicBlocks()) {
for (auto& inst : bb->getInstructions()) {
@ -49,12 +101,12 @@ void RISCv64RegAlloc::eliminateFrameIndices() {
current_offset += size;
unsigned alloca_vreg = isel->getVReg(alloca);
// 局部变量使用相对于s0的负向偏移
frame_info.alloca_offsets[alloca_vreg] = -current_offset;
}
}
}
frame_info.locals_size = current_offset;
// --- MODIFICATION END ---
// 遍历所有机器指令,将伪指令展开为真实指令
for (auto& mbb : MFunc->getBlocks()) {
@ -325,13 +377,17 @@ void RISCv64RegAlloc::buildInterferenceGraph() {
void RISCv64RegAlloc::colorGraph() {
std::vector<unsigned> sorted_vregs;
for (auto const& [vreg, neighbors] : interference_graph) {
sorted_vregs.push_back(vreg);
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)) {

View File

@ -34,6 +34,9 @@ private:
// 辅助函数获取指令的Use/Def集合
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
// 辅助函数,处理调用约定
void handleCallingConvention();
MachineFunction* MFunc;
// 活跃性分析结果