[llvm] [CycleInfo] Remove GenericCycle::TopLevelCycle. NFC (PR #209677)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 21:04:33 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-adt

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

moveTopLevelCycleToNewParent maintains TopLevelCycle eagerly, rewriting the
whole re-parented subtree with depth_first. When discovery nests k cycles
one by one this is quadratic, and the df_iterator walk plus its visited set
dominate construction on deep nests (~78% of time on a 1500-deep nest).

Walk ParentCycle links in getTopLevelParentCycle instead and delete the
member. The walk is valid during construction too: parent links are
always current, and discovery queries blocks whose innermost cycle sits
at the top of the forest being merged, so the walk is short.

Aided by Claude Fable 5


---
Full diff: https://github.com/llvm/llvm-project/pull/209677.diff


2 Files Affected:

- (modified) llvm/include/llvm/ADT/GenericCycleImpl.h (+3-9) 
- (modified) llvm/include/llvm/ADT/GenericCycleInfo.h (+1-5) 


``````````diff
diff --git a/llvm/include/llvm/ADT/GenericCycleImpl.h b/llvm/include/llvm/ADT/GenericCycleImpl.h
index dfeb479d764e5..1710141d39cad 100644
--- a/llvm/include/llvm/ADT/GenericCycleImpl.h
+++ b/llvm/include/llvm/ADT/GenericCycleImpl.h
@@ -227,11 +227,6 @@ void GenericCycle<ContextT>::verifyCycleNest() const {
   if (ParentCycle) {
     assert(is_contained(ParentCycle->children(), this) &&
            "Cycle is not a subcycle of its parent!");
-    assert(ParentCycle->TopLevelCycle == TopLevelCycle &&
-           "Top level cycle of parent cycle must be the same");
-  } else {
-    assert(TopLevelCycle == this &&
-           "Cycle without parent must be top-level cycle");
   }
 #endif
 }
@@ -293,7 +288,9 @@ template <typename ContextT>
 auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(
     const BlockT *Block) const -> CycleT * {
   CycleT *Cycle = getCycle(Block);
-  return Cycle ? Cycle->TopLevelCycle : nullptr;
+  while (Cycle && Cycle->ParentCycle)
+    Cycle = Cycle->ParentCycle;
+  return Cycle;
 }
 
 template <typename ContextT>
@@ -311,9 +308,6 @@ void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
   *Pos = std::move(CurrentContainer.back());
   CurrentContainer.pop_back();
   Child->ParentCycle = NewParent;
-  Child->TopLevelCycle = NewParent;
-  for (CycleT *Cycle : depth_first(Child))
-    Cycle->TopLevelCycle = NewParent;
   // This only relinks the cycle tree and does NOT touch BlockLayout, so it
   // leaves every cycle's [IdxBegin, IdxEnd) range stale, i.e. BlockLayout is
   // left invalid. The caller must call layoutBlocks() before any
diff --git a/llvm/include/llvm/ADT/GenericCycleInfo.h b/llvm/include/llvm/ADT/GenericCycleInfo.h
index c3093d4cf83e5..5a414d502225c 100644
--- a/llvm/include/llvm/ADT/GenericCycleInfo.h
+++ b/llvm/include/llvm/ADT/GenericCycleInfo.h
@@ -54,10 +54,6 @@ template <typename ContextT> class GenericCycle {
   /// at the root.
   GenericCycle *ParentCycle = nullptr;
 
-  /// The top-level cycle this cycle is part of. Points to itself if this is
-  /// a top-level cycle.
-  GenericCycle *TopLevelCycle;
-
   /// The entry block(s) of the cycle. The header is the only entry if
   /// this is a loop. Is empty for the root "cycle", to avoid
   /// unnecessary memory use.
@@ -108,7 +104,7 @@ template <typename ContextT> class GenericCycle {
   GenericCycle &operator=(GenericCycle &&Rhs) = delete;
 
 public:
-  GenericCycle() : TopLevelCycle(this) {}
+  GenericCycle() = default;
 
   /// \brief Whether the cycle is a natural loop.
   bool isReducible() const { return Entries.size() == 1; }

``````````

</details>


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


More information about the llvm-commits mailing list