[llvm] [CycleInfo] Identify cycles with a single-pass DFS algorithm (PR #210491)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 18 12:42:20 PDT 2026
================
@@ -329,257 +323,204 @@ void GenericCycleInfo<ContextT>::addBlockToCycle(BlockT *Block, CycleRef C) {
++X.IdxEnd;
}
}
- addToBlockMap(Block, &Cyc);
+ addToBlockMap(Block, C);
// Cyc and its ancestors gain the new block: extend each one's slice and
// invalidate its exit-block cache in a single walk up the tree.
- for (unsigned I = getCycleIndex(Cyc); I != NoCycle;
- I = Cycles[I].ParentIndex) {
- ++Cycles[I].IdxEnd;
+ for (CycleRef I = C; I; I = deref(I).Parent) {
+ ++deref(I).IdxEnd;
if (!ExitBlocksCaches.empty())
- ExitBlocksCaches[I].clear();
+ ExitBlocksCaches[I.Index].clear();
}
}
-/// Move the discovered forest into Info's flat preorder array. Assigns preorder
-/// IDs, depths and descendant counts, remaps BlockMap from creation-order to
-/// preorder indices, and lays out every cycle's blocks in BlockLayout.
+/// Lay the discovered cycle forest out into Info's flat preorder array: number
+/// the cycles in Euler-tour order, set each one's parent, depth and descendant
+/// count, place every block into its innermost cycle's region of BlockLayout,
+/// and fill BlockMap. Arrays are keyed by header-preorder rank.
template <typename ContextT>
-void GenericCycleInfoCompute<ContextT>::flatten(ArrayRef<BlockT *> Order) {
- unsigned N = AllCycles.size();
+void GenericCycleInfoCompute<ContextT>::flatten(ArrayRef<BlockT *> Headers,
+ ArrayRef<unsigned> ChildHead,
+ ArrayRef<unsigned> NextSibling,
+ ArrayRef<unsigned> OwnCount,
+ unsigned TopHead) {
+ unsigned N = Headers.size();
Info.NumCycles = N;
if (!N)
return;
Info.Cycles = std::make_unique<CycleT[]>(N);
- // Walk the cycle forest as an Euler tour. On entry, a cycle's IdxEnd still
- // holds its own-block count (accumulated during run()); reserve that many
- // slots for its own region [Cursor, Cursor + count). Its children take the
- // following slots, so on leaving, Cursor is the cycle's real range end, which
- // overwrites the now-consumed count in IdxEnd.
+ // Walk the cycle forest as an Euler tour. On entry a cycle reserves [Cursor,
+ // Cursor + OwnCount) for its own blocks (IdxBegin temporarily holds that
+ // region's end; the fill loop below walks it back down); its descendants take
+ // the following slots, so on exit Cursor is its IdxEnd.
+ SmallVector<unsigned, 8> FlatIdx(N);
struct Frame {
- CycleT *Flat;
- unsigned ChildCur, ChildEnd;
- unsigned ID;
+ unsigned Flat;
+ unsigned Child; // Next child to enter, NoCycle once exhausted.
};
SmallVector<Frame, 8> Stack;
- unsigned Cursor = 0;
- unsigned NextID = 0;
- auto enter = [&](CycleT *Temp, CycleT *Parent) {
+ unsigned Cursor = 0, NextID = 0;
+ auto enter = [&](unsigned C, CycleRef Parent) {
unsigned ID = NextID++;
+ FlatIdx[C] = ID;
CycleT &Flat = Info.Cycles[ID];
- Flat.ParentIndex =
- Parent ? Info.getCycleIndex(*Parent) : CycleInfoT::NoCycle;
- Flat.Depth = Parent ? Parent->Depth + 1 : 1;
- Flat.Entries = std::move(Temp->Entries);
- Cursor += Temp->IdxEnd; // IdxEnd currently holds Temp's own-block count.
- Flat.IdxBegin = Cursor; // Real begin restored by the fill loop below.
- Stack.push_back({&Flat, Temp->IdxBegin, Temp->Depth, ID});
- // Temp's IdxBegin now holds the flat index, for the BlockMap remap below.
- Temp->IdxBegin = ID;
+ Flat.Parent = Parent;
+ Flat.Depth = Parent ? Info.deref(Parent).Depth + 1 : 1;
+ Flat.appendEntry(Headers[C]);
----------------
MaskRay wrote:
Nod. `GenericCycleInfo::getEntries` is called by FixIrreducible.cpp/MachineCycleAnalysis.cpp. The refactoring can be separate so that this change is almost NFC (modulo the block print order).
https://github.com/llvm/llvm-project/pull/210491
More information about the llvm-commits
mailing list