[llvm] [LoopBoundSplit] Fix edge connections during transformation (PR #192106)
Congzhe Cao via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 15 12:07:04 PDT 2026
https://github.com/CongzheUalberta updated https://github.com/llvm/llvm-project/pull/192106
>From ef694405316688c0299ab941e9c34e40a85aa596 Mon Sep 17 00:00:00 2001
From: Congzhe Cao <congzhe.cao at huawei.com>
Date: Tue, 14 Apr 2026 13:57:45 -0400
Subject: [PATCH 1/3] [LoopBoundSplit] Fix edge connections during
transformation
The issue is caused by invalid intermediate IR when `getSCEV()` is called:
The exiting block of pre-loop did not re-connect to preheader of the
post-loop but still connected to original exit block which is broken, causing
`LI.verify()` unable to correctly recompute another LoopInfo for verification.
To fix, reconnect the edge earlier before calling `getSCEV()`.
---
llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
index a461e1f7fe074..88bf9418f9326 100644
--- a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
@@ -356,6 +356,11 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
BasicBlock *PostLoopPreHeader = PostLoop->getLoopPreheader();
IRBuilder<> Builder(&PostLoopPreHeader->front());
+ // Replace exit branch target of pre-loop by post-loop's preheader.
+ if (L.getExitBlock() == ExitingCond.BI->getSuccessor(0))
+ ExitingCond.BI->setSuccessor(0, PostLoopPreHeader);
+ else
+ ExitingCond.BI->setSuccessor(1, PostLoopPreHeader);
// Update phi nodes in header of post-loop.
bool isExitingLatch = L.getExitingBlock() == L.getLoopLatch();
Value *ExitingCondLCSSAPhi = nullptr;
@@ -419,11 +424,6 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
cast<CondBrInst>(VMap[SplitCandidateCond.BI]);
ClonedSplitCandidateBI->setCondition(ConstantInt::getFalse(Context));
- // Replace exit branch target of pre-loop by post-loop's preheader.
- if (L.getExitBlock() == ExitingCond.BI->getSuccessor(0))
- ExitingCond.BI->setSuccessor(0, PostLoopPreHeader);
- else
- ExitingCond.BI->setSuccessor(1, PostLoopPreHeader);
// Update phi node in exit block of post-loop.
Builder.SetInsertPoint(PostLoopPreHeader, PostLoopPreHeader->begin());
>From d3ab9119df4883b95c1129b61a8b6e7c325737bf Mon Sep 17 00:00:00 2001
From: Congzhe Cao <congzhe.cao at huawei.com>
Date: Tue, 14 Apr 2026 14:42:43 -0400
Subject: [PATCH 2/3] formating update
---
llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
index 88bf9418f9326..f7c18fdd25243 100644
--- a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
@@ -424,7 +424,6 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
cast<CondBrInst>(VMap[SplitCandidateCond.BI]);
ClonedSplitCandidateBI->setCondition(ConstantInt::getFalse(Context));
-
// Update phi node in exit block of post-loop.
Builder.SetInsertPoint(PostLoopPreHeader, PostLoopPreHeader->begin());
for (PHINode &PN : PostLoop->getExitBlock()->phis()) {
>From 3a34ed5febb4669ca6978f61c3ff0cbce82fa37c Mon Sep 17 00:00:00 2001
From: Congzhe Cao <congzhe.cao at huawei.com>
Date: Wed, 15 Apr 2026 15:06:13 -0400
Subject: [PATCH 3/3] Address reviewer's comments on April 14th.
---
llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp | 29 ++++++++++++++-----
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
index f7c18fdd25243..70fe6cdc75c14 100644
--- a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
@@ -357,10 +357,20 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
IRBuilder<> Builder(&PostLoopPreHeader->front());
// Replace exit branch target of pre-loop by post-loop's preheader.
+ // Note: update the branch here after calling cloneLoopWithPreheader()
+ // to keep the IR valid. Otherwise LI.verify(DT) would fail below
+ // because with invalide IR it would not be able to correctly compute
+ // another fresh LoopInfo for verification.
if (L.getExitBlock() == ExitingCond.BI->getSuccessor(0))
ExitingCond.BI->setSuccessor(0, PostLoopPreHeader);
else
ExitingCond.BI->setSuccessor(1, PostLoopPreHeader);
+
+ // Update dominator tree.
+ DT.changeImmediateDominator(PostLoopPreHeader, L.getExitingBlock());
+#ifndef NDEBUG
+ LI.verify(DT);
+#endif
// Update phi nodes in header of post-loop.
bool isExitingLatch = L.getExitingBlock() == L.getLoopLatch();
Value *ExitingCondLCSSAPhi = nullptr;
@@ -382,6 +392,8 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
// Find PHI with exiting condition from pre-loop. The PHI should be
// SCEVAddRecExpr and have same incoming value from backedge with
// ExitingCond.
+ //
+ // TODO: Separate SCEV queries from PHI node updates.
if (!SE.isSCEVable(PN.getType()))
continue;
@@ -391,13 +403,22 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
ExitingCondLCSSAPhi = LCSSAPhi;
}
- // Add conditional branch to check we can skip post-loop in its preheader.
+ // Add conditional branch to check we can skip post-loop in its preheader,
+ // and update DT.
Instruction *OrigBI = PostLoopPreHeader->getTerminator();
ICmpInst::Predicate Pred = ICmpInst::ICMP_NE;
Value *Cond =
Builder.CreateICmp(Pred, ExitingCondLCSSAPhi, ExitingCond.BoundValue);
Builder.CreateCondBr(Cond, PostLoop->getHeader(), PostLoop->getExitBlock());
OrigBI->eraseFromParent();
+ DT.changeImmediateDominator(PostLoop->getExitBlock(), PostLoopPreHeader);
+#ifdef EXPENSIVE_CHECKS
+ assert(DT.verify(DominatorTree::VerificationLevel::Full) &&
+ "DT broken during transformation!");
+#else
+ assert(DT.verify(DominatorTree::VerificationLevel::Fast) &&
+ "DT broken during transformation!");
+#endif
// Create new loop bound and add it into preheader of pre-loop.
const SCEV *NewBoundSCEV = ExitingCond.BoundSCEV;
@@ -448,17 +469,11 @@ static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
}
}
- // Update dominator tree.
- DT.changeImmediateDominator(PostLoopPreHeader, L.getExitingBlock());
- DT.changeImmediateDominator(PostLoop->getExitBlock(), PostLoopPreHeader);
-
// Invalidate cached SE information.
SE.forgetLoop(&L);
-
// Canonicalize loops.
simplifyLoop(&L, &DT, &LI, &SE, nullptr, nullptr, true);
simplifyLoop(PostLoop, &DT, &LI, &SE, nullptr, nullptr, true);
-
// Add new post-loop to loop pass manager.
U.addSiblingLoops(PostLoop);
More information about the llvm-commits
mailing list