diff options
author | Eli Friedman <efriedma@codeaurora.org> | 2018-01-31 20:42:25 +0000 |
---|---|---|
committer | Eli Friedman <efriedma@codeaurora.org> | 2018-01-31 20:42:25 +0000 |
commit | 79d297abe44aded6e829dedff8d7e3402cb971d4 (patch) | |
tree | 6972898ffb24f85588d8dbce612b7172ef17b29f /llvm/lib/Transforms/Utils/GlobalStatus.cpp | |
parent | d4bb329d0ea29bf6882b8f3bee9b944c161980a3 (diff) | |
download | bcm5719-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.cpp | 33 |
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); } |