Skip to content

Commit

Permalink
[LCSSA] Cache the loop exit blocks across recursive analysis (NFC) (#…
Browse files Browse the repository at this point in the history
…101087)

The computation of loop exit blocks recently showed up as a huge compile
time cost for a large file. This computation was already being cached
during an invocation of formLCSSAForInstructions, but can also be cached
across callers formLCSSA and formLCSSARecursively (the latter was what
was being invoked in the examined case).

Since each of these functions has an external entry point invoked from
other passes, doing so required refactoring each into a worker mechanism
that takes a LoopExitBlocks map, and the externally callable version
that declares the map. That way we can pass it down from the outermost
formLCSSARecursively.

This reduced the time spent in the LCSSA pass from ~110s to ~1s.
  • Loading branch information
teresajohnson authored Jul 30, 2024
1 parent e59c832 commit 273e74b
Showing 1 changed file with 57 additions and 21 deletions.
78 changes: 57 additions & 21 deletions llvm/lib/Transforms/Utils/LCSSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,26 @@ static bool isExitBlock(BasicBlock *BB,
return is_contained(ExitBlocks, BB);
}

// Cache the Loop ExitBlocks computed during the analysis. We expect to get a
// lot of instructions within the same loops, computing the exit blocks is
// expensive, and we're not mutating the loop structure.
using LoopExitBlocksTy = SmallDenseMap<Loop *, SmallVector<BasicBlock *, 1>>;

/// For every instruction from the worklist, check to see if it has any uses
/// that are outside the current loop. If so, insert LCSSA PHI nodes and
/// rewrite the uses.
bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
const DominatorTree &DT, const LoopInfo &LI,
ScalarEvolution *SE,
SmallVectorImpl<PHINode *> *PHIsToRemove,
SmallVectorImpl<PHINode *> *InsertedPHIs) {
static bool
formLCSSAForInstructionsImpl(SmallVectorImpl<Instruction *> &Worklist,
const DominatorTree &DT, const LoopInfo &LI,
ScalarEvolution *SE,
SmallVectorImpl<PHINode *> *PHIsToRemove,
SmallVectorImpl<PHINode *> *InsertedPHIs,
LoopExitBlocksTy &LoopExitBlocks) {
SmallVector<Use *, 16> UsesToRewrite;
SmallSetVector<PHINode *, 16> LocalPHIsToRemove;
PredIteratorCache PredCache;
bool Changed = false;

// Cache the Loop ExitBlocks across this loop. We expect to get a lot of
// instructions within the same loops, computing the exit blocks is
// expensive, and we're not mutating the loop structure.
SmallDenseMap<Loop*, SmallVector<BasicBlock *,1>> LoopExitBlocks;

while (!Worklist.empty()) {
UsesToRewrite.clear();

Expand Down Expand Up @@ -317,13 +319,28 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
return Changed;
}

/// For every instruction from the worklist, check to see if it has any uses
/// that are outside the current loop. If so, insert LCSSA PHI nodes and
/// rewrite the uses.
bool llvm::formLCSSAForInstructions(SmallVectorImpl<Instruction *> &Worklist,
const DominatorTree &DT, const LoopInfo &LI,
ScalarEvolution *SE,
SmallVectorImpl<PHINode *> *PHIsToRemove,
SmallVectorImpl<PHINode *> *InsertedPHIs) {
LoopExitBlocksTy LoopExitBlocks;

return formLCSSAForInstructionsImpl(Worklist, DT, LI, SE, PHIsToRemove,
InsertedPHIs, LoopExitBlocks);
}

// Compute the set of BasicBlocks in the loop `L` dominating at least one exit.
static void computeBlocksDominatingExits(
Loop &L, const DominatorTree &DT, SmallVector<BasicBlock *, 8> &ExitBlocks,
Loop &L, const DominatorTree &DT,
const SmallVectorImpl<BasicBlock *> &ExitBlocks,
SmallSetVector<BasicBlock *, 8> &BlocksDominatingExits) {
// We start from the exit blocks, as every block trivially dominates itself
// (not strictly).
SmallVector<BasicBlock *, 8> BBWorklist(ExitBlocks);
SmallVector<BasicBlock *, 8> BBWorklist(ExitBlocks.begin(), ExitBlocks.end());

while (!BBWorklist.empty()) {
BasicBlock *BB = BBWorklist.pop_back_val();
Expand Down Expand Up @@ -360,8 +377,9 @@ static void computeBlocksDominatingExits(
}
}

bool llvm::formLCSSA(Loop &L, const DominatorTree &DT, const LoopInfo *LI,
ScalarEvolution *SE) {
static bool formLCSSAImpl(Loop &L, const DominatorTree &DT, const LoopInfo *LI,
ScalarEvolution *SE,
LoopExitBlocksTy &LoopExitBlocks) {
bool Changed = false;

#ifdef EXPENSIVE_CHECKS
Expand All @@ -372,8 +390,9 @@ bool llvm::formLCSSA(Loop &L, const DominatorTree &DT, const LoopInfo *LI,
}
#endif

SmallVector<BasicBlock *, 8> ExitBlocks;
L.getExitBlocks(ExitBlocks);
if (!LoopExitBlocks.count(&L))
L.getExitBlocks(LoopExitBlocks[&L]);
const SmallVectorImpl<BasicBlock *> &ExitBlocks = LoopExitBlocks[&L];
if (ExitBlocks.empty())
return false;

Expand Down Expand Up @@ -414,26 +433,43 @@ bool llvm::formLCSSA(Loop &L, const DominatorTree &DT, const LoopInfo *LI,
}
}

Changed = formLCSSAForInstructions(Worklist, DT, *LI, SE);
Changed = formLCSSAForInstructionsImpl(Worklist, DT, *LI, SE, nullptr,
nullptr, LoopExitBlocks);

assert(L.isLCSSAForm(DT));

return Changed;
}

bool llvm::formLCSSA(Loop &L, const DominatorTree &DT, const LoopInfo *LI,
ScalarEvolution *SE) {
LoopExitBlocksTy LoopExitBlocks;

return formLCSSAImpl(L, DT, LI, SE, LoopExitBlocks);
}

/// Process a loop nest depth first.
bool llvm::formLCSSARecursively(Loop &L, const DominatorTree &DT,
const LoopInfo *LI, ScalarEvolution *SE) {
static bool formLCSSARecursivelyImpl(Loop &L, const DominatorTree &DT,
const LoopInfo *LI, ScalarEvolution *SE,
LoopExitBlocksTy &LoopExitBlocks) {
bool Changed = false;

// Recurse depth-first through inner loops.
for (Loop *SubLoop : L.getSubLoops())
Changed |= formLCSSARecursively(*SubLoop, DT, LI, SE);
Changed |= formLCSSARecursivelyImpl(*SubLoop, DT, LI, SE, LoopExitBlocks);

Changed |= formLCSSA(L, DT, LI, SE);
Changed |= formLCSSAImpl(L, DT, LI, SE, LoopExitBlocks);
return Changed;
}

/// Process a loop nest depth first.
bool llvm::formLCSSARecursively(Loop &L, const DominatorTree &DT,
const LoopInfo *LI, ScalarEvolution *SE) {
LoopExitBlocksTy LoopExitBlocks;

return formLCSSARecursivelyImpl(L, DT, LI, SE, LoopExitBlocks);
}

/// Process all loops in the function, inner-most out.
static bool formLCSSAOnAllLoops(const LoopInfo *LI, const DominatorTree &DT,
ScalarEvolution *SE) {
Expand Down

0 comments on commit 273e74b

Please sign in to comment.