[backend-O1-1]修复了寄存器分配器在处理函数参数时不健壮的问题

This commit is contained in:
Lixuanwang
2025-08-20 01:37:59 +08:00
parent ef68235446
commit dd2725796a
4 changed files with 147 additions and 32 deletions

View File

@ -129,11 +129,11 @@ void RISCv64ISel::select() {
mv->addOperand(std::make_unique<RegOperand>(original_vreg));
CurMBB->addInstruction(std::move(mv));
MFunc->addProtectedArgumentVReg(saved_vreg);
// 4.【关键】更新vreg映射表将arg的vreg指向新的、安全的vreg
// 这样,后续所有对该参数的 getVReg(arg) 调用都会自动获得 saved_vreg
// 使得函数体内的代码都使用这个被保存过的值。
vreg_map[arg] = saved_vreg;
int_arg_idx++;
}
// --- 处理浮点参数 ---
@ -147,9 +147,8 @@ void RISCv64ISel::select() {
fmv->addOperand(std::make_unique<RegOperand>(original_vreg));
CurMBB->addInstruction(std::move(fmv));
// 同样更新映射
MFunc->addProtectedArgumentVReg(saved_vreg);
vreg_map[arg] = saved_vreg;
fp_arg_idx++;
}
// 对于栈传递的参数,则无需处理

View File

