[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