[llvm] [CycleInfo] Move representation-dependent queries to GenericCycleInfo. NFC (PR #209665)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 19:50:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-analysis

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

With the Euler tour representation (#<!-- -->208614), blocks live in
GenericCycleInfo::BlockLayout and GenericCycle keeps a `CI` back-pointer just
so the out-of-line contains(BlockT *) and blocks() can reach it.

Adopt the design suggested by @<!-- -->aengelke, move the
representation-dependent queries to GenericCycleInfo, taking the cycle
as an argument (contains, getBlocks, getExitBlocks, getExitingBlocks,
getCyclePreheader, getCyclePredecessor, verifyCycle, verifyCycleNest,
and per-cycle print), and delete GenericCycle::CI.

- GenericCycleInfo's move operations become defaulted, dropping the
  CI re-pointing walk, and sizeof(GenericCycle) shrinks by a pointer.
- isCycleInvariant gains a MachineCycleInfo parameter, and
  GenericUniformityInfo gains getCycleInfo() for callers that only hold the
  uniformity result.

Aided by Claude Fable 5


---

Patch is 48.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209665.diff


15 Files Affected:

- (modified) llvm/include/llvm/ADT/GenericCycleImpl.h (+71-117) 
- (modified) llvm/include/llvm/ADT/GenericCycleInfo.h (+73-85) 
- (modified) llvm/include/llvm/ADT/GenericUniformityImpl.h (+46-35) 
- (modified) llvm/include/llvm/ADT/GenericUniformityInfo.h (+3) 
- (modified) llvm/include/llvm/CodeGen/MachineCycleAnalysis.h (+4-3) 
- (modified) llvm/include/llvm/IR/GenericConvergenceVerifierImpl.h (+2-2) 
- (modified) llvm/lib/Analysis/CFG.cpp (+1-1) 
- (modified) llvm/lib/Analysis/UniformityAnalysis.cpp (+2-2) 
- (modified) llvm/lib/CodeGen/MachineCycleAnalysis.cpp (+4-3) 
- (modified) llvm/lib/CodeGen/MachineSink.cpp (+4-4) 
- (modified) llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (+2-2) 
- (modified) llvm/lib/Target/AMDGPU/AMDGPUGlobalISelDivergenceLowering.cpp (+2-1) 
- (modified) llvm/lib/Target/AMDGPU/SIInstrInfo.cpp (+1-1) 
- (modified) llvm/lib/Transforms/IPO/AttributorAttributes.cpp (+1-1) 
- (modified) llvm/lib/Transforms/Utils/FixIrreducible.cpp (+11-11) 


``````````diff
diff --git a/llvm/include/llvm/ADT/GenericCycleImpl.h b/llvm/include/llvm/ADT/GenericCycleImpl.h
index dfeb479d764e5..02e6770f0aedd 100644
--- a/llvm/include/llvm/ADT/GenericCycleImpl.h
+++ b/llvm/include/llvm/ADT/GenericCycleImpl.h
@@ -34,60 +34,39 @@
 namespace llvm {
 
 template <typename ContextT>
-bool GenericCycle<ContextT>::contains(const GenericCycle *C) const {
-  // Containment check using the Euler tour representation.
-  return C && IdxBegin <= C->IdxBegin && C->IdxEnd <= IdxEnd;
-}
-
-template <typename ContextT>
-bool GenericCycle<ContextT>::contains(const BlockT *Block) const {
-  return contains(CI->getCycle(Block));
-}
-
-template <typename ContextT>
-auto GenericCycle<ContextT>::block_begin() const -> const_block_iterator {
-  return CI->BlockLayout.begin() + IdxBegin;
-}
-
-template <typename ContextT>
-auto GenericCycle<ContextT>::block_end() const -> const_block_iterator {
-  return CI->BlockLayout.begin() + IdxEnd;
-}
-
-template <typename ContextT>
-void GenericCycle<ContextT>::getExitBlocks(
-    SmallVectorImpl<BlockT *> &TmpStorage) const {
-  if (!ExitBlocksCache.empty()) {
-    TmpStorage.append(ExitBlocksCache.begin(), ExitBlocksCache.end());
+void GenericCycleInfo<ContextT>::getExitBlocks(
+    const CycleT &C, SmallVectorImpl<BlockT *> &TmpStorage) const {
+  if (!C.ExitBlocksCache.empty()) {
+    TmpStorage.append(C.ExitBlocksCache.begin(), C.ExitBlocksCache.end());
     return;
   }
 
   size_t NumExitBlocks = 0;
-  for (BlockT *Block : blocks()) {
-    llvm::append_range(ExitBlocksCache, successors(Block));
+  for (BlockT *Block : getBlocks(C)) {
+    llvm::append_range(C.ExitBlocksCache, successors(Block));
 
-    for (size_t Idx = NumExitBlocks, End = ExitBlocksCache.size(); Idx < End;
+    for (size_t Idx = NumExitBlocks, End = C.ExitBlocksCache.size(); Idx < End;
          ++Idx) {
-      BlockT *Succ = ExitBlocksCache[Idx];
-      if (!contains(Succ)) {
-        auto ExitEndIt = ExitBlocksCache.begin() + NumExitBlocks;
-        if (std::find(ExitBlocksCache.begin(), ExitEndIt, Succ) == ExitEndIt)
-          ExitBlocksCache[NumExitBlocks++] = Succ;
+      BlockT *Succ = C.ExitBlocksCache[Idx];
+      if (!contains(&C, Succ)) {
+        auto ExitEndIt = C.ExitBlocksCache.begin() + NumExitBlocks;
+        if (std::find(C.ExitBlocksCache.begin(), ExitEndIt, Succ) == ExitEndIt)
+          C.ExitBlocksCache[NumExitBlocks++] = Succ;
       }
     }
 
-    ExitBlocksCache.resize(NumExitBlocks);
+    C.ExitBlocksCache.resize(NumExitBlocks);
   }
 
-  TmpStorage.append(ExitBlocksCache.begin(), ExitBlocksCache.end());
+  TmpStorage.append(C.ExitBlocksCache.begin(), C.ExitBlocksCache.end());
 }
 
 template <typename ContextT>
-void GenericCycle<ContextT>::getExitingBlocks(
-    SmallVectorImpl<BlockT *> &TmpStorage) const {
-  for (BlockT *Block : blocks()) {
+void GenericCycleInfo<ContextT>::getExitingBlocks(
+    const CycleT &C, SmallVectorImpl<BlockT *> &TmpStorage) const {
+  for (BlockT *Block : getBlocks(C)) {
     for (BlockT *Succ : successors(Block)) {
-      if (!contains(Succ)) {
+      if (!contains(&C, Succ)) {
         TmpStorage.push_back(Block);
         break;
       }
@@ -96,12 +75,13 @@ void GenericCycle<ContextT>::getExitingBlocks(
 }
 
 template <typename ContextT>
-auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
-  BlockT *Predecessor = getCyclePredecessor();
+auto GenericCycleInfo<ContextT>::getCyclePreheader(const CycleT &C) const
+    -> BlockT * {
+  BlockT *Predecessor = getCyclePredecessor(C);
   if (!Predecessor)
     return nullptr;
 
-  assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
+  assert(C.isReducible() && "Cycle Predecessor must be in a reducible cycle!");
 
   if (succ_size(Predecessor) != 1)
     return nullptr;
@@ -114,16 +94,17 @@ auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
 }
 
 template <typename ContextT>
-auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
-  if (!isReducible())
+auto GenericCycleInfo<ContextT>::getCyclePredecessor(const CycleT &C) const
+    -> BlockT * {
+  if (!C.isReducible())
     return nullptr;
 
   BlockT *Out = nullptr;
 
   // Loop over the predecessors of the header node...
-  BlockT *Header = getHeader();
+  BlockT *Header = C.getHeader();
   for (const auto Pred : predecessors(Header)) {
-    if (!contains(Pred)) {
+    if (!contains(&C, Pred)) {
       if (Out && Out != Pred)
         return nullptr;
       Out = Pred;
@@ -133,25 +114,25 @@ auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
   return Out;
 }
 
-/// \brief Verify that this is actually a well-formed cycle in the CFG.
-template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
+template <typename ContextT>
+void GenericCycleInfo<ContextT>::verifyCycle(const CycleT &C) const {
 #ifndef NDEBUG
-  assert(getNumBlocks() != 0 && "Cycle cannot be empty.");
+  assert(C.getNumBlocks() != 0 && "Cycle cannot be empty.");
   DenseSet<BlockT *> Blocks;
-  for (BlockT *BB : blocks()) {
+  for (BlockT *BB : getBlocks(C)) {
     assert(Blocks.insert(BB).second); // duplicates in block list?
   }
-  assert(!Entries.empty() && "Cycle must have one or more entries.");
+  assert(!C.Entries.empty() && "Cycle must have one or more entries.");
 
   DenseSet<BlockT *> Entries;
-  for (BlockT *Entry : entries()) {
+  for (BlockT *Entry : C.entries()) {
     assert(Entries.insert(Entry).second); // duplicate entry?
-    assert(contains(Entry));
+    assert(contains(&C, Entry));
   }
 
   // Setup for using a depth-first iterator to visit every block in the cycle.
   SmallVector<BlockT *, 8> ExitBBs;
-  getExitBlocks(ExitBBs);
+  getExitBlocks(C, ExitBBs);
   df_iterator_default_set<BlockT *> VisitSet;
   VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
 
@@ -159,18 +140,18 @@ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
   SmallPtrSet<BlockT *, 8> VisitedBBs;
 
   // Check the individual blocks.
-  for (BlockT *BB : depth_first_ext(getHeader(), VisitSet)) {
+  for (BlockT *BB : depth_first_ext(C.getHeader(), VisitSet)) {
     assert(llvm::any_of(llvm::children<BlockT *>(BB),
-                        [&](BlockT *B) { return contains(B); }) &&
+                        [&](BlockT *B) { return contains(&C, B); }) &&
            "Cycle block has no in-cycle successors!");
 
     assert(llvm::any_of(llvm::inverse_children<BlockT *>(BB),
-                        [&](BlockT *B) { return contains(B); }) &&
+                        [&](BlockT *B) { return contains(&C, B); }) &&
            "Cycle block has no in-cycle predecessors!");
 
     DenseSet<BlockT *> OutsideCyclePreds;
     for (BlockT *B : llvm::inverse_children<BlockT *>(BB))
-      if (!contains(B))
+      if (!contains(&C, B))
         OutsideCyclePreds.insert(B);
 
     if (Entries.contains(BB)) {
@@ -184,13 +165,13 @@ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
         assert(!OutsideCyclePreds.contains(CB) &&
                "Non-entry block reachable from outside!");
     }
-    assert(BB != &getHeader()->getParent()->front() &&
+    assert(BB != &C.getHeader()->getParent()->front() &&
            "Cycle contains function entry block!");
 
     VisitedBBs.insert(BB);
   }
 
-  if (VisitedBBs.size() != getNumBlocks()) {
+  if (VisitedBBs.size() != C.getNumBlocks()) {
     dbgs() << "The following blocks are unreachable in the cycle:\n  ";
     ListSeparator LS;
     for (auto *BB : Blocks) {
@@ -203,34 +184,31 @@ template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
     llvm_unreachable("Unreachable block in cycle");
   }
 
-  verifyCycleNest();
+  verifyCycleNest(C);
 #endif
 }
 
-/// \brief Verify the parent-child relations of this cycle.
-///
-/// Note that this does \em not check that cycle is really a cycle in the CFG.
 template <typename ContextT>
-void GenericCycle<ContextT>::verifyCycleNest() const {
+void GenericCycleInfo<ContextT>::verifyCycleNest(const CycleT &C) const {
 #ifndef NDEBUG
   // Check the subcycles.
-  for (GenericCycle *Child : children()) {
+  for (CycleT *Child : C.children()) {
     // Each block in each subcycle should be contained within this cycle.
-    for (BlockT *BB : Child->blocks()) {
-      assert(contains(BB) &&
+    for (BlockT *BB : getBlocks(*Child)) {
+      assert(contains(&C, BB) &&
              "Cycle does not contain all the blocks of a subcycle!");
     }
-    assert(Child->Depth == Depth + 1);
+    assert(Child->Depth == C.Depth + 1);
   }
 
   // Check the parent cycle pointer.
-  if (ParentCycle) {
-    assert(is_contained(ParentCycle->children(), this) &&
+  if (C.ParentCycle) {
+    assert(is_contained(C.ParentCycle->children(), &C) &&
            "Cycle is not a subcycle of its parent!");
-    assert(ParentCycle->TopLevelCycle == TopLevelCycle &&
+    assert(C.ParentCycle->TopLevelCycle == C.TopLevelCycle &&
            "Top level cycle of parent cycle must be the same");
   } else {
-    assert(TopLevelCycle == this &&
+    assert(C.TopLevelCycle == &C &&
            "Cycle without parent must be top-level cycle");
   }
 #endif
@@ -289,13 +267,6 @@ template <typename ContextT> class GenericCycleInfoCompute {
   void dfs(FunctionT *F, BlockT *EntryBlock);
 };
 
-template <typename ContextT>
-auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(
-    const BlockT *Block) const -> CycleT * {
-  CycleT *Cycle = getCycle(Block);
-  return Cycle ? Cycle->TopLevelCycle : nullptr;
-}
-
 template <typename ContextT>
 void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
                                                               CycleT *Child) {
@@ -320,14 +291,6 @@ void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
   // range-dependent query is used.
 }
 
-template <typename ContextT>
-void GenericCycleInfo<ContextT>::verifyBlockNumberEpoch(
-    const FunctionT *Fn) const {
-  assert(BlockNumberEpoch ==
-             GraphTraits<const FunctionT *>::getNumberEpoch(Fn) &&
-         "CycleInfo used with outdated block number epoch");
-}
-
 template <typename ContextT>
 void GenericCycleInfo<ContextT>::addToBlockMap(BlockT *Block, CycleT *Cycle) {
   // The caller should ensure that BlockMap is large enough.
@@ -438,7 +401,6 @@ void GenericCycleInfoCompute<ContextT>::run(FunctionT *F) {
     LLVM_DEBUG(errs() << "Found cycle for header: "
                       << Info.Context.print(HeaderCandidate) << "\n");
     std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
-    NewCycle->CI = &Info;
     NewCycle->appendEntry(HeaderCandidate);
     Info.addToBlockMap(HeaderCandidate, NewCycle.get());
     // The header is this cycle's first own block. Until layoutBlocks runs,
@@ -624,18 +586,6 @@ void GenericCycleInfo<ContextT>::splitCriticalEdge(BlockT *Pred, BlockT *Succ,
   verifyCycleNest();
 }
 
-/// \brief Find the innermost cycle containing a given block.
-///
-/// \returns the innermost cycle containing \p Block or nullptr if
-///          it is not contained in any cycle.
-template <typename ContextT>
-auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const
-    -> CycleT * {
-  verifyBlockNumberEpoch(Block->getParent());
-  unsigned Number = GraphTraits<const BlockT *>::getNumber(Block);
-  return Number < BlockMap.size() ? BlockMap[Number] : nullptr;
-}
-
 /// \brief Find the innermost cycle containing both given cycles.
 ///
 /// \returns the innermost cycle containing both \p A and \p B
@@ -676,18 +626,6 @@ auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(BlockT *A,
   return getSmallestCommonCycle(getCycle(A), getCycle(B));
 }
 
-/// \brief get the depth for the cycle which containing a given block.
-///
-/// \returns the depth for the innermost cycle containing \p Block or 0 if it is
-///          not contained in any cycle.
-template <typename ContextT>
-unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
-  CycleT *Cycle = getCycle(Block);
-  if (!Cycle)
-    return 0;
-  return Cycle->getDepth();
-}
-
 /// \brief Verify the internal consistency of the cycle tree.
 ///
 /// Note that this does \em not check that cycles are really cycles in the CFG,
@@ -702,11 +640,11 @@ void GenericCycleInfo<ContextT>::verifyCycleNest(bool VerifyFull) const {
       BlockT *Header = Cycle->getHeader();
       assert(CycleHeaders.insert(Header).second);
       if (VerifyFull)
-        Cycle->verifyCycle();
+        verifyCycle(*Cycle);
       else
-        Cycle->verifyCycleNest();
+        verifyCycleNest(*Cycle);
       // Check the block map entries for blocks contained in this cycle.
-      for (BlockT *BB : Cycle->blocks()) {
+      for (BlockT *BB : getBlocks(*Cycle)) {
         CycleT *CycleInBlockMap = getCycle(BB);
         assert(CycleInBlockMap != nullptr);
         assert(Cycle->contains(CycleInBlockMap));
@@ -729,11 +667,27 @@ void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const {
       for (unsigned I = 0; I < Cycle->Depth; ++I)
         Out << "    ";
 
-      Out << Cycle->print(Context) << '\n';
+      Out << print(Cycle) << '\n';
     }
   }
 }
 
+/// \brief Print a single cycle: its depth, entries, and remaining blocks.
+template <typename ContextT>
+Printable GenericCycleInfo<ContextT>::print(const CycleT *Cycle) const {
+  return Printable([this, Cycle](raw_ostream &Out) {
+    Out << "depth=" << Cycle->Depth << ": entries("
+        << Cycle->printEntries(Context) << ')';
+
+    for (auto *Block : getBlocks(*Cycle)) {
+      if (Cycle->isEntry(Block))
+        continue;
+
+      Out << ' ' << Context.print(Block);
+    }
+  });
+}
+
 } // namespace llvm
 
 #undef DEBUG_TYPE
diff --git a/llvm/include/llvm/ADT/GenericCycleInfo.h b/llvm/include/llvm/ADT/GenericCycleInfo.h
index c3093d4cf83e5..d3ffafc7d0d39 100644
--- a/llvm/include/llvm/ADT/GenericCycleInfo.h
+++ b/llvm/include/llvm/ADT/GenericCycleInfo.h
@@ -82,9 +82,6 @@ template <typename ContextT> class GenericCycle {
   ///       always have the same depth.
   unsigned Depth = 0;
 
-  /// The cycle info that owns this cycle. Used by contains(BlockT*).
-  const GenericCycleInfo<ContextT> *CI = nullptr;
-
   /// Cache for the results of GetExitBlocks
   mutable SmallVector<BlockT *, 4> ExitBlocksCache;
 
@@ -130,46 +127,24 @@ template <typename ContextT> class GenericCycle {
   }
 
   /// \brief Replace all entries with \p Block as single entry.
+  /// \p Block must be contained in the cycle.
   void setSingleEntry(BlockT *Block) {
-    assert(contains(Block));
     Entries.clear();
     Entries.push_back(Block);
     clearCache();
   }
 
-  /// \brief Return whether \p Block is contained in the cycle. O(1).
-  bool contains(const BlockT *Block) const;
-
   /// \brief Returns true iff this cycle contains \p C. O(1). Non-strict, i.e.
   /// returns true if C is the same cycle.
-  bool contains(const GenericCycle *C) const;
+  bool contains(const GenericCycle *C) const {
+    return C && IdxBegin <= C->IdxBegin && C->IdxEnd <= IdxEnd;
+  }
 
   const GenericCycle *getParentCycle() const { return ParentCycle; }
   GenericCycle *getParentCycle() { return ParentCycle; }
   unsigned getDepth() const { return Depth; }
 
-  /// Return all of the successor blocks of this cycle.
-  ///
-  /// These are the blocks _outside of the current cycle_ which are
-  /// branched to.
-  void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
-
-  /// Return all blocks of this cycle that have successor outside of this cycle.
-  /// These blocks have cycle exit branch.
-  void getExitingBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
-
-  /// Return the preheader block for this cycle. Pre-header is well-defined for
-  /// reducible cycle in docs/LoopTerminology.md as: the only one entering
-  /// block and its only edge is to the entry block. Return null for irreducible
-  /// cycles.
-  BlockT *getCyclePreheader() const;
-
-  /// If the cycle has exactly one entry with exactly one predecessor, return
-  /// it, otherwise return nullptr.
-  BlockT *getCyclePredecessor() const;
-
-  void verifyCycle() const;
-  void verifyCycleNest() const;
+  size_t getNumBlocks() const { return IdxEnd - IdxBegin; }
 
   /// Iteration over child cycles.
   //@{
@@ -200,19 +175,6 @@ template <typename ContextT> class GenericCycle {
   }
   //@}
 
-  /// Iteration over blocks in the cycle (including entry blocks).
-  //@{
-  using const_block_iterator =
-      typename SmallVector<BlockT *, 8>::const_iterator;
-
-  const_block_iterator block_begin() const;
-  const_block_iterator block_end() const;
-  size_t getNumBlocks() const { return IdxEnd - IdxBegin; }
-  iterator_range<const_block_iterator> blocks() const {
-    return llvm::make_range(block_begin(), block_end());
-  }
-  //@}
-
   /// Iteration over entry blocks.
   //@{
   using const_entry_iterator =
@@ -236,19 +198,6 @@ template <typename ContextT> class GenericCycle {
         Out << LS << Ctx.print(Entry);
     });
   }
-
-  Printable print(const ContextT &Ctx) const {
-    return Printable([this, &Ctx](raw_ostream &Out) {
-      Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
-
-      for (auto *Block : blocks()) {
-        if (isEntry(Block))
-          continue;
-
-        Out << ' ' << Ctx.print(Block);
-      }
-    });
-  }
 };
 
 /// \brief Cycle information for a function.
@@ -257,7 +206,6 @@ template <typename ContextT> class GenericCycleInfo {
   using BlockT = typename ContextT::BlockT;
   using CycleT = GenericCycle<ContextT>;
   using FunctionT = typename ContextT::FunctionT;
-  template <typename> friend class GenericCycle;
   template <typename> friend class GenericCycleInfoCompute;
 
 private:
@@ -283,7 +231,11 @@ template <typename ContextT> class GenericCycleInfo {
   /// the subtree.
   void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
 
-  void verifyBlockNumberEpoch(const FunctionT *Fn) const;
+  void verifyBlockNumberEpoch(const FunctionT *Fn) const {
+    assert(BlockNumberEpoch ==
+               GraphTraits<const FunctionT *>::getNumberEpoch(Fn) &&
+           "CycleInfo used with outdated block number epoch");
+  }
   void addToBlockMap(BlockT *Block, CycleT *Cycle);
 
   /// Build BlockLayout and every cycle's [IdxBegin, IdxEnd) slice
@@ -292,29 +244,8 @@ template <typename ContextT> class GenericCycleInfo {
 
 public:
   GenericCycleInfo() = default;
-  GenericCycleInfo(GenericCycleInfo &&Other) { *this = std::move(Other); }
-  GenericCycleInfo &operator=(GenericCycleInfo &&Other) {
-    if (this == &Other)
-      return *this;
-    Context = std::move(Other.Context);
-    BlockNumberEpoch = Other.BlockNumberEpoch;
-    BlockMap = std::move(Other.BlockMap);
-    BlockLayout = std::move(Other.BlockLayout);
-    TopLevelCycles = std::move(Other.TopLevelCycles);
-    // The moved cycles carry a back-reference to their owning info (used by
-    // GenericCycle::contains(BlockT*) and blocks()); re-point it at this
-    // object.
-    SmallVector<CycleT *, 8> Worklist;
-    for (auto &TLC : TopLevelCycles)
-      Worklist.push_back(TLC.get());
-    while (!Worklist.empty()) {
-      CycleT *C = Worklist.pop_back_val();
-      C->CI = this;
-      for (auto &Child : C->Children)
-        Worklist.push_back(Child.get());
-    }
-    return *this;
-  }
+  GenericCycleInfo(GenericCycleInfo &&) = default;
+  GenericCycleInfo &operator=(GenericCycleInfo &&) = default;
 
   void clear();
   void compute(FunctionT &F);
@@ -323,11 +254,68 @@ template <typename ContextT> class GenericCycleInfo {
   const FunctionT *getFunction() const { return Context.getFunction(); }
   const ContextT &getSSAContext() const { return Context; }
 
-  CycleT *getCycle(const BlockT *Block) const;
+  /// \brief Find the innermost cycle containing \p Block.
+  ///
+  /// \returns the innermost cycle containing \p Block or nullptr if
+  ///          it is not contained in any cycle.
+  CycleT *getCycle(const BlockT *Block) const {
+    verifyBlockNumberEpoch(Block->getParent());
+    unsigned Number = GraphTraits<const BlockT *>::getNumber(Block);
+    return Number < BlockMap.size() ? BlockMap[Number] : nullptr;
+  }
+
+  /// \brief Return whether \p Block is contained in \p C. O(1).
+  bool contains(const CycleT *C, const BlockT *Block) const {
+    return C && C->contains(getCycle(Block));
+  }
+
+  /// \brief Return the blocks of \p C, including th...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/209665


More information about the llvm-commits mailing list