[midend][backend]补全了符合RV64调用约定的寄存器着色规则
This commit is contained in:
@ -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)) {
|
||||
|
||||
@ -34,6 +34,9 @@ private:
|
||||
// 辅助函数,获取指令的Use/Def集合
|
||||
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
|
||||
|
||||
// 辅助函数,处理调用约定
|
||||
void handleCallingConvention();
|
||||
|
||||
MachineFunction* MFunc;
|
||||
|
||||
// 活跃性分析结果
|
||||
|
||||
Reference in New Issue
Block a user