[llvm] [polly] [LoopInfo] Add an opaque LoopRef handle and stop exposing loop containers (PR #210653)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 20 00:05:52 PDT 2026


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/210653

>From 22db1a825b9b34f786a800fca8ea5fdca379a695 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 19 Jul 2026 22:25:18 -0700
Subject: [PATCH 1/2] [LoopInfo] Add an opaque LoopRef handle and stop exposing
 loop containers

Introduce llvm::LoopRef, the LoopInfo counterpart of CycleRef
(cc98c1eb84c6), wrapping the loop pointer rather than a preorder index
since passes hold loop identities across loop-forest mutation.

getBlocksVector, mutable getBlocksSet, getSubLoopsVector, and
getTopLevelLoopsVector hand out mutable references to the internal
containers, so every caller re-implements loop-nest surgery by hand.
Delete them in favor of two operations, making representation changes
(removing the block set, maintaining a loop numbering) local to
LoopInfoBase.

Also move hasNoExitBlocks, getExitEdges, and getUniqueLatchExitBlock
from LoopBase members to LoopRef queries.

Two behavior changes: SimpleLoopUnswitch's deleteDeadBlocksFromLoop now
runs the per-child deletion callbacks while the forest is still fully
consistent and detaches dead children before destroying them
(previously the callbacks could observe a destroyed sibling still
linked into the forest); FixIrreducible's reconnectChildLoops takes
children in their original relative order rather than std::partition's
arbitrary order.

Aided by Claude Fable 5
---
 bolt/lib/Core/BinaryFunction.cpp              |   2 +-
 llvm/include/llvm/Support/GenericLoopInfo.h   | 113 +++++++++++++-----
 .../llvm/Support/GenericLoopInfoImpl.h        |  37 +++---
 .../Target/AMDGPU/AMDGPUNextUseAnalysis.cpp   |   2 +-
 llvm/lib/Transforms/Scalar/LoopDeletion.cpp   |   2 +-
 .../lib/Transforms/Scalar/LoopPredication.cpp |   2 +-
 .../Transforms/Scalar/SimpleLoopUnswitch.cpp  | 103 ++++++----------
 llvm/lib/Transforms/Utils/FixIrreducible.cpp  |  23 ++--
 llvm/lib/Transforms/Utils/LoopPeel.cpp        |   2 +-
 llvm/lib/Transforms/Utils/LoopUtils.cpp       |   2 +-
 .../Transforms/Vectorize/LoopVectorize.cpp    |   3 +-
 llvm/lib/Transforms/Vectorize/VPlan.cpp       |   3 +-
 polly/lib/Analysis/ScopDetection.cpp          |   2 +-
 13 files changed, 159 insertions(+), 137 deletions(-)

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index f580edf2626d2..e0a76c1462654 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -4501,7 +4501,7 @@ void BinaryFunction::calculateLoopInfo() {
 
     // Compute exit count.
     SmallVector<BinaryLoop::Edge, 1> ExitEdges;
-    L->getExitEdges(ExitEdges);
+    BLI->getExitEdges(BLI->ref(L), ExitEdges);
     for (BinaryLoop::Edge &Exit : ExitEdges) {
       const BinaryBasicBlock *Exiting = Exit.first;
       const BinaryBasicBlock *ExitTarget = Exit.second;
diff --git a/llvm/include/llvm/Support/GenericLoopInfo.h b/llvm/include/llvm/Support/GenericLoopInfo.h
index 77f9cd731f71f..e83d1fdccfbe0 100644
--- a/llvm/include/llvm/Support/GenericLoopInfo.h
+++ b/llvm/include/llvm/Support/GenericLoopInfo.h
@@ -51,6 +51,24 @@ namespace llvm {
 
 template <class N, class M> class LoopInfoBase;
 template <class N, class M> class LoopBase;
+template <class N, class M> class PopulateLoopsDFS;
+
+/// Opaque handle to a loop within a LoopInfoBase. A handle stays valid for as
+/// long as the loop itself. The long-term goal is to move LoopBase operations
+/// to LoopInfoBase.
+class LoopRef {
+  void *Ptr = nullptr;
+
+  explicit LoopRef(void *Ptr) : Ptr(Ptr) {}
+  template <class N, class M> friend class LoopInfoBase;
+
+public:
+  LoopRef() = default;
+  bool isValid() const { return Ptr != nullptr; }
+  explicit operator bool() const { return isValid(); }
+  bool operator==(LoopRef O) const { return Ptr == O.Ptr; }
+  bool operator!=(LoopRef O) const { return Ptr != O.Ptr; }
+};
 
 //===----------------------------------------------------------------------===//
 /// Instances of this class are used to represent loops that are detected in the
@@ -146,10 +164,6 @@ template <class BlockT, class LoopT> class LoopBase {
     assert(!isInvalid() && "Loop not in a valid state!");
     return SubLoops;
   }
-  std::vector<LoopT *> &getSubLoopsVector() {
-    assert(!isInvalid() && "Loop not in a valid state!");
-    return SubLoops;
-  }
   using iterator = typename std::vector<LoopT *>::const_iterator;
   using reverse_iterator =
       typename std::vector<LoopT *>::const_reverse_iterator;
@@ -189,19 +203,6 @@ template <class BlockT, class LoopT> class LoopBase {
     return Blocks.size();
   }
 
-  /// Return a direct, mutable handle to the blocks vector so that we can
-  /// mutate it efficiently with techniques like `std::remove`.
-  std::vector<BlockT *> &getBlocksVector() {
-    assert(!isInvalid() && "Loop not in a valid state!");
-    return Blocks;
-  }
-  /// Return a direct, mutable handle to the blocks set so that we can
-  /// mutate it efficiently.
-  SmallPtrSetImpl<const BlockT *> &getBlocksSet() {
-    assert(!isInvalid() && "Loop not in a valid state!");
-    return DenseBlockSet;
-  }
-
   /// Return a direct, immutable handle to the blocks set.
   const SmallPtrSetImpl<const BlockT *> &getBlocksSet() const {
     assert(!isInvalid() && "Loop not in a valid state!");
@@ -294,19 +295,9 @@ template <class BlockT, class LoopT> class LoopBase {
   /// Otherwise return null.
   BlockT *getUniqueExitBlock() const;
 
-  /// Return the unique exit block for the latch, or null if there are multiple
-  /// different exit blocks or the latch is not exiting.
-  BlockT *getUniqueLatchExitBlock() const;
-
-  /// Return true if this loop does not have any exit blocks.
-  bool hasNoExitBlocks() const;
-
   /// Edge type.
   using Edge = std::pair<BlockT *, BlockT *>;
 
-  /// Return all pairs of (_inside_block_,_outside_block_).
-  void getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const;
-
   /// If there is a preheader for this loop, return it. A loop has a preheader
   /// if there is only one edge to the header of the loop from outside of the
   /// loop. If this is the case, the block branching to the header of the loop
@@ -434,6 +425,16 @@ template <class BlockT, class LoopT> class LoopBase {
     Blocks.reserve(size);
   }
 
+  /// interface to do reserve() for SubLoops
+  void reserveSubLoops(unsigned Size) {
+    assert(!isInvalid() && "Loop not in a valid state!");
+    SubLoops.reserve(Size);
+  }
+
+  /// Capacity of the block list; input to an enclosing loop's reserveBlocks()
+  /// during construction, when this loop's list is not yet fully populated.
+  unsigned getBlocksCapacity() const { return Blocks.capacity(); }
+
   /// This method is used to move BB (which must be part of this loop) to be the
   /// loop header of the loop (the block that dominates all others).
   void moveToHeader(BlockT *BB) {
@@ -480,6 +481,7 @@ template <class BlockT, class LoopT> class LoopBase {
 
 protected:
   friend class LoopInfoBase<BlockT, LoopT>;
+  friend class PopulateLoopsDFS<BlockT, LoopT>;
 
   /// This creates an empty loop.
   LoopBase() : ParentLoop(nullptr) {}
@@ -625,6 +627,12 @@ template <class BlockT, class LoopT> class LoopInfoBase {
            "loop info used with outdated block numbers");
   }
 
+  /// Resolve a handle to its loop.
+  LoopT *deref(LoopRef L) const {
+    assert(L.isValid() && "dereferencing an invalid loop handle");
+    return static_cast<LoopT *>(L.Ptr);
+  }
+
 public:
   /// Return the inner most loop that BB lives in. If a basic block is in no
   /// loop (for example the entry node), null is returned.
@@ -644,6 +652,54 @@ template <class BlockT, class LoopT> class LoopInfoBase {
     return L ? L->getLoopDepth() : 0;
   }
 
+  /// The handle for a loop of this LoopInfo; an invalid handle for null.
+  LoopRef ref(const LoopT *L) const { return LoopRef(const_cast<LoopT *>(L)); }
+
+  using Edge = std::pair<BlockT *, BlockT *>;
+
+  /// Return true if \p L does not have any exit blocks.
+  bool hasNoExitBlocks(LoopRef L) const;
+
+  /// Return all pairs of (_inside_block_,_outside_block_).
+  void getExitEdges(LoopRef L, SmallVectorImpl<Edge> &ExitEdges) const;
+
+  /// Return the unique exit block for the latch of \p L, or null if there are
+  /// multiple different exit blocks or the latch is not exiting.
+  BlockT *getUniqueLatchExitBlock(LoopRef L) const;
+
+  /// Remove every block satisfying \p Pred from \p L's block list, preserving
+  /// the order of the remaining blocks. Only \p L itself is updated, not its
+  /// ancestors or descendants, and not the block-to-loop mapping.
+  template <typename PredicateT>
+  void removeBlocksIf(LoopRef L, PredicateT Pred) {
+    LoopT *Lp = deref(L);
+    llvm::erase_if(Lp->Blocks, [&](BlockT *BB) {
+      if (!Pred(BB))
+        return false;
+      Lp->DenseBlockSet.erase(BB);
+      return true;
+    });
+  }
+
+  /// Detach and return the children of \p Parent (the top-level loops if
+  /// \p Parent is invalid) that satisfy \p Pred, clearing their parent
+  /// pointers. Both the remaining and the returned children keep their
+  /// relative order.
+  template <typename PredicateT>
+  SmallVector<LoopT *, 4> takeChildrenIf(LoopRef Parent, PredicateT Pred) {
+    std::vector<LoopT *> &List =
+        Parent ? deref(Parent)->SubLoops : TopLevelLoops;
+    SmallVector<LoopT *, 4> Taken;
+    llvm::erase_if(List, [&](LoopT *Child) {
+      if (!Pred(Child))
+        return false;
+      Child->ParentLoop = nullptr;
+      Taken.push_back(Child);
+      return true;
+    });
+    return Taken;
+  }
+
   /// \brief Find the innermost loop containing both given loops.
   ///
   /// \returns the innermost loop containing both \p A and \p B
@@ -664,9 +720,6 @@ template <class BlockT, class LoopT> class LoopInfoBase {
   /// Return the top-level loops.
   const std::vector<LoopT *> &getTopLevelLoops() const { return TopLevelLoops; }
 
-  /// Return the top-level loops.
-  std::vector<LoopT *> &getTopLevelLoopsVector() { return TopLevelLoops; }
-
   /// This removes the specified top-level loop from this loop info object.
   /// The loop is not deleted, as it will presumably be inserted into
   /// another loop.
diff --git a/llvm/include/llvm/Support/GenericLoopInfoImpl.h b/llvm/include/llvm/Support/GenericLoopInfoImpl.h
index e0a06ad75842c..434dc6feaa545 100644
--- a/llvm/include/llvm/Support/GenericLoopInfoImpl.h
+++ b/llvm/include/llvm/Support/GenericLoopInfoImpl.h
@@ -92,8 +92,8 @@ std::pair<BlockT *, bool> getExitBlockHelper(const LoopBase<BlockT, LoopT> *L,
 }
 
 template <class BlockT, class LoopT>
-bool LoopBase<BlockT, LoopT>::hasNoExitBlocks() const {
-  auto RC = getExitBlockHelper(this, false);
+bool LoopInfoBase<BlockT, LoopT>::hasNoExitBlocks(LoopRef L) const {
+  auto RC = getExitBlockHelper(deref(L), false);
   if (RC.second)
     // found multiple exit blocks
     return false;
@@ -160,24 +160,26 @@ BlockT *LoopBase<BlockT, LoopT>::getUniqueExitBlock() const {
 }
 
 template <class BlockT, class LoopT>
-BlockT *LoopBase<BlockT, LoopT>::getUniqueLatchExitBlock() const {
-  BlockT *Latch = getLoopLatch();
+BlockT *LoopInfoBase<BlockT, LoopT>::getUniqueLatchExitBlock(LoopRef L) const {
+  const LoopT *Lp = deref(L);
+  BlockT *Latch = Lp->getLoopLatch();
   assert(Latch && "Latch block must exists");
-  auto IsExitBlock = [this](BlockT *BB, bool AllowRepeats) -> BlockT * {
+  auto IsExitBlock = [Lp](BlockT *BB, bool AllowRepeats) -> BlockT * {
     assert(!AllowRepeats && "Unexpected parameter value.");
-    return !contains(BB) ? BB : nullptr;
+    return !Lp->contains(BB) ? BB : nullptr;
   };
-  return find_singleton<BlockT>(children<BlockT *>(Latch), IsExitBlock);
+  return find_singleton<BlockT>(llvm::children<BlockT *>(Latch), IsExitBlock);
 }
 
 /// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
 template <class BlockT, class LoopT>
-void LoopBase<BlockT, LoopT>::getExitEdges(
-    SmallVectorImpl<Edge> &ExitEdges) const {
-  assert(!isInvalid() && "Loop not in a valid state!");
-  for (const auto BB : blocks())
-    for (auto *Succ : children<BlockT *>(BB))
-      if (!contains(Succ))
+void LoopInfoBase<BlockT, LoopT>::getExitEdges(
+    LoopRef L, SmallVectorImpl<Edge> &ExitEdges) const {
+  const LoopT *Lp = deref(L);
+  assert(!Lp->isInvalid() && "Loop not in a valid state!");
+  for (const auto BB : Lp->blocks())
+    for (auto *Succ : llvm::children<BlockT *>(BB))
+      if (!Lp->contains(Succ))
         // Not in current loop? It must be an exit block.
         ExitEdges.emplace_back(BB, Succ);
 }
@@ -495,7 +497,7 @@ static void discoverAndMapSubloop(LoopT *L, ArrayRef<BlockT *> Backedges,
       // Discover a subloop of this loop.
       Subloop->setParentLoop(L);
       ++NumSubloops;
-      NumBlocks += Subloop->getBlocksVector().capacity();
+      NumBlocks += Subloop->getBlocksCapacity();
       PredBB = Subloop->getHeader();
       // Continue traversal along predecessors that are not loop-back edges from
       // within this subloop tree itself. Note that a predecessor may directly
@@ -507,7 +509,7 @@ static void discoverAndMapSubloop(LoopT *L, ArrayRef<BlockT *> Backedges,
       }
     }
   }
-  L->getSubLoopsVector().reserve(NumSubloops);
+  L->reserveSubLoops(NumSubloops);
   L->reserveBlocks(NumBlocks);
 }
 
@@ -544,15 +546,14 @@ void PopulateLoopsDFS<BlockT, LoopT>::insertIntoLoop(BlockT *Block) {
     // We reach this point once per subloop after processing all the blocks in
     // the subloop.
     if (!Subloop->isOutermost())
-      Subloop->getParentLoop()->getSubLoopsVector().push_back(Subloop);
+      Subloop->getParentLoop()->SubLoops.push_back(Subloop);
     else
       LI->addTopLevelLoop(Subloop);
 
     // For convenience, Blocks and Subloops are inserted in postorder. Reverse
     // the lists, except for the loop header, which is always at the beginning.
     Subloop->reverseBlock(1);
-    std::reverse(Subloop->getSubLoopsVector().begin(),
-                 Subloop->getSubLoopsVector().end());
+    std::reverse(Subloop->SubLoops.begin(), Subloop->SubLoops.end());
 
     Subloop = Subloop->getParentLoop();
   }
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
index cad1513f280fb..16b928594b7eb 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
@@ -1122,7 +1122,7 @@ class llvm::AMDGPUNextUseAnalysisImpl {
   MBBDistPair calcShortestDistanceToExit(const MachineBasicBlock *CurMBB,
                                          const MachineLoop *CurLoop) const {
     SmallVector<std::pair<MachineBasicBlock *, MachineBasicBlock *>> ExitEdges;
-    CurLoop->getExitEdges(ExitEdges);
+    MLI->getExitEdges(MLI->ref(CurLoop), ExitEdges);
     MBBDistPair LD;
 
     for (auto [Exit, Dest] : ExitEdges) {
diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
index 0664eed072a9a..4ce52179992dd 100644
--- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -488,7 +488,7 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
   // the situation of needing to be able to solve statically which exit block
   // will be branched to, or trying to preserve the branching logic in a loop
   // invariant manner.
-  if (!ExitBlock && !L->hasNoExitBlocks()) {
+  if (!ExitBlock && !LI.hasNoExitBlocks(LI.ref(L))) {
     LLVM_DEBUG(dbgs() << "Deletion requires at most one exit block.\n");
     return LoopDeletionResult::Unmodified;
   }
diff --git a/llvm/lib/Transforms/Scalar/LoopPredication.cpp b/llvm/lib/Transforms/Scalar/LoopPredication.cpp
index de5365271e233..2487a5786c8e1 100644
--- a/llvm/lib/Transforms/Scalar/LoopPredication.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPredication.cpp
@@ -877,7 +877,7 @@ bool LoopPredication::isLoopProfitableToPredicate() {
     return true;
 
   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 8> ExitEdges;
-  L->getExitEdges(ExitEdges);
+  LI->getExitEdges(LI->ref(L), ExitEdges);
   // If there is only one exiting edge in the loop, it is always profitable to
   // predicate the loop.
   if (ExitEdges.size() == 1)
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 89c0288140237..60a2151e26c94 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -509,14 +509,9 @@ static void hoistLoopToNewParent(Loop &L, BasicBlock &Preheader,
   // no-longer-containing loops to reflect the nesting change.
   for (Loop *OldContainingL = OldParentL; OldContainingL != NewParentL;
        OldContainingL = OldContainingL->getParentLoop()) {
-    llvm::erase_if(OldContainingL->getBlocksVector(),
-                   [&](const BasicBlock *BB) {
-                     return BB == &Preheader || L.contains(BB);
-                   });
-
-    OldContainingL->getBlocksSet().erase(&Preheader);
-    for (BasicBlock *BB : L.blocks())
-      OldContainingL->getBlocksSet().erase(BB);
+    LI.removeBlocksIf(LI.ref(OldContainingL), [&](const BasicBlock *BB) {
+      return BB == &Preheader || L.contains(BB);
+    });
 
     // Because we just hoisted a loop out of this one, we have essentially
     // created new exit paths from it. That means we need to form LCSSA PHI
@@ -593,7 +588,7 @@ static bool unswitchTrivialBranch(Loop &L, CondBrInst &BI, DominatorTree &DT,
 
   std::optional<int> LatchIdx = std::nullopt;
   auto *LoopLatch = L.getLoopLatch();
-  auto *ULExit = L.getUniqueLatchExitBlock();
+  auto *ULExit = LI.getUniqueLatchExitBlock(LI.ref(&L));
   if (SE && FullUnswitch && ULExit) {
     if (BI.getSuccessor(0) == LoopLatch && L.contains(BI.getSuccessor(1)))
       LatchIdx = 0;
@@ -1845,18 +1840,17 @@ static void deleteDeadBlocksFromLoop(Loop &L,
                  [&](BasicBlock *BB) { return DeadBlockSet.count(BB); });
 
   // Walk from this loop up through its parents removing all of the dead blocks.
-  for (Loop *ParentL = &L; ParentL; ParentL = ParentL->getParentLoop()) {
-    for (auto *BB : DeadBlockSet)
-      ParentL->getBlocksSet().erase(BB);
-    llvm::erase_if(ParentL->getBlocksVector(),
-                   [&](BasicBlock *BB) { return DeadBlockSet.count(BB); });
-  }
-
-  // Now delete the dead child loops. This raw delete will clear them
-  // recursively.
-  llvm::erase_if(L.getSubLoopsVector(), [&](Loop *ChildL) {
+  for (Loop *ParentL = &L; ParentL; ParentL = ParentL->getParentLoop())
+    LI.removeBlocksIf(LI.ref(ParentL),
+                      [&](BasicBlock *BB) { return DeadBlockSet.count(BB); });
+
+  // Now delete the dead child loops. Run the per-child deletion callbacks
+  // first, while the loop forest is still fully consistent (markLoopAsDeleted
+  // checks the child's position in it), then detach the dead children and
+  // destroy them.
+  for (Loop *ChildL : L) {
     if (!DeadBlockSet.count(ChildL->getHeader()))
-      return false;
+      continue;
 
     assert(llvm::all_of(ChildL->blocks(),
                         [&](BasicBlock *ChildBB) {
@@ -1867,9 +1861,11 @@ static void deleteDeadBlocksFromLoop(Loop &L,
     LoopUpdater.markLoopAsDeleted(*ChildL, ChildL->getName());
     if (SE)
       SE->forgetBlockAndLoopDispositions();
+  }
+  for (Loop *ChildL : LI.takeChildrenIf(LI.ref(&L), [&](Loop *ChildL) {
+         return DeadBlockSet.count(ChildL->getHeader());
+       }))
     LI.destroy(ChildL);
-    return true;
-  });
 
   // Remove the loop mappings for the dead blocks and drop all the references
   // from these blocks to others to handle cyclic references as we start
@@ -2044,15 +2040,10 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
   // *up* the nest.
   if (!LoopBlockSet.empty() && L.getParentLoop() != ParentL) {
     // Remove this loop's (original) blocks from all of the intervening loops.
-    for (Loop *IL = L.getParentLoop(); IL != ParentL;
-         IL = IL->getParentLoop()) {
-      IL->getBlocksSet().erase(PH);
-      for (auto *BB : L.blocks())
-        IL->getBlocksSet().erase(BB);
-      llvm::erase_if(IL->getBlocksVector(), [&](BasicBlock *BB) {
+    for (Loop *IL = L.getParentLoop(); IL != ParentL; IL = IL->getParentLoop())
+      LI.removeBlocksIf(LI.ref(IL), [&](BasicBlock *BB) {
         return BB == PH || L.contains(BB);
       });
-    }
 
     LI.changeLoopFor(PH, ParentL);
     L.getParentLoop()->removeChildLoop(&L);
@@ -2062,25 +2053,18 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
       LI.addTopLevelLoop(&L);
   }
 
-  // Now we update all the blocks which are no longer within the loop.
-  auto &Blocks = L.getBlocksVector();
-  auto BlocksSplitI =
-      LoopBlockSet.empty()
-          ? Blocks.begin()
-          : std::stable_partition(
-                Blocks.begin(), Blocks.end(),
-                [&](BasicBlock *BB) { return LoopBlockSet.count(BB); });
-
-  // Before we erase the list of unlooped blocks, build a set of them.
-  SmallPtrSet<BasicBlock *, 16> UnloopedBlocks(BlocksSplitI, Blocks.end());
+  // Now we update all the blocks which are no longer within the loop, building
+  // the set of them as they are removed.
+  SmallPtrSet<BasicBlock *, 16> UnloopedBlocks;
+  LI.removeBlocksIf(LI.ref(&L), [&](BasicBlock *BB) {
+    if (LoopBlockSet.count(BB))
+      return false;
+    UnloopedBlocks.insert(BB);
+    return true;
+  });
   if (LoopBlockSet.empty())
     UnloopedBlocks.insert(PH);
 
-  // Now erase these blocks from the loop.
-  for (auto *BB : make_range(BlocksSplitI, Blocks.end()))
-    L.getBlocksSet().erase(BB);
-  Blocks.erase(BlocksSplitI, Blocks.end());
-
   // Sort the exits in ascending loop depth, we'll work backwards across these
   // to process them inside out.
   llvm::stable_sort(ExitsInLoops, [&](BasicBlock *LHS, BasicBlock *RHS) {
@@ -2092,10 +2076,8 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
   Loop *PrevExitL = L.getParentLoop(); // The deepest possible exit loop.
 
   auto RemoveUnloopedBlocksFromLoop =
-      [](Loop &L, SmallPtrSetImpl<BasicBlock *> &UnloopedBlocks) {
-        for (auto *BB : UnloopedBlocks)
-          L.getBlocksSet().erase(BB);
-        llvm::erase_if(L.getBlocksVector(), [&](BasicBlock *BB) {
+      [&LI](Loop &L, SmallPtrSetImpl<BasicBlock *> &UnloopedBlocks) {
+        LI.removeBlocksIf(LI.ref(&L), [&](BasicBlock *BB) {
           return UnloopedBlocks.count(BB);
         });
       };
@@ -2171,19 +2153,11 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
         LI.changeLoopFor(BB, nullptr);
 
   // Sink all the child loops whose headers are no longer in the loop set to
-  // the parent (or to be top level loops). We reach into the loop and directly
-  // update its subloop vector to make this batch update efficient.
-  auto &SubLoops = L.getSubLoopsVector();
-  auto SubLoopsSplitI =
-      LoopBlockSet.empty()
-          ? SubLoops.begin()
-          : std::stable_partition(
-                SubLoops.begin(), SubLoops.end(), [&](Loop *SubL) {
-                  return LoopBlockSet.count(SubL->getHeader());
-                });
-  for (auto *HoistedL : make_range(SubLoopsSplitI, SubLoops.end())) {
+  // the parent (or to be top level loops).
+  for (Loop *HoistedL : LI.takeChildrenIf(LI.ref(&L), [&](Loop *SubL) {
+         return !LoopBlockSet.count(SubL->getHeader());
+       })) {
     HoistedLoops.push_back(HoistedL);
-    HoistedL->setParentLoop(nullptr);
 
     // To compute the new parent of this hoisted loop we look at where we
     // placed the preheader above. We can't lookup the header itself because we
@@ -2198,11 +2172,10 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
     else
       LI.addTopLevelLoop(HoistedL);
   }
-  SubLoops.erase(SubLoopsSplitI, SubLoops.end());
 
   // Actually delete the loop if nothing remained within it.
-  if (Blocks.empty()) {
-    assert(SubLoops.empty() &&
+  if (L.getBlocks().empty()) {
+    assert(L.getSubLoops().empty() &&
            "Failed to remove all subloops from the original loop!");
     if (Loop *ParentL = L.getParentLoop())
       ParentL->removeChildLoop(llvm::find(*ParentL, &L));
@@ -2955,7 +2928,7 @@ static int CalculateUnswitchCostMultiplier(
         std::max<int>(ParentL->getNumBlocks() / UnswitchParentBlocksDiv, 1);
 
   int SiblingsCount =
-      (ParentL ? ParentL->getSubLoopsVector().size() : llvm::size(LI));
+      (ParentL ? ParentL->getSubLoops().size() : llvm::size(LI));
   // Count amount of clones that all the candidates might cause during
   // unswitching. Branch/guard/select counts as 1, switch counts as log2 of its
   // cases.
diff --git a/llvm/lib/Transforms/Utils/FixIrreducible.cpp b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
index 77e8cb838ca75..6fe5f2a22bc32 100644
--- a/llvm/lib/Transforms/Utils/FixIrreducible.cpp
+++ b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
@@ -180,15 +180,12 @@ INITIALIZE_PASS_END(FixIrreducible, "fix-irreducible",
 // fully inside the new loop. Reconnect these as children of the new loop.
 static void reconnectChildLoops(LoopInfo &LI, Loop *ParentLoop, Loop *NewLoop,
                                 BasicBlock *OldHeader) {
-  auto &CandidateLoops = ParentLoop ? ParentLoop->getSubLoopsVector()
-                                    : LI.getTopLevelLoopsVector();
-  // Any candidate is a child iff its header is owned by the new loop. Move all
-  // the children to a new vector.
-  auto FirstChild = llvm::partition(CandidateLoops, [&](Loop *L) {
-    return NewLoop == L || !NewLoop->contains(L->getHeader());
-  });
-  SmallVector<Loop *, 8> ChildLoops(FirstChild, CandidateLoops.end());
-  CandidateLoops.erase(FirstChild, CandidateLoops.end());
+  // Any candidate (sibling of NewLoop, or top-level loop if there is no
+  // parent) is a child iff its header is owned by the new loop.
+  SmallVector<Loop *, 4> ChildLoops =
+      LI.takeChildrenIf(LI.ref(ParentLoop), [&](Loop *L) {
+        return NewLoop != L && NewLoop->contains(L->getHeader());
+      });
 
   for (Loop *Child : ChildLoops) {
     LLVM_DEBUG(dbgs() << "child loop: " << Child->getHeader()->getName()
@@ -203,18 +200,14 @@ static void reconnectChildLoops(LoopInfo &LI, Loop *ParentLoop, Loop *NewLoop,
         LLVM_DEBUG(dbgs() << "moved block from child: " << BB->getName()
                           << "\n");
       }
-      std::vector<Loop *> GrandChildLoops;
-      std::swap(GrandChildLoops, Child->getSubLoopsVector());
-      for (auto *GrandChildLoop : GrandChildLoops) {
-        GrandChildLoop->setParentLoop(nullptr);
+      for (Loop *GrandChildLoop :
+           LI.takeChildrenIf(LI.ref(Child), [](const Loop *) { return true; }))
         NewLoop->addChildLoop(GrandChildLoop);
-      }
       LI.destroy(Child);
       LLVM_DEBUG(dbgs() << "subsumed child loop (common header)\n");
       continue;
     }
 
-    Child->setParentLoop(nullptr);
     NewLoop->addChildLoop(Child);
     LLVM_DEBUG(dbgs() << "added child loop to new loop\n");
   }
diff --git a/llvm/lib/Transforms/Utils/LoopPeel.cpp b/llvm/lib/Transforms/Utils/LoopPeel.cpp
index 9488b91caa830..3fe61fd2020ef 100644
--- a/llvm/lib/Transforms/Utils/LoopPeel.cpp
+++ b/llvm/lib/Transforms/Utils/LoopPeel.cpp
@@ -1120,7 +1120,7 @@ void llvm::peelLoop(Loop *L, unsigned PeelCount, bool PeelLast, LoopInfo *LI,
   BasicBlock *PreHeader = L->getLoopPreheader();
   BasicBlock *Latch = L->getLoopLatch();
   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 4> ExitEdges;
-  L->getExitEdges(ExitEdges);
+  LI->getExitEdges(LI->ref(L), ExitEdges);
 
   // Remember dominators of blocks we might reach through exits to change them
   // later. Immediate dominator of such block might change, because we add more
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 58b52519beaf4..224f247ba5c30 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -598,7 +598,7 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
     // Remove the old branch.
     Preheader->getTerminator()->eraseFromParent();
   } else {
-    assert(L->hasNoExitBlocks() &&
+    assert((!LI || LI->hasNoExitBlocks(LI->ref(L))) &&
            "Loop should have either zero or one exit blocks.");
 
     Builder.SetInsertPoint(OldTerm);
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 4cd6a55f01a90..39f81794bd9fe 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5982,7 +5982,8 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
   std::optional<uint64_t> MaxRuntimeStep;
   if (auto MaxVScale = getMaxVScale(*CM.TheFunction, CM.TTI))
     MaxRuntimeStep = uint64_t(*MaxVScale) * BestVF.getKnownMinValue() * BestUF;
-  assert((OrigLoop->getUniqueLatchExitBlock() || RequiresScalarEpilogue) &&
+  assert((LI->getUniqueLatchExitBlock(LI->ref(OrigLoop)) ||
+          RequiresScalarEpilogue) &&
          "loops not exiting via the latch without required epilogue?");
   VPlanTransforms::materializeVectorTripCount(
       BestVPlan, VectorPH, HasTailFolded, RequiresScalarEpilogue,
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 7d69b3453cba9..80199a55744f5 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -1006,7 +1006,8 @@ void VPlan::execute(VPTransformState *State) {
 
     Loop *OrigLoop =
         State->LI->getLoopFor(getScalarHeader()->getIRBasicBlock());
-    auto Blocks = OrigLoop->getBlocksVector();
+    SmallVector<BasicBlock *> Blocks(OrigLoop->block_begin(),
+                                     OrigLoop->block_end());
     Blocks.push_back(ScalarPh);
     while (!OrigLoop->isInnermost())
       State->LI->erase(*OrigLoop->begin());
diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp
index c2fe4e7d62119..dc628eeb8bf50 100644
--- a/polly/lib/Analysis/ScopDetection.cpp
+++ b/polly/lib/Analysis/ScopDetection.cpp
@@ -1419,7 +1419,7 @@ ScopDetection::countBeneficialLoops(Region *R, ScalarEvolution &SE,
   }
 
   auto SubLoops =
-      L ? L->getSubLoopsVector() : std::vector<Loop *>(LI.begin(), LI.end());
+      L ? L->getSubLoops() : std::vector<Loop *>(LI.begin(), LI.end());
 
   for (auto &SubLoop : SubLoops)
     if (R->contains(SubLoop)) {

>From cb0e1807b0d76283056ca2705d86a54315bea977 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Mon, 20 Jul 2026 00:05:39 -0700
Subject: [PATCH 2/2] avoid ref in call sites

---
 bolt/lib/Core/BinaryFunction.cpp              |  2 +-
 llvm/include/llvm/Support/GenericLoopInfo.h   |  8 +++----
 .../llvm/Support/GenericLoopInfoImpl.h        |  5 ++---
 .../Target/AMDGPU/AMDGPUNextUseAnalysis.cpp   |  2 +-
 llvm/lib/Transforms/Scalar/LoopDeletion.cpp   |  2 +-
 .../lib/Transforms/Scalar/LoopPredication.cpp |  2 +-
 .../Transforms/Scalar/SimpleLoopUnswitch.cpp  | 22 +++++++++----------
 llvm/lib/Transforms/Utils/FixIrreducible.cpp  |  4 ++--
 llvm/lib/Transforms/Utils/LoopPeel.cpp        |  2 +-
 llvm/lib/Transforms/Utils/LoopUtils.cpp       |  2 +-
 .../Transforms/Vectorize/LoopVectorize.cpp    |  3 +--
 11 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index e0a76c1462654..2641f270f476b 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -4501,7 +4501,7 @@ void BinaryFunction::calculateLoopInfo() {
 
     // Compute exit count.
     SmallVector<BinaryLoop::Edge, 1> ExitEdges;
-    BLI->getExitEdges(BLI->ref(L), ExitEdges);
+    BLI->getExitEdges(L, ExitEdges);
     for (BinaryLoop::Edge &Exit : ExitEdges) {
       const BinaryBasicBlock *Exiting = Exit.first;
       const BinaryBasicBlock *ExitTarget = Exit.second;
diff --git a/llvm/include/llvm/Support/GenericLoopInfo.h b/llvm/include/llvm/Support/GenericLoopInfo.h
index e83d1fdccfbe0..42d0d370676a9 100644
--- a/llvm/include/llvm/Support/GenericLoopInfo.h
+++ b/llvm/include/llvm/Support/GenericLoopInfo.h
@@ -59,11 +59,13 @@ template <class N, class M> class PopulateLoopsDFS;
 class LoopRef {
   void *Ptr = nullptr;
 
-  explicit LoopRef(void *Ptr) : Ptr(Ptr) {}
   template <class N, class M> friend class LoopInfoBase;
 
 public:
   LoopRef() = default;
+  template <class BlockT, class LoopT>
+  LoopRef(const LoopBase<BlockT, LoopT> *L)
+      : Ptr(static_cast<LoopT *>(const_cast<LoopBase<BlockT, LoopT> *>(L))) {}
   bool isValid() const { return Ptr != nullptr; }
   explicit operator bool() const { return isValid(); }
   bool operator==(LoopRef O) const { return Ptr == O.Ptr; }
@@ -652,9 +654,7 @@ template <class BlockT, class LoopT> class LoopInfoBase {
     return L ? L->getLoopDepth() : 0;
   }
 
-  /// The handle for a loop of this LoopInfo; an invalid handle for null.
-  LoopRef ref(const LoopT *L) const { return LoopRef(const_cast<LoopT *>(L)); }
-
+  /// Edge type.
   using Edge = std::pair<BlockT *, BlockT *>;
 
   /// Return true if \p L does not have any exit blocks.
diff --git a/llvm/include/llvm/Support/GenericLoopInfoImpl.h b/llvm/include/llvm/Support/GenericLoopInfoImpl.h
index 434dc6feaa545..3baf0a08cb785 100644
--- a/llvm/include/llvm/Support/GenericLoopInfoImpl.h
+++ b/llvm/include/llvm/Support/GenericLoopInfoImpl.h
@@ -168,7 +168,7 @@ BlockT *LoopInfoBase<BlockT, LoopT>::getUniqueLatchExitBlock(LoopRef L) const {
     assert(!AllowRepeats && "Unexpected parameter value.");
     return !Lp->contains(BB) ? BB : nullptr;
   };
-  return find_singleton<BlockT>(llvm::children<BlockT *>(Latch), IsExitBlock);
+  return find_singleton<BlockT>(children<BlockT *>(Latch), IsExitBlock);
 }
 
 /// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
@@ -176,9 +176,8 @@ template <class BlockT, class LoopT>
 void LoopInfoBase<BlockT, LoopT>::getExitEdges(
     LoopRef L, SmallVectorImpl<Edge> &ExitEdges) const {
   const LoopT *Lp = deref(L);
-  assert(!Lp->isInvalid() && "Loop not in a valid state!");
   for (const auto BB : Lp->blocks())
-    for (auto *Succ : llvm::children<BlockT *>(BB))
+    for (auto *Succ : children<BlockT *>(BB))
       if (!Lp->contains(Succ))
         // Not in current loop? It must be an exit block.
         ExitEdges.emplace_back(BB, Succ);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
index 16b928594b7eb..66d35f726f51c 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUNextUseAnalysis.cpp
@@ -1122,7 +1122,7 @@ class llvm::AMDGPUNextUseAnalysisImpl {
   MBBDistPair calcShortestDistanceToExit(const MachineBasicBlock *CurMBB,
                                          const MachineLoop *CurLoop) const {
     SmallVector<std::pair<MachineBasicBlock *, MachineBasicBlock *>> ExitEdges;
-    MLI->getExitEdges(MLI->ref(CurLoop), ExitEdges);
+    MLI->getExitEdges(CurLoop, ExitEdges);
     MBBDistPair LD;
 
     for (auto [Exit, Dest] : ExitEdges) {
diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
index 4ce52179992dd..56957aa08868a 100644
--- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -488,7 +488,7 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
   // the situation of needing to be able to solve statically which exit block
   // will be branched to, or trying to preserve the branching logic in a loop
   // invariant manner.
-  if (!ExitBlock && !LI.hasNoExitBlocks(LI.ref(L))) {
+  if (!ExitBlock && !LI.hasNoExitBlocks(L)) {
     LLVM_DEBUG(dbgs() << "Deletion requires at most one exit block.\n");
     return LoopDeletionResult::Unmodified;
   }
diff --git a/llvm/lib/Transforms/Scalar/LoopPredication.cpp b/llvm/lib/Transforms/Scalar/LoopPredication.cpp
index 2487a5786c8e1..d39f02f40651f 100644
--- a/llvm/lib/Transforms/Scalar/LoopPredication.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPredication.cpp
@@ -877,7 +877,7 @@ bool LoopPredication::isLoopProfitableToPredicate() {
     return true;
 
   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 8> ExitEdges;
-  LI->getExitEdges(LI->ref(L), ExitEdges);
+  LI->getExitEdges(L, ExitEdges);
   // If there is only one exiting edge in the loop, it is always profitable to
   // predicate the loop.
   if (ExitEdges.size() == 1)
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 60a2151e26c94..ce9bc612a6e2d 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -509,7 +509,7 @@ static void hoistLoopToNewParent(Loop &L, BasicBlock &Preheader,
   // no-longer-containing loops to reflect the nesting change.
   for (Loop *OldContainingL = OldParentL; OldContainingL != NewParentL;
        OldContainingL = OldContainingL->getParentLoop()) {
-    LI.removeBlocksIf(LI.ref(OldContainingL), [&](const BasicBlock *BB) {
+    LI.removeBlocksIf(OldContainingL, [&](const BasicBlock *BB) {
       return BB == &Preheader || L.contains(BB);
     });
 
@@ -588,7 +588,7 @@ static bool unswitchTrivialBranch(Loop &L, CondBrInst &BI, DominatorTree &DT,
 
   std::optional<int> LatchIdx = std::nullopt;
   auto *LoopLatch = L.getLoopLatch();
-  auto *ULExit = LI.getUniqueLatchExitBlock(LI.ref(&L));
+  auto *ULExit = LI.getUniqueLatchExitBlock(&L);
   if (SE && FullUnswitch && ULExit) {
     if (BI.getSuccessor(0) == LoopLatch && L.contains(BI.getSuccessor(1)))
       LatchIdx = 0;
@@ -1841,7 +1841,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
 
   // Walk from this loop up through its parents removing all of the dead blocks.
   for (Loop *ParentL = &L; ParentL; ParentL = ParentL->getParentLoop())
-    LI.removeBlocksIf(LI.ref(ParentL),
+    LI.removeBlocksIf(ParentL,
                       [&](BasicBlock *BB) { return DeadBlockSet.count(BB); });
 
   // Now delete the dead child loops. Run the per-child deletion callbacks
@@ -1862,7 +1862,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
     if (SE)
       SE->forgetBlockAndLoopDispositions();
   }
-  for (Loop *ChildL : LI.takeChildrenIf(LI.ref(&L), [&](Loop *ChildL) {
+  for (Loop *ChildL : LI.takeChildrenIf(&L, [&](Loop *ChildL) {
          return DeadBlockSet.count(ChildL->getHeader());
        }))
     LI.destroy(ChildL);
@@ -2041,9 +2041,8 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
   if (!LoopBlockSet.empty() && L.getParentLoop() != ParentL) {
     // Remove this loop's (original) blocks from all of the intervening loops.
     for (Loop *IL = L.getParentLoop(); IL != ParentL; IL = IL->getParentLoop())
-      LI.removeBlocksIf(LI.ref(IL), [&](BasicBlock *BB) {
-        return BB == PH || L.contains(BB);
-      });
+      LI.removeBlocksIf(
+          IL, [&](BasicBlock *BB) { return BB == PH || L.contains(BB); });
 
     LI.changeLoopFor(PH, ParentL);
     L.getParentLoop()->removeChildLoop(&L);
@@ -2056,7 +2055,7 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
   // Now we update all the blocks which are no longer within the loop, building
   // the set of them as they are removed.
   SmallPtrSet<BasicBlock *, 16> UnloopedBlocks;
-  LI.removeBlocksIf(LI.ref(&L), [&](BasicBlock *BB) {
+  LI.removeBlocksIf(&L, [&](BasicBlock *BB) {
     if (LoopBlockSet.count(BB))
       return false;
     UnloopedBlocks.insert(BB);
@@ -2077,9 +2076,8 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
 
   auto RemoveUnloopedBlocksFromLoop =
       [&LI](Loop &L, SmallPtrSetImpl<BasicBlock *> &UnloopedBlocks) {
-        LI.removeBlocksIf(LI.ref(&L), [&](BasicBlock *BB) {
-          return UnloopedBlocks.count(BB);
-        });
+        LI.removeBlocksIf(
+            &L, [&](BasicBlock *BB) { return UnloopedBlocks.count(BB); });
       };
 
   SmallVector<BasicBlock *, 16> Worklist;
@@ -2154,7 +2152,7 @@ static bool rebuildLoopAfterUnswitch(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
 
   // Sink all the child loops whose headers are no longer in the loop set to
   // the parent (or to be top level loops).
-  for (Loop *HoistedL : LI.takeChildrenIf(LI.ref(&L), [&](Loop *SubL) {
+  for (Loop *HoistedL : LI.takeChildrenIf(&L, [&](Loop *SubL) {
          return !LoopBlockSet.count(SubL->getHeader());
        })) {
     HoistedLoops.push_back(HoistedL);
diff --git a/llvm/lib/Transforms/Utils/FixIrreducible.cpp b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
index 6fe5f2a22bc32..db0c3c0e50704 100644
--- a/llvm/lib/Transforms/Utils/FixIrreducible.cpp
+++ b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
@@ -183,7 +183,7 @@ static void reconnectChildLoops(LoopInfo &LI, Loop *ParentLoop, Loop *NewLoop,
   // Any candidate (sibling of NewLoop, or top-level loop if there is no
   // parent) is a child iff its header is owned by the new loop.
   SmallVector<Loop *, 4> ChildLoops =
-      LI.takeChildrenIf(LI.ref(ParentLoop), [&](Loop *L) {
+      LI.takeChildrenIf(ParentLoop, [&](Loop *L) {
         return NewLoop != L && NewLoop->contains(L->getHeader());
       });
 
@@ -201,7 +201,7 @@ static void reconnectChildLoops(LoopInfo &LI, Loop *ParentLoop, Loop *NewLoop,
                           << "\n");
       }
       for (Loop *GrandChildLoop :
-           LI.takeChildrenIf(LI.ref(Child), [](const Loop *) { return true; }))
+           LI.takeChildrenIf(Child, [](const Loop *) { return true; }))
         NewLoop->addChildLoop(GrandChildLoop);
       LI.destroy(Child);
       LLVM_DEBUG(dbgs() << "subsumed child loop (common header)\n");
diff --git a/llvm/lib/Transforms/Utils/LoopPeel.cpp b/llvm/lib/Transforms/Utils/LoopPeel.cpp
index 3fe61fd2020ef..4f5b79c7b0812 100644
--- a/llvm/lib/Transforms/Utils/LoopPeel.cpp
+++ b/llvm/lib/Transforms/Utils/LoopPeel.cpp
@@ -1120,7 +1120,7 @@ void llvm::peelLoop(Loop *L, unsigned PeelCount, bool PeelLast, LoopInfo *LI,
   BasicBlock *PreHeader = L->getLoopPreheader();
   BasicBlock *Latch = L->getLoopLatch();
   SmallVector<std::pair<BasicBlock *, BasicBlock *>, 4> ExitEdges;
-  LI->getExitEdges(LI->ref(L), ExitEdges);
+  LI->getExitEdges(L, ExitEdges);
 
   // Remember dominators of blocks we might reach through exits to change them
   // later. Immediate dominator of such block might change, because we add more
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 224f247ba5c30..8b594ddf6a355 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -598,7 +598,7 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
     // Remove the old branch.
     Preheader->getTerminator()->eraseFromParent();
   } else {
-    assert((!LI || LI->hasNoExitBlocks(LI->ref(L))) &&
+    assert((!LI || LI->hasNoExitBlocks(L)) &&
            "Loop should have either zero or one exit blocks.");
 
     Builder.SetInsertPoint(OldTerm);
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 39f81794bd9fe..55a8a0adc9fee 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -5982,8 +5982,7 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
   std::optional<uint64_t> MaxRuntimeStep;
   if (auto MaxVScale = getMaxVScale(*CM.TheFunction, CM.TTI))
     MaxRuntimeStep = uint64_t(*MaxVScale) * BestVF.getKnownMinValue() * BestUF;
-  assert((LI->getUniqueLatchExitBlock(LI->ref(OrigLoop)) ||
-          RequiresScalarEpilogue) &&
+  assert((LI->getUniqueLatchExitBlock(OrigLoop) || RequiresScalarEpilogue) &&
          "loops not exiting via the latch without required epilogue?");
   VPlanTransforms::materializeVectorTripCount(
       BestVPlan, VectorPH, HasTailFolded, RequiresScalarEpilogue,



More information about the llvm-commits mailing list