[Utils] Fix incorrect LCSSA PHI nodes when splitting critical edges with MergeIdenticalEdges (#131744)

This PR fixes incorrect LCSSA PHI node generation when splitting
critical edges with both
`PreserveLCSSA` and `MergeIdenticalEdges` enabled. The bug caused PHI
nodes in the split block
to miss predecessors when multiple identical edges were merged.
This commit is contained in:
Camsyn
2025-04-03 18:02:03 +08:00
committed by GitHub
parent bf516098fb
commit ecc35456d7
2 changed files with 67 additions and 1 deletions

View File

@@ -207,6 +207,8 @@ llvm::SplitKnownCriticalEdge(Instruction *TI, unsigned SuccNum,
}
}
unsigned NumSplitIdenticalEdges = 1;
// If there are any other edges from TIBB to DestBB, update those to go
// through the split block, making those edges non-critical as well (and
// reducing the number of phi entries in the DestBB if relevant).
@@ -219,6 +221,9 @@ llvm::SplitKnownCriticalEdge(Instruction *TI, unsigned SuccNum,
// We found another edge to DestBB, go to NewBB instead.
TI->setSuccessor(i, NewBB);
// Record the number of split identical edges to DestBB.
NumSplitIdenticalEdges++;
}
}
@@ -290,7 +295,11 @@ llvm::SplitKnownCriticalEdge(Instruction *TI, unsigned SuccNum,
// Update LCSSA form in the newly created exit block.
if (Options.PreserveLCSSA) {
createPHIsForSplitLoopExit(TIBB, NewBB, DestBB);
// If > 1 identical edges to be split, we need to introduce the same
// number of the incoming blocks for the new PHINode.
createPHIsForSplitLoopExit(
SmallVector<BasicBlock *, 4>(NumSplitIdenticalEdges, TIBB), NewBB,
DestBB);
}
if (!LoopPreds.empty()) {

View File

@@ -438,6 +438,63 @@ bb2:
EXPECT_TRUE(PDT.verify());
}
TEST(BasicBlockUtils, SplitLoopCriticalEdge) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C, R"IR(
declare i1 @predicate(ptr %p)
define ptr @Parse(ptr %gp) {
entry:
br label %for.inc
for.inc:
%phi = phi ptr [ %gp, %entry ], [ %cp, %while.cond ], [ %cp, %while.cond ]
%cond = call i1 @predicate(ptr %phi)
%inc= getelementptr inbounds i8, ptr %phi, i64 1
br i1 %cond, label %while.cond, label %exit
while.cond:
%cp = phi ptr [ %inc, %for.inc ], [ %incdec, %while.body ]
%val = load i8, ptr %cp, align 1
switch i8 %val, label %while.body [
i8 10, label %for.inc
i8 0, label %for.inc
]
while.body:
%incdec = getelementptr inbounds i8, ptr %cp, i64 1
br label %while.cond
exit:
ret ptr %phi
}
)IR");
Function *F = M->getFunction("Parse");
DominatorTree DT(*F);
LoopInfo LI(DT);
CriticalEdgeSplittingOptions CESO =
CriticalEdgeSplittingOptions(nullptr, &LI, nullptr)
.setMergeIdenticalEdges()
.setPreserveLCSSA();
EXPECT_EQ(2u, SplitAllCriticalEdges(*F, CESO));
BasicBlock *WhileBB = getBasicBlockByName(*F, "while.cond");
BasicBlock *SplitBB = WhileBB->getTerminator()->getSuccessor(1);
// The only 1 successor of SplitBB is %for.inc
EXPECT_EQ(1u, SplitBB->getTerminator()->getNumSuccessors());
// MergeIdenticalEdges: SplitBB has two identical predecessors, %while.cond.
EXPECT_EQ(WhileBB, SplitBB->getUniquePredecessor());
EXPECT_TRUE(SplitBB->hasNPredecessors(2));
auto *PN = dyn_cast<PHINode>(&SplitBB->front());
// PreserveLCSSA: should insert a PHI node in front of SplitBB
EXPECT_NE(nullptr, PN);
// The PHI node should have 2 identical incoming blocks.
EXPECT_EQ(2u, PN->getNumIncomingValues());
EXPECT_EQ(PN->getIncomingBlock(0), PN->getIncomingBlock(1));
}
TEST(BasicBlockUtils, SplitIndirectBrCriticalEdgesIgnorePHIs) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C, R"IR(