[llvm] [CycleInfo] Identify cycles with a single-pass DFS algorithm (PR #210491)
Alexis Engelke via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 18 01:22:26 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]);
+ Cursor += OwnCount[C];
+ Flat.IdxBegin = Cursor;
+ Stack.push_back({ID, ChildHead[C]});
};
- for (CycleT *TLC : TopLevelCycles) {
- enter(TLC, nullptr);
+ for (auto TLC = TopHead; TLC != NoCycle; TLC = NextSibling[TLC]) {
+ enter(TLC, CycleRef());
while (!Stack.empty()) {
Frame &F = Stack.back();
- if (F.ChildCur != F.ChildEnd) {
- enter(AttachedChildren[F.ChildCur++], F.Flat);
+ if (F.Child != NoCycle) {
+ unsigned C = F.Child;
+ F.Child = NextSibling[C];
+ enter(C, CycleRef(F.Flat));
} else {
- F.Flat->IdxEnd = Cursor;
- F.Flat->NumDescendants = NextID - F.ID - 1;
+ CycleT &Flat = Info.Cycles[F.Flat];
+ Flat.IdxEnd = Cursor;
+ Flat.NumDescendants = NextID - F.Flat - 1;
Stack.pop_back();
}
}
}
- // Place every block into its innermost cycle's own region, remapping its
- // BlockMap entry from a creation-order index to the flat preorder index.
+ // Place every block into its innermost cycle's own region.
Info.BlockLayout.resize_for_overwrite(Cursor);
- for (BlockT *B : llvm::reverse(Order)) {
- unsigned Number = GraphTraits<const BlockT *>::getNumber(B);
- unsigned Created = Info.BlockMap[Number];
- if (Created != CycleInfoT::NoCycle) {
- // Created indexes AllCycles; enter() stashed the flat preorder index in
- // that temporary node's IdxBegin.
- unsigned Flat = AllCycles[Created].IdxBegin;
- Info.BlockMap[Number] = Flat;
- CycleT &FlatCycle = Info.Cycles[Flat];
- Info.BlockLayout[--FlatCycle.IdxBegin] = B;
- }
+ for (unsigned N : llvm::reverse(Preorder)) {
+ BlockInfo &BI = info(N);
+ if (BI.CycleIdx == NoCycle)
+ continue;
+ unsigned Flat = FlatIdx[BI.CycleIdx];
+ Info.BlockMap[N] = CycleRef(Flat);
+ Info.BlockLayout[--Info.Cycles[Flat].IdxBegin] = BI.Block;
}
}
/// \brief Main function of the cycle info computations.
template <typename ContextT>
void GenericCycleInfoCompute<ContextT>::run(FunctionT *F) {
BlockT *EntryBlock = GraphTraits<FunctionT *>::getEntryNode(F);
- LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
- << "\n");
- dfs(F, EntryBlock);
-
- SmallVector<BlockT *, 8> Worklist;
-
- for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
- const DFSInfo CandidateInfo = getDFSInfo(HeaderCandidate);
-
- for (BlockT *Pred : predecessors(HeaderCandidate)) {
- const DFSInfo PredDFSInfo = getDFSInfo(Pred);
- // This automatically ignores unreachable predecessors since they have
- // zeros in their DFSInfo.
- if (CandidateInfo.isAncestorOf(PredDFSInfo))
- Worklist.push_back(Pred);
- }
- if (Worklist.empty()) {
- continue;
+ BlockInfos.assign(GraphTraits<FunctionT *>::getMaxNumber(F), BlockInfo{});
+
+ dfs(EntryBlock);
----------------
aengelke wrote:
Early exit if num cycles is zero.
https://github.com/llvm/llvm-project/pull/210491
More information about the llvm-commits
mailing list