[llvm] [MemorySSA] Make getPreviousDef iterative to avoid stack overflow (PR #205159)
Antonio Frighetto via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 24 02:19:18 PDT 2026
================
@@ -33,101 +33,222 @@ using namespace llvm;
// that there are two or more definitions needing to be merged.
// This still will leave non-minimal form in the case of irreducible control
// flow, where phi nodes may be in cycles with themselves, but unnecessary.
-MemoryAccess *MemorySSAUpdater::getPreviousDefRecursive(
+//
+// The predecessor walk is driven by an explicit worklist rather than native
+// recursion: it used to be mutually recursive with getPreviousDefFromEnd, and
+// the recursion depth scaled with the length of the walk, so deep CFGs (e.g.
+// long block chains in large generated kernels/shaders) could overflow the
+// native stack. Each StackFrame mirrors one activation of that walk; the Stage
+// records where to resume after a spawned child block has produced its result
+// (returned via Returned). All observable behaviour is preserved: cache
+// lookups/inserts, VisitedBlocks cycle detection (including the
+// single-predecessor insert-without-erase asymmetry), predecessor operand
+// order, and phi simplification/creation.
+MemoryAccess *MemorySSAUpdater::getPreviousDefIterative(
BasicBlock *BB,
DenseMap<BasicBlock *, TrackingVH<MemoryAccess>> &CachedPreviousDef) {
- // First, do a cache lookup. Without this cache, certain CFG structures
- // (like a series of if statements) take exponential time to visit.
- auto Cached = CachedPreviousDef.find(BB);
- if (Cached != CachedPreviousDef.end())
- return Cached->second;
-
- // If this method is called from an unreachable block, return LoE.
- if (!MSSA->DT->isReachableFromEntry(BB))
- return MSSA->getLiveOnEntryDef();
-
- if (BasicBlock *Pred = BB->getUniquePredecessor()) {
- VisitedBlocks.insert(BB);
- // Single predecessor case, just recurse, we can only have one definition.
- MemoryAccess *Result = getPreviousDefFromEnd(Pred, CachedPreviousDef);
- CachedPreviousDef.insert({BB, Result});
- return Result;
- }
-
- if (VisitedBlocks.count(BB)) {
- // We hit our node again, meaning we had a cycle, we must insert a phi
- // node to break it so we have an operand. The only case this will
- // insert useless phis is if we have irreducible control flow.
- MemoryAccess *Result = MSSA->createMemoryPhi(BB);
- CachedPreviousDef.insert({BB, Result});
- return Result;
- }
+ // Resume point for a frame after a child block's result becomes available.
+ enum class Stage {
+ EnterBlock, // first visit to the frame's block
+ ResumeSinglePred, // resuming after the unique predecessor is resolved
+ RunPredLoop, // running/resuming the multi-predecessor loop
----------------
antoniofrighetto wrote:
It would be nice to have a brief doc comment above `struct StackFrame`, documenting the state machine as well its phases (rather than having side comments here).
https://github.com/llvm/llvm-project/pull/205159
More information about the llvm-commits
mailing list