[backend-O1-1]修复了寄存器分配器在处理函数参数时不健壮的问题
This commit is contained in:
@@ -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++;
|
||||
}
|
||||
// 对于栈传递的参数,则无需处理
|
||||
|
||||
@@ -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;
|
||||
// 总是将待合并的虚拟寄存器赋给 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;
|
||||
u = x;
|
||||
v = y;
|
||||
}
|
||||
|
||||
// 防御性检查,处理物理寄存器之间的传送指令
|
||||
@@ -529,6 +589,74 @@ void RISCv64RegAlloc::coalesce() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_conflicting = false;
|
||||
// 检查1:u 和 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) {
|
||||
// --- 场景1:u是物理寄存器或已预着色虚拟寄存器,使用 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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user