Index: include/llvm/IR/LegacyPassManagers.h =================================================================== --- include/llvm/IR/LegacyPassManagers.h +++ include/llvm/IR/LegacyPassManagers.h @@ -186,6 +186,12 @@ /// Set pass P as the last user of the given analysis passes. void setLastUser(ArrayRef AnalysisPasses, Pass *P); + /// Set pass P as locked for last use changes. + void setLockedLastUse(const Pass *P); + + /// Determine if the last use of pass P is unlocked. + bool isLastUseUnlocked(const Pass *P); + /// Collect passes whose last user is P void collectLastUses(SmallVectorImpl &LastUses, Pass *P); @@ -239,6 +245,10 @@ // LastUser->second is the last user of Lastuser->first. DenseMap LastUser; + // Map to keep track of locks on last use. A pass has its + // last use locked when the pass is no longer preserved. + SmallVector LockedLastUse; + // Map to keep track of passes that are last used by a pass. // This inverse map is initialized at PM->run() based on // LastUser map. @@ -420,6 +430,10 @@ bool isPassDebuggingExecutionsOrMore() const; private: + void removeNotPreservedAnalysis(Pass *P, + const AnalysisUsage::VectorType &PreservedSet, + DenseMap &AnalysisSet); + void dumpAnalysisUsage(StringRef Msg, const Pass *P, const AnalysisUsage::VectorType &Set) const; Index: lib/IR/LegacyPassManager.cpp =================================================================== --- lib/IR/LegacyPassManager.cpp +++ lib/IR/LegacyPassManager.cpp @@ -497,6 +497,18 @@ activeStack.push(PMDM); } +/// Set pass P as locked for last use changes. +void PMTopLevelManager::setLockedLastUse(const Pass *P) { + LockedLastUse.push_back(P); +} + +/// Determine if the last use of pass P is unlocked. +bool PMTopLevelManager::isLastUseUnlocked(const Pass *P) { + for (const Pass *Locked : LockedLastUse) + if (P == Locked) return false; + return true; +} + /// Set pass P as the last user of the given analysis passes. void PMTopLevelManager::setLastUser(ArrayRef AnalysisPasses, Pass *P) { @@ -505,7 +517,8 @@ PDepth = P->getResolver()->getPMDataManager().getDepth(); for (Pass *AP : AnalysisPasses) { - LastUser[AP] = P; + if (isLastUseUnlocked(AP)) + LastUser[AP] = P; if (P == AP) continue; @@ -543,7 +556,8 @@ if (LUI->second == AP) // DenseMap iterator is not invalidated here because // this is just updating existing entries. - LastUser[LUI->first] = P; + if (isLastUseUnlocked(LUI->first)) + LastUser[LUI->first] = P; } } } @@ -870,28 +884,35 @@ } } -/// Remove Analysis not preserved by Pass P -void PMDataManager::removeNotPreservedAnalysis(Pass *P) { - AnalysisUsage *AnUsage = TPM->findAnalysisUsage(P); - if (AnUsage->getPreservesAll()) - return; - - const AnalysisUsage::VectorType &PreservedSet = AnUsage->getPreservedSet(); - for (DenseMap::iterator I = AvailableAnalysis.begin(), - E = AvailableAnalysis.end(); I != E; ) { +void PMDataManager::removeNotPreservedAnalysis(Pass *P, + const AnalysisUsage::VectorType &PreservedSet, + DenseMap &AnalysisSet) { + for (DenseMap::iterator I = AnalysisSet.begin(), + E = AnalysisSet.end(); I != E; ) { DenseMap::iterator Info = I++; if (Info->second->getAsImmutablePass() == nullptr && std::find(PreservedSet.begin(), PreservedSet.end(), Info->first) == PreservedSet.end()) { // Remove this analysis + Pass *S = Info->second; if (PassDebugging >= Details) { - Pass *S = Info->second; dbgs() << " -- '" << P->getPassName() << "' is not preserving '"; dbgs() << S->getPassName() << "'\n"; } - AvailableAnalysis.erase(Info); + TPM->setLockedLastUse(S); + AnalysisSet.erase(Info); } } +} + +/// Remove Analysis not preserved by Pass P +void PMDataManager::removeNotPreservedAnalysis(Pass *P) { + AnalysisUsage *AnUsage = TPM->findAnalysisUsage(P); + if (AnUsage->getPreservesAll()) + return; + + const AnalysisUsage::VectorType &PreservedSet = AnUsage->getPreservedSet(); + removeNotPreservedAnalysis(P, PreservedSet, AvailableAnalysis); // Check inherited analysis also. If P is not preserving analysis // provided by parent manager then remove it here. @@ -900,22 +921,7 @@ if (!InheritedAnalysis[Index]) continue; - for (DenseMap::iterator - I = InheritedAnalysis[Index]->begin(), - E = InheritedAnalysis[Index]->end(); I != E; ) { - DenseMap::iterator Info = I++; - if (Info->second->getAsImmutablePass() == nullptr && - std::find(PreservedSet.begin(), PreservedSet.end(), Info->first) == - PreservedSet.end()) { - // Remove this analysis - if (PassDebugging >= Details) { - Pass *S = Info->second; - dbgs() << " -- '" << P->getPassName() << "' is not preserving '"; - dbgs() << S->getPassName() << "'\n"; - } - InheritedAnalysis[Index]->erase(Info); - } - } + removeNotPreservedAnalysis(P, PreservedSet, *InheritedAnalysis[Index]); } } Index: test/Feature/legacypassmanager.ll =================================================================== --- /dev/null +++ test/Feature/legacypassmanager.ll @@ -0,0 +1,19 @@ +; RUN: opt < %s -S -globals-aa -lcssa -argpromotion +; +; This is to verify a fix to bug 27050. The opt arguments expands to a series +; that involves -basiccg twice. Before the fix, both those CallGraphs were +; live at the same time during execution, which caused a value handle assert +; during argpromotion since only the latest CG's asserting value handles were +; removed when a function was deleted. + +%rec = type { i8 } + +define void @bar() { + call void @foo(%rec* undef) + ret void +} + +define internal void @foo(%rec* %par0) { + ret void +} +