summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/Utils/GlobalStatus.cpp
diff options
context:
space:
mode:
authorEli Friedman <efriedma@codeaurora.org>2018-01-31 20:42:25 +0000
committerEli Friedman <efriedma@codeaurora.org>2018-01-31 20:42:25 +0000
commit79d297abe44aded6e829dedff8d7e3402cb971d4 (patch)
tree6972898ffb24f85588d8dbce612b7172ef17b29f /llvm/lib/Transforms/Utils/GlobalStatus.cpp
parentd4bb329d0ea29bf6882b8f3bee9b944c161980a3 (diff)
downloadbcm5719-llvm-79d297abe44aded6e829dedff8d7e3402cb971d4.tar.gz
bcm5719-llvm-79d297abe44aded6e829dedff8d7e3402cb971d4.zip
[GlobalOpt] Fix exponential compile-time with selects.
If you have a long chain of select instructions created from something like `int* p = &g; if (foo()) p += 4; if (foo2()) p += 4;` etc., a naive recursive visitor will recursively visit each select twice, which is O(2^N) in the number of select instructions. Use the visited set to cut off recursion in this case. (No testcase because this doesn't actually change the behavior, just the time.) Differential Revision: https://reviews.llvm.org/D42451 llvm-svn: 323910
Diffstat (limited to 'llvm/lib/Transforms/Utils/GlobalStatus.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/GlobalStatus.cpp33
1 files changed, 16 insertions, 17 deletions
diff --git a/llvm/lib/Transforms/Utils/GlobalStatus.cpp b/llvm/lib/Transforms/Utils/GlobalStatus.cpp
index 245fefb38ee..ff6970db47d 100644
--- a/llvm/lib/Transforms/Utils/GlobalStatus.cpp
+++ b/llvm/lib/Transforms/Utils/GlobalStatus.cpp
@@ -60,7 +60,7 @@ bool llvm::isSafeToDestroyConstant(const Constant *C) {
}
static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
- SmallPtrSetImpl<const PHINode *> &PhiUsers) {
+ SmallPtrSetImpl<const Value *> &VisitedUsers) {
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
if (GV->isExternallyInitialized())
GS.StoredType = GlobalStatus::StoredOnce;
@@ -75,7 +75,8 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
if (!isa<PointerType>(CE->getType()))
return true;
- if (analyzeGlobalAux(CE, GS, PhiUsers))
+ // FIXME: Do we need to add constexpr selects to VisitedUsers?
+ if (analyzeGlobalAux(CE, GS, VisitedUsers))
return true;
} else if (const Instruction *I = dyn_cast<Instruction>(UR)) {
if (!GS.HasMultipleAccessingFunctions) {
@@ -137,20 +138,18 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
GS.StoredType = GlobalStatus::Stored;
}
}
- } else if (isa<BitCastInst>(I)) {
- if (analyzeGlobalAux(I, GS, PhiUsers))
+ } else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I)) {
+ // Skip over bitcasts and GEPs; we don't care about the type or offset
+ // of the pointer.
+ if (analyzeGlobalAux(I, GS, VisitedUsers))
return true;
- } else if (isa<GetElementPtrInst>(I)) {
- if (analyzeGlobalAux(I, GS, PhiUsers))
- return true;
- } else if (isa<SelectInst>(I)) {
- if (analyzeGlobalAux(I, GS, PhiUsers))
- return true;
- } else if (const PHINode *PN = dyn_cast<PHINode>(I)) {
- // PHI nodes we can check just like select or GEP instructions, but we
- // have to be careful about infinite recursion.
- if (PhiUsers.insert(PN).second) // Not already visited.
- if (analyzeGlobalAux(I, GS, PhiUsers))
+ } else if (isa<SelectInst>(I) || isa<PHINode>(I)) {
+ // Look through selects and PHIs to find if the pointer is
+ // conditionally accessed. Make sure we only visit an instruction
+ // once; otherwise, we can get infinite recursion or exponential
+ // compile time.
+ if (VisitedUsers.insert(I).second)
+ if (analyzeGlobalAux(I, GS, VisitedUsers))
return true;
} else if (isa<CmpInst>(I)) {
GS.IsCompared = true;
@@ -191,6 +190,6 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
GlobalStatus::GlobalStatus() = default;
bool GlobalStatus::analyzeGlobal(const Value *V, GlobalStatus &GS) {
- SmallPtrSet<const PHINode *, 16> PhiUsers;
- return analyzeGlobalAux(V, GS, PhiUsers);
+ SmallPtrSet<const Value *, 16> VisitedUsers;
+ return analyzeGlobalAux(V, GS, VisitedUsers);
}
OpenPOWER on IntegriCloud