[BasicBlockUtils] Fixed LoopInfo update in UpdateAnalysisInformation() (#177147)
SplitLandingPadPredecessors() results in an irreducible loop
and makes LoopInfo invalid. Verification results in a crash:
Assertion `CB != OutsideLoopPreds[i] && "Loop has multiple entry
points!"' failed.
Created a new test with a broken LoopInfo after
SplitLandingPadPredecessors().
The test @split-lp-predecessors-test() after
SplitBlockPredecessors(catch_dest, { loop }, "", DT, LI) changes to
the following IR where the loop {%catch_dest} gets into irreducible
loop {%catch_dest.split-lp, %catch_dest}:
```
define void @split-lp-predecessors-test() personality ptr null {
entry:
invoke void @foo()
to label %loop unwind label %catch_dest.split-lp
loop: ; preds = %latch, %entry
invoke void @foo()
to label %latch unwind label %catch_dest1
latch: ; preds = %loop
br label %loop
catch_dest1: ; preds = %loop
%lpad = landingpad i32
cleanup
br label %catch_dest
catch_dest.split-lp: ; preds = %entry, %catch_dest
%lpad.split-lp = landingpad i32
cleanup
br label %catch_dest
catch_dest: ; preds = %catch_dest.split-lp, %catch_dest1
invoke void @foo()
to label %exit unwind label %catch_dest.split-lp
exit: ; preds = %catch_dest
ret void
}
```
Irreducible loops must be removed from LoopInfo.
When UpdateAnalysisInformation() detects an irreducible loop created
then the loop is erased from LoopInfo.
See the issue #163922 for details.
This commit is contained in:
parent
c7908d3320
commit
e901b0295d
2 changed files with 110 additions and 2 deletions
|
|
@ -1057,6 +1057,15 @@ BasicBlock *llvm::SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt,
|
|||
return SplitBlockImpl(Old, SplitPt, DTU, /*DT=*/nullptr, LI, MSSAU, BBName);
|
||||
}
|
||||
|
||||
static bool hasReachableLoopEntryToHeader(const Loop &L,
|
||||
const DominatorTree &DT) {
|
||||
for (const BasicBlock *Pred : predecessors(L.getHeader()))
|
||||
if (!L.contains(Pred) && DT.isReachableFromEntry(Pred))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Update DominatorTree, LoopInfo, and LCCSA analysis information.
|
||||
/// Invalidates DFS Numbering when DTU or DT is provided.
|
||||
static void UpdateAnalysisInformation(BasicBlock *OldBB, BasicBlock *NewBB,
|
||||
|
|
@ -1166,8 +1175,15 @@ static void UpdateAnalysisInformation(BasicBlock *OldBB, BasicBlock *NewBB,
|
|||
InnermostPredLoop->addBasicBlockToLoop(NewBB, *LI);
|
||||
} else {
|
||||
L->addBasicBlockToLoop(NewBB, *LI);
|
||||
if (SplitMakesNewLoopHeader)
|
||||
L->moveToHeader(NewBB);
|
||||
if (SplitMakesNewLoopHeader) {
|
||||
// The old header might still have a loop entry. If so the loop becomes
|
||||
// irreducible and must be erased. Otherwise the NewBB becomes the loop
|
||||
// header.
|
||||
if (hasReachableLoopEntryToHeader(*L, *DT))
|
||||
LI->erase(L);
|
||||
else
|
||||
L->moveToHeader(NewBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -456,6 +456,98 @@ bb1:
|
|||
EXPECT_TRUE(DT.verify());
|
||||
}
|
||||
|
||||
TEST(BasicBlockUtils, SplitLandingPadPredecessors) {
|
||||
LLVMContext C;
|
||||
std::unique_ptr<Module> M = parseIR(C, R"IR(
|
||||
declare void @foo()
|
||||
|
||||
define void @split-lp-predecessors-test() personality ptr null {
|
||||
entry:
|
||||
invoke void @foo()
|
||||
to label %loop unwind label %catch_dest
|
||||
|
||||
loop:
|
||||
invoke void @foo()
|
||||
to label %latch unwind label %catch_dest
|
||||
|
||||
latch:
|
||||
br label %loop
|
||||
|
||||
catch_dest:
|
||||
%lp = landingpad i32
|
||||
cleanup
|
||||
invoke void @foo()
|
||||
to label %exit unwind label %catch_dest
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
)IR");
|
||||
Function *F = M->getFunction("split-lp-predecessors-test");
|
||||
DominatorTree DT(*F);
|
||||
LoopInfo LI(DT);
|
||||
|
||||
EXPECT_TRUE(DT.verify());
|
||||
LI.verify(DT);
|
||||
SplitBlockPredecessors(getBasicBlockByName(*F, "catch_dest"),
|
||||
{getBasicBlockByName(*F, "loop")}, "", &DT, &LI);
|
||||
|
||||
EXPECT_TRUE(DT.verify());
|
||||
LI.verify(DT);
|
||||
EXPECT_EQ(LI.getLoopFor(getBasicBlockByName(*F, "catch_dest")), nullptr);
|
||||
}
|
||||
|
||||
TEST(BasicBlockUtils, SplitLandingPadPredecessorsLoopStruct) {
|
||||
LLVMContext C;
|
||||
std::unique_ptr<Module> M = parseIR(C, R"IR(
|
||||
declare void @foo()
|
||||
|
||||
define void @split-lp-predecessors-test(i1 %flag) personality ptr null {
|
||||
entry:
|
||||
br label %superloop
|
||||
|
||||
superloop:
|
||||
invoke void @foo()
|
||||
to label %loop unwind label %catch_dest
|
||||
|
||||
loop:
|
||||
invoke void @foo()
|
||||
to label %latch unwind label %catch_dest
|
||||
|
||||
latch:
|
||||
br label %loop
|
||||
|
||||
catch_dest:
|
||||
%lp = landingpad i32
|
||||
cleanup
|
||||
br label %loop2
|
||||
|
||||
loop2:
|
||||
br i1 %flag, label %loop2, label %loop2_exit
|
||||
|
||||
loop2_exit:
|
||||
invoke void @foo()
|
||||
to label %exit unwind label %catch_dest
|
||||
|
||||
exit:
|
||||
br label %superloop
|
||||
}
|
||||
)IR");
|
||||
Function *F = M->getFunction("split-lp-predecessors-test");
|
||||
DominatorTree DT(*F);
|
||||
LoopInfo LI(DT);
|
||||
|
||||
EXPECT_TRUE(DT.verify());
|
||||
LI.verify(DT);
|
||||
SplitBlockPredecessors(getBasicBlockByName(*F, "catch_dest"),
|
||||
{getBasicBlockByName(*F, "loop")}, "", &DT, &LI);
|
||||
|
||||
EXPECT_TRUE(DT.verify());
|
||||
LI.verify(DT);
|
||||
EXPECT_EQ(LI.getLoopFor(getBasicBlockByName(*F, "catch_dest")),
|
||||
LI.getLoopFor(getBasicBlockByName(*F, "superloop")));
|
||||
}
|
||||
|
||||
TEST(BasicBlockUtils, SplitCriticalEdge) {
|
||||
LLVMContext C;
|
||||
std::unique_ptr<Module> M = parseIR(C, R"IR(
|
||||
|
|
|
|||
Loading…
Reference in a new issue