@ -98,6 +98,7 @@ bool RISCv64RegAlloc::doAllocation() {
precolorByCallingConvention();
analyzeLiveness();
build();
protectCrossCallVRegs();
makeWorklist();
while (!simplifyWorklist.empty() || !worklistMoves.empty() || !freezeWorklist.empty() || !spillWorklist.empty()) {
@ -185,6 +186,57 @@ void RISCv64RegAlloc::precolorByCallingConvention() {
}
}
void RISCv64RegAlloc::protectCrossCallVRegs() {
// 从ISel获取被标记为需要保护的参数副本vreg集合
const auto& vregs_to_protect_potentially = MFunc->getProtectedArgumentVRegs();
if (vregs_to_protect_potentially.empty()) {
return; // 如果没有需要保护的vreg直接返回
}
VRegSet live_across_call_vregs;
// 遍历所有指令找出哪些被标记的vreg其生命周期确实跨越了call指令
for (const auto& mbb_ptr : MFunc->getBlocks()) {
for (const auto& instr_ptr : mbb_ptr->getInstructions()) {
if (instr_ptr->getOpcode() == RVOpcodes::CALL) {
const VRegSet& live_out_after_call = live_out_map.at(instr_ptr.get());
for (unsigned vreg : vregs_to_protect_potentially) {
if (live_out_after_call.count(vreg)) {
live_across_call_vregs.insert(vreg);
}
}
}
}
}
if (live_across_call_vregs.empty()) {
return; // 如果被标记的vreg没有一个跨越call也无需操作
}
if (DEEPDEBUG) {
std::cerr << "--- [FIX] Applying protection for argument vregs that live across calls: ";
for(unsigned v : live_across_call_vregs) std::cerr << regIdToString(v) << " ";
std::cerr << "\n";
}
// 获取所有调用者保存寄存器
const auto& caller_saved_int = getCallerSavedIntRegs();
const auto& caller_saved_fp = getCallerSavedFpRegs();
const unsigned offset = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID);
// 为每个确认跨越call的vreg添加与所有调用者保存寄存器的冲突
for (unsigned vreg : live_across_call_vregs) {
if (isFPVReg(vreg)) { // 如果是浮点vreg
for (auto preg : caller_saved_fp) {
addEdge(vreg, offset + static_cast<unsigned>(preg));
}
} else { // 如果是整数vreg
for (auto preg : caller_saved_int) {
addEdge(vreg, offset + static_cast<unsigned>(preg));
}
}
}
}
// 初始化/重置所有数据结构
void RISCv64RegAlloc::initialize() {
initial.clear();
@ -504,12 +556,20 @@ void RISCv64RegAlloc::coalesce() {
unsigned y = getAlias(*use.begin());
unsigned u, v;
// 进一步修正标准化u和v的逻辑必须同时考虑物理寄存器和已预着色的虚拟寄存器
// 目标是确保如果两个操作数中有一个是预着色的,它一定会被赋给 u
if (precolored.count(y) || coloredNodes.count(y)) {
u = y; v = x;
} else {
u = x; v = y;
// 总是将待合并的虚拟寄存器赋给 v将合并目标赋给 u
// 优先级: 物理寄存器 (precolored) > 已着色的虚拟寄存器 (coloredNodes) > 普通虚拟寄存器
if (precolored.count(y)) {
u = y;
v = x;
} else if (precolored.count(x)) {
u = x;
v = y;
} else if (coloredNodes.count(y)) {
u = y;
v = x;
} else {
u = x;
v = y;
}
// 防御性检查,处理物理寄存器之间的传送指令
@ -528,7 +588,75 @@ void RISCv64RegAlloc::coalesce() {
addWorklist(u);
return;
}
bool is_conflicting = false;
// 检查1u 和 v 在冲突图中是否直接相连
if ((adjList.count(v) && adjList.at(v).count(u)) || (adjList.count(u) && adjList.at(u).count(v))) {
if (DEEPERDEBUG) std::cerr << " -> [Check] Nodes interfere directly.\n";
is_conflicting = true;
}
// 检查2如果节点不直接相连则检查是否存在间接的颜色冲突
else {
// 获取 u 和 v 的颜色(如果它们有的话)
unsigned u_color_id = 0, v_color_id = 0;
if (precolored.count(u)) {
u_color_id = u;
} else if (coloredNodes.count(u) || color_map.count(u)) { // color_map.count(u) 是更可靠的检查
u_color_id = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(color_map.at(u));
}
if (precolored.count(v)) {
v_color_id = v;
} else if (coloredNodes.count(v) || color_map.count(v)) {
v_color_id = static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID) + static_cast<unsigned>(color_map.at(v));
}
// 如果 u 有颜色,检查 v 是否与该颜色代表的物理寄存器冲突
if (u_color_id != 0 && adjList.count(v) && adjList.at(v).count(u_color_id)) {
if (DEEPERDEBUG) std::cerr << " -> [Check] Node " << regIdToString(v) << " interferes with the color of " << regIdToString(u) << " (" << regIdToString(u_color_id) << ").\n";
is_conflicting = true;
}
// 如果 v 有颜色,检查 u 是否与该颜色代表的物理寄存器冲突
else if (v_color_id != 0 && adjList.count(u) && adjList.at(u).count(v_color_id)) {
if (DEEPERDEBUG) std::cerr << " -> [Check] Node " << regIdToString(u) << " interferes with the color of " << regIdToString(v) << " (" << regIdToString(v_color_id) << ").\n";
is_conflicting = true;
}
}
if (is_conflicting) {
if (DEEPERDEBUG) std::cerr << " -> Constrained (nodes interfere directly or via pre-coloring).\n";
constrainedMoves.insert(move);
addWorklist(u);
addWorklist(v);
return;
}
bool u_is_colored = precolored.count(u) || coloredNodes.count(u);
bool v_is_colored = precolored.count(v) || coloredNodes.count(v);
if (u_is_colored && v_is_colored) {
PhysicalReg u_color = precolored.count(u)
? static_cast<PhysicalReg>(u - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID))
: color_map.at(u);
PhysicalReg v_color = precolored.count(v)
? static_cast<PhysicalReg>(v - static_cast<unsigned>(PhysicalReg::PHYS_REG_START_ID))
: color_map.at(v);
if (u_color != v_color) {
if (DEEPERDEBUG) std::cerr << " -> Constrained (move between two different precolored nodes: "
<< regToString(u_color) << " and " << regToString(v_color) << ").\n";
constrainedMoves.insert(move);
return;
} else {
if (DEEPERDEBUG) std::cerr << " -> Trivial coalesce (move between same precolored nodes).\n";
coalescedMoves.insert(move);
combine(u, v);
addWorklist(u);
return;
}
}
// 类型检查
if (isFPVReg(u) != isFPVReg(v)) {
if (DEEPERDEBUG) std::cerr << " -> Constrained (type mismatch: " << regIdToString(u) << " is "
<< (isFPVReg(u) ? "float" : "int") << ", " << regIdToString(v) << " is "
@ -539,25 +667,11 @@ void RISCv64RegAlloc::coalesce() {
return;
}
// 注意如果v已经是u的邻居 pre_interfere 会为true。
// 但如果v不在adjList中例如v是预着色节点我们需要检查u是否在v的邻居中。
// 为了简化我们假设adjList包含了所有虚拟寄存器。对于(Phys, Virt)对冲突信息存储在Virt节点的邻接表中。
bool pre_interfere = (adjList.count(v) && adjList.at(v).count(u)) || (adjList.count(u) && adjList.at(u).count(v));
if (pre_interfere) {
if (DEEPERDEBUG) std::cerr << " -> Constrained (nodes already interfere).\n";
constrainedMoves.insert(move);
addWorklist(u);
addWorklist(v);
return;
}
// 考虑物理寄存器和已预着色的虚拟寄存器
// 启发式判断逻辑
bool u_is_effectively_precolored = precolored.count(u) || coloredNodes.count(u);
bool can_coalesce = false;
if (u_is_effectively_precolored) {
// --- 场景1u是物理寄存器或已预着色虚拟寄存器使用 George 启发式 ---
if (DEEPERDEBUG) std::cerr << " -> Trying George Heuristic (u is effectively precolored)...\n";
VRegSet neighbors_of_v = adjacent(v);
@ -1227,11 +1341,7 @@ bool RISCv64RegAlloc::georgeHeuristic(unsigned t, unsigned u) {
int K = isFPVReg(t) ? K_fp : K_int;
// 缺陷 #2 修正: 移除了致命的 || precolored.count(u) 条件。
// 在此函数的上下文中u 总是预着色的物理寄存器ID导致旧的条件永远为true使整个启发式失效。
// 正确的逻辑是检查邻居t的度数是否小于K或者t是否已经与u冲突。
// return degree.at(t) < K || adjList.at(t).count(u);
return degree.at(t) < K || !adjList.at(t).count(u);
return degree.at(t) < K || adjList.at(t).count(u);
}
void RISCv64RegAlloc::combine(unsigned u, unsigned v) {

View File

@ -326,12 +326,19 @@ public:
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
blocks.push_back(std::move(block));
}
void addProtectedArgumentVReg(unsigned vreg) {
protected_argument_vregs.insert(vreg);
}
const std::set<unsigned>& getProtectedArgumentVRegs() const {
return protected_argument_vregs;
}
private:
Function* F;
RISCv64ISel* isel; // 指向创建它的ISel用于获取vreg映射等信息
std::string name;
std::vector<std::unique_ptr<MachineBasicBlock>> blocks;
StackFrameInfo frame_info;
std::set<unsigned> protected_argument_vregs;
};
inline bool isMemoryOp(RVOpcodes opcode) {
switch (opcode) {

View File

@ -45,12 +45,11 @@ private:
void rewriteProgram();
bool doAllocation();
void applyColoring();
void dumpState(const std::string &stage);
void precolorByCallingConvention();
void protectCrossCallVRegs();
// --- 辅助函数 ---
void dumpState(const std::string &stage);
void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def);
void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def);
void addEdge(unsigned u, unsigned v);