mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-13 22:58:50 +00:00
[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
This commit is contained in:
parent
09e2179bbf
commit
75b50e6d60
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user