[llvm] [CycleInfo] Store cycles in a flat preorder array. NFC (PR #209981)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 09:35:56 PDT 2026
================
@@ -301,73 +304,86 @@ void GenericCycleInfo<ContextT>::addBlockToCycle(BlockT *Block, CycleT *Cycle) {
BlockMap.resize(GraphTraits<FunctionT *>::getMaxNumber(Block->getParent()));
// Insert Block at the end of Cycle's slice and shift every later cycle's
- // range right. contain it below. The forest is an Euler tour, so a subtree
- // ending at or before Pos is entirely earlier and is skipped.
+ // range right. Ranges straddling Pos belong to Cycle's ancestors and are
+ // extended below.
unsigned Pos = Cycle->IdxEnd;
BlockLayout.insert(BlockLayout.begin() + Pos, Block);
- SmallVector<CycleT *, 8> Worklist(toplevel_cycles());
- while (!Worklist.empty()) {
- CycleT *C = Worklist.pop_back_val();
- if (C->IdxEnd <= Pos)
- continue;
- if (C->IdxBegin >= Pos) {
- ++C->IdxBegin;
- ++C->IdxEnd;
+ for (CycleT &C : cycles())
+ if (C.IdxBegin >= Pos) {
+ ++C.IdxBegin;
+ ++C.IdxEnd;
}
- for (auto &Child : C->Children)
- Worklist.push_back(Child.get());
- }
addToBlockMap(Block, Cycle);
// Cycle 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 (CycleT *C = Cycle; C; C = C->getParentCycle()) {
++C->IdxEnd;
if (!ExitBlocksCaches.empty())
- ExitBlocksCaches[C->ID].clear();
+ ExitBlocksCaches[getCycleIndex(*C)].clear();
}
}
+/// Move the discovered forest into Info's flat preorder array. Assigns preorder
+/// IDs, depths and descendant counts, remaps BlockMap from the temporary nodes,
+/// and lays out every cycle's blocks in BlockLayout.
template <typename ContextT>
-void GenericCycleInfo<ContextT>::layoutBlocks(ArrayRef<BlockT *> Order) {
- if (TopLevelCycles.empty())
+void GenericCycleInfoCompute<ContextT>::flatten(ArrayRef<BlockT *> Order) {
+ unsigned N = AllCycles.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.
struct Frame {
- CycleT *C;
- typename CycleT::const_child_iterator ChildCur, ChildEnd;
+ CycleT *Flat;
+ unsigned ChildCur, ChildEnd;
+ unsigned ID;
};
SmallVector<Frame, 8> Stack;
unsigned Cursor = 0;
- NumCycles = 0;
- auto enter = [&](CycleT *C) {
- C->ID = NumCycles++;
- Cursor += C->IdxEnd; // IdxEnd currently holds C's own-block count.
- C->IdxBegin = Cursor;
- Stack.push_back({C, C->child_begin(), C->child_end()});
+ unsigned NextID = 0;
+ auto enter = [&](CycleT *Temp, CycleT *Parent) {
+ unsigned ID = NextID++;
+ CycleT &Flat = Info.Cycles[ID];
+ Flat.ParentCycle = Parent;
+ 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;
};
- for (CycleT *TLC : toplevel_cycles()) {
- enter(TLC);
+ for (CycleT *TLC : TopLevelCycles) {
+ enter(TLC, nullptr);
while (!Stack.empty()) {
Frame &F = Stack.back();
if (F.ChildCur != F.ChildEnd) {
- enter(*F.ChildCur++);
+ enter(AttachedChildren[F.ChildCur++], F.Flat);
} else {
- F.C->IdxEnd = Cursor;
+ F.Flat->IdxEnd = Cursor;
+ F.Flat->NumDescendants = NextID - F.ID - 1;
Stack.pop_back();
}
}
}
- // Place every block into its innermost cycle's own region.
- BlockLayout.resize_for_overwrite(Cursor);
- for (BlockT *B : llvm::reverse(Order))
- if (CycleT *C = getCycle(B))
- BlockLayout[--C->IdxBegin] = B;
+ // Place every block into its innermost cycle's own region, remapping its
+ // BlockMap entry from the temporary node to the flat one.
+ Info.BlockLayout.resize_for_overwrite(Cursor);
+ for (BlockT *B : llvm::reverse(Order)) {
+ unsigned Number = GraphTraits<const BlockT *>::getNumber(B);
+ if (CycleT *Temp = Info.BlockMap[Number]) {
+ CycleT *Flat = &Info.Cycles[Temp->IdxBegin];
+ Info.BlockMap[Number] = Flat;
----------------
MaskRay wrote:
Yes, should be feasible during the process making `GenericCycle` an implementation detail!
https://github.com/llvm/llvm-project/pull/209981
More information about the llvm-commits
mailing list