[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