summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis/MemorySSAUpdater.cpp
diff options
context:
space:
mode:
authorEli Friedman <efriedma@codeaurora.org>2018-03-26 19:52:54 +0000
committerEli Friedman <efriedma@codeaurora.org>2018-03-26 19:52:54 +0000
commit88e2bac94d14b1e6d65aea3d3b3d48695ec0835d (patch)
tree18494c02be38ee1e426ce7b75679842031482faa /llvm/lib/Analysis/MemorySSAUpdater.cpp
parent93ce24838cd83c728d0cc852c4ae56700bac5b15 (diff)
downloadbcm5719-llvm-88e2bac94d14b1e6d65aea3d3b3d48695ec0835d.tar.gz
bcm5719-llvm-88e2bac94d14b1e6d65aea3d3b3d48695ec0835d.zip
[MemorySSA] Fix exponential compile-time updating MemorySSA.
MemorySSAUpdater::getPreviousDefRecursive is a recursive algorithm, for each block, it computes the previous definition for each predecessor, then takes those definitions and combines them. But currently it doesn't remember results which it already computed; this means it can visit the same block multiple times, which adds up to exponential time overall. To fix this, this patch adds a cache. If we computed the result for a block already, we don't need to visit it again because we'll come up with the same result. Well, unless we RAUW a MemoryPHI; in that case, the TrackingVH will be updated automatically. This matches the original source paper for this algorithm. The testcase isn't really a test for the bug, but it adds coverage for the case where tryRemoveTrivialPhi erases an existing PHI node. (It's hard to write a good regression test for a performance issue.) Differential Revision: https://reviews.llvm.org/D44715 llvm-svn: 328577
Diffstat (limited to 'llvm/lib/Analysis/MemorySSAUpdater.cpp')
-rw-r--r--llvm/lib/Analysis/MemorySSAUpdater.cpp43
1 files changed, 28 insertions, 15 deletions
diff --git a/llvm/lib/Analysis/MemorySSAUpdater.cpp b/llvm/lib/Analysis/MemorySSAUpdater.cpp
index f5d89f699a5..0d1e6471e98 100644
--- a/llvm/lib/Analysis/MemorySSAUpdater.cpp
+++ b/llvm/lib/Analysis/MemorySSAUpdater.cpp
@@ -37,15 +37,26 @@ 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(BasicBlock *BB) {
- // Single predecessor case, just recurse, we can only have one definition.
- if (BasicBlock *Pred = BB->getSinglePredecessor()) {
- return getPreviousDefFromEnd(Pred);
+MemoryAccess *MemorySSAUpdater::getPreviousDefRecursive(
+ 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;
+ } else if (BasicBlock *Pred = BB->getSinglePredecessor()) {
+ // Single predecessor case, just recurse, we can only have one definition.
+ MemoryAccess *Result = getPreviousDefFromEnd(Pred, CachedPreviousDef);
+ CachedPreviousDef.insert({BB, Result});
+ return Result;
} else 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.
- return MSSA->createMemoryPhi(BB);
+ MemoryAccess *Result = MSSA->createMemoryPhi(BB);
+ CachedPreviousDef.insert({BB, Result});
+ return Result;
} else if (VisitedBlocks.insert(BB).second) {
// Mark us visited so we can detect a cycle
SmallVector<MemoryAccess *, 8> PhiOps;
@@ -54,7 +65,7 @@ MemoryAccess *MemorySSAUpdater::getPreviousDefRecursive(BasicBlock *BB) {
// potential phi node. This will insert phi nodes if we cycle in order to
// break the cycle and have an operand.
for (auto *Pred : predecessors(BB))
- PhiOps.push_back(getPreviousDefFromEnd(Pred));
+ PhiOps.push_back(getPreviousDefFromEnd(Pred, CachedPreviousDef));
// Now try to simplify the ops to avoid placing a phi.
// This may return null if we never created a phi yet, that's okay
@@ -90,6 +101,7 @@ MemoryAccess *MemorySSAUpdater::getPreviousDefRecursive(BasicBlock *BB) {
// Set ourselves up for the next variable by resetting visited state.
VisitedBlocks.erase(BB);
+ CachedPreviousDef.insert({BB, Result});
return Result;
}
llvm_unreachable("Should have hit one of the three cases above");
@@ -100,9 +112,10 @@ MemoryAccess *MemorySSAUpdater::getPreviousDefRecursive(BasicBlock *BB) {
// it continues globally, creating phi nodes to ensure we have a single
// definition.
MemoryAccess *MemorySSAUpdater::getPreviousDef(MemoryAccess *MA) {
- auto *LocalResult = getPreviousDefInBlock(MA);
-
- return LocalResult ? LocalResult : getPreviousDefRecursive(MA->getBlock());
+ if (auto *LocalResult = getPreviousDefInBlock(MA))
+ return LocalResult;
+ DenseMap<BasicBlock *, TrackingVH<MemoryAccess>> CachedPreviousDef;
+ return getPreviousDefRecursive(MA->getBlock(), CachedPreviousDef);
}
// This starts at the memory access, and goes backwards in the block to the find
@@ -133,13 +146,15 @@ MemoryAccess *MemorySSAUpdater::getPreviousDefInBlock(MemoryAccess *MA) {
}
// This starts at the end of block
-MemoryAccess *MemorySSAUpdater::getPreviousDefFromEnd(BasicBlock *BB) {
+MemoryAccess *MemorySSAUpdater::getPreviousDefFromEnd(
+ BasicBlock *BB,
+ DenseMap<BasicBlock *, TrackingVH<MemoryAccess>> &CachedPreviousDef) {
auto *Defs = MSSA->getWritableBlockDefs(BB);
if (Defs)
return &*Defs->rbegin();
- return getPreviousDefRecursive(BB);
+ return getPreviousDefRecursive(BB, CachedPreviousDef);
}
// Recurse over a set of phi uses to eliminate the trivial ones
MemoryAccess *MemorySSAUpdater::recursePhi(MemoryAccess *Phi) {
@@ -230,10 +245,8 @@ void MemorySSAUpdater::insertDef(MemoryDef *MD, bool RenameUses) {
InsertedPHIs.clear();
// See if we had a local def, and if not, go hunting.
- MemoryAccess *DefBefore = getPreviousDefInBlock(MD);
- bool DefBeforeSameBlock = DefBefore != nullptr;
- if (!DefBefore)
- DefBefore = getPreviousDefRecursive(MD->getBlock());
+ MemoryAccess *DefBefore = getPreviousDef(MD);
+ bool DefBeforeSameBlock = DefBefore->getBlock() == MD->getBlock();
// There is a def before us, which means we can replace any store/phi uses
// of that thing with us, since we are in the way of whatever was there
OpenPOWER on IntegriCloud