diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index e9c8ca3072c..105da67cbb3 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -29,6 +29,7 @@ #ifndef LLVM_PASS_H #define LLVM_PASS_H +#include #include namespace llvm { @@ -82,17 +83,40 @@ class Pass { AnalysisResolver *Resolver; // Used to resolve analysis const void *PassID; PassKind Kind; + bool Executed; + void operator=(const Pass&) = delete; Pass(const Pass &) = delete; public: explicit Pass(PassKind K, char &pid) - : Resolver(nullptr), PassID(&pid), Kind(K) { } + : Resolver(nullptr), PassID(&pid), Kind(K), Executed(false) { } virtual ~Pass(); - PassKind getPassKind() const { return Kind; } + /// Returns true if the pass has already executed. + /// + /// For an analysis pass it means the result is available. If the function + /// returns false, the pass was not run, was skipped or freed. + /// + bool isExecuted() const { return Executed; } + + /// Marks the pass as executed or not. + /// + /// A pass should be marked as executed, if its 'runOn*' method successfully + /// finished. When the pass is not needed anymore, it is marked as + /// 'non-executed', it takes place in \c freePass. It also occurs when the + /// pass is skipped for some reason. + /// + /// The flag should be set prior to call to 'runOn*' method. If it decides + /// that the pass should be skipped, it will reset the flag. + /// + void setExecuted(bool x) { + assert(x || !getAsImmutablePass()); // Immutable pass cannot be invalidated. + Executed = x; + } + /// getPassName - Return a nice clean name for a pass. This usually /// implemented in terms of the name that is registered by one of the /// Registration templates, but can be overloaded directly. @@ -279,8 +303,7 @@ public: /// bool runOnModule(Module &) override { return false; } - explicit ImmutablePass(char &pid) - : ModulePass(pid) {} + explicit ImmutablePass(char &pid) : ModulePass(pid) { setExecuted(true); } // Force out-of-line virtual method. ~ImmutablePass() override; @@ -316,8 +339,9 @@ public: protected: /// Optional passes call this function to check whether the pass should be /// skipped. This is the case when Attribute::OptimizeNone is set or when - /// optimization bisect is over the limit. - bool skipFunction(const Function &F) const; + /// optimization bisect is over the limit. It also resets flag Executed on + /// the pass. + bool skipFunction(const Function &F); }; diff --git a/include/llvm/PassAnalysisSupport.h b/include/llvm/PassAnalysisSupport.h index abd99293805..d7091fc4fe4 100644 --- a/include/llvm/PassAnalysisSupport.h +++ b/include/llvm/PassAnalysisSupport.h @@ -206,6 +206,9 @@ AnalysisType *Pass::getAnalysisIfAvailable() const { Pass *ResultPass = Resolver->getAnalysisIfAvailable(PI, true); if (!ResultPass) return nullptr; + if (!ResultPass->isExecuted()) + return nullptr; + // Because the AnalysisType may not be a subclass of pass (for // AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially // adjust the return pointer (because the class may multiply inherit, once @@ -234,6 +237,8 @@ AnalysisType &Pass::getAnalysisID(AnalysisID PI) const { assert (ResultPass && "getAnalysis*() called on an analysis that was not " "'required' by pass!"); + assert(ResultPass->isExecuted() && + "getAnalysis*() called on an analysis that was freed"); // Because the AnalysisType may not be a subclass of pass (for // AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially diff --git a/lib/Analysis/CallGraphSCCPass.cpp b/lib/Analysis/CallGraphSCCPass.cpp index 9cef7814415..290fd34cff5 100644 --- a/lib/Analysis/CallGraphSCCPass.cpp +++ b/lib/Analysis/CallGraphSCCPass.cpp @@ -414,6 +414,7 @@ bool CGPassManager::RunAllPassesOnSCC(CallGraphSCC &CurSCC, CallGraph &CG, initializeAnalysisImpl(P); // Actually run this pass on the current SCC. + P->setExecuted(true); Changed |= RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate, DevirtualizedCall); diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index f449ce94d57..1b5d6e5d1b7 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -722,8 +722,10 @@ void LoopInfoWrapperPass::verifyAnalysis() const { // checking by default, LoopPass has been taught to call verifyLoop manually // during loop pass sequences. if (VerifyLoopInfo) { - auto &DT = getAnalysis().getDomTree(); - LI.verify(DT); + if (auto *Analysis = getAnalysisIfAvailable()) { + auto &DT = Analysis->getDomTree(); + LI.verify(DT); + } } } diff --git a/lib/Analysis/LoopPass.cpp b/lib/Analysis/LoopPass.cpp index 3f4a0794215..d3e697e5c61 100644 --- a/lib/Analysis/LoopPass.cpp +++ b/lib/Analysis/LoopPass.cpp @@ -198,6 +198,7 @@ bool LPPassManager::runOnFunction(Function &F) { PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader()); TimeRegion PassTimer(getPassTimer(P)); + P->setExecuted(true); Changed |= P->runOnLoop(CurrentLoop, *this); } LoopWasDeleted = CurrentLoop->isInvalid(); diff --git a/lib/CodeGen/MachineDominators.cpp b/lib/CodeGen/MachineDominators.cpp index 303a6a9263b..a548480044e 100644 --- a/lib/CodeGen/MachineDominators.cpp +++ b/lib/CodeGen/MachineDominators.cpp @@ -69,7 +69,7 @@ void MachineDominatorTree::releaseMemory() { } void MachineDominatorTree::verifyAnalysis() const { - if (VerifyMachineDomInfo) + if (VerifyMachineDomInfo && isExecuted()) verifyDomTree(); } diff --git a/lib/CodeGen/MachineFunctionPass.cpp b/lib/CodeGen/MachineFunctionPass.cpp index 2265676ff8b..a7ece36a1e5 100644 --- a/lib/CodeGen/MachineFunctionPass.cpp +++ b/lib/CodeGen/MachineFunctionPass.cpp @@ -38,8 +38,10 @@ Pass *MachineFunctionPass::createPrinterPass(raw_ostream &O, bool MachineFunctionPass::runOnFunction(Function &F) { // Do not codegen any 'available_externally' functions at all, they have // definitions outside the translation unit. - if (F.hasAvailableExternallyLinkage()) + if (F.hasAvailableExternallyLinkage()) { + setExecuted(false); return false; + } MachineModuleInfo &MMI = getAnalysis(); MachineFunction &MF = MMI.getMachineFunction(F); diff --git a/lib/IR/LegacyPassManager.cpp b/lib/IR/LegacyPassManager.cpp index 628a67bd639..0b2c40b742a 100644 --- a/lib/IR/LegacyPassManager.cpp +++ b/lib/IR/LegacyPassManager.cpp @@ -955,6 +955,9 @@ void PMDataManager::freePass(Pass *P, StringRef Msg, AvailableAnalysis.erase(Pos); } } + + if (!P->getAsImmutablePass()) + P->setExecuted(false); } /// Add pass P into the PassVector. Update @@ -1293,6 +1296,7 @@ bool BBPassManager::runOnFunction(Function &F) { PassManagerPrettyStackEntry X(BP, *I); TimeRegion PassTimer(getPassTimer(BP)); + BP->setExecuted(true); LocalChanged |= BP->runOnBasicBlock(*I); } @@ -1459,7 +1463,9 @@ bool FunctionPassManagerImpl::run(Function &F) { initializeAllAnalysisInfo(); for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) { - Changed |= getContainedManager(Index)->runOnFunction(F); + FPPassManager *P = getContainedManager(Index); + P->setExecuted(true); + Changed |= P->runOnFunction(F); F.getContext().yield(); } @@ -1510,6 +1516,7 @@ bool FPPassManager::runOnFunction(Function &F) { PassManagerPrettyStackEntry X(FP, F); TimeRegion PassTimer(getPassTimer(FP)); + FP->setExecuted(true); LocalChanged |= FP->runOnFunction(F); } @@ -1530,8 +1537,10 @@ bool FPPassManager::runOnFunction(Function &F) { bool FPPassManager::runOnModule(Module &M) { bool Changed = false; - for (Function &F : M) + for (Function &F : M) { + setExecuted(true); Changed |= runOnFunction(F); + } return Changed; } @@ -1587,6 +1596,7 @@ MPPassManager::runOnModule(Module &M) { PassManagerPrettyStackEntry X(MP, M); TimeRegion PassTimer(getPassTimer(MP)); + MP->setExecuted(true); LocalChanged |= MP->runOnModule(M); } @@ -1690,7 +1700,9 @@ bool PassManagerImpl::run(Module &M) { initializeAllAnalysisInfo(); for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) { - Changed |= getContainedManager(Index)->runOnModule(M); + MPPassManager *P = getContainedManager(Index); + P->setExecuted(true); + Changed |= P->runOnModule(M); M.getContext().yield(); } diff --git a/lib/IR/Pass.cpp b/lib/IR/Pass.cpp index a42945ef3ff..6e22c1d4641 100644 --- a/lib/IR/Pass.cpp +++ b/lib/IR/Pass.cpp @@ -146,13 +146,16 @@ PassManagerType FunctionPass::getPotentialPassManagerType() const { return PMT_FunctionPassManager; } -bool FunctionPass::skipFunction(const Function &F) const { - if (!F.getContext().getOptBisect().shouldRunPass(this, F)) +bool FunctionPass::skipFunction(const Function &F) { + if (!F.getContext().getOptBisect().shouldRunPass(this, F)) { + setExecuted(false); return true; + } if (F.hasFnAttribute(Attribute::OptimizeNone)) { DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function " << F.getName() << "\n"); + setExecuted(false); return true; } return false; diff --git a/test/CodeGen/Generic/externally_available.ll b/test/CodeGen/Generic/externally_available.ll index 7976cc97188..2376bc73992 100644 --- a/test/CodeGen/Generic/externally_available.ll +++ b/test/CodeGen/Generic/externally_available.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s | not grep test_ +; RUN: llc -verify-machine-dom-info < %s | not grep test_ ; test_function should not be emitted to the .s file. define available_externally i32 @test_function() { diff --git a/test/CodeGen/Mips/mul.ll b/test/CodeGen/Mips/mul.ll index 9e053fc2e7d..fa147b08ff2 100644 --- a/test/CodeGen/Mips/mul.ll +++ b/test/CodeGen/Mips/mul.ll @@ -1,4 +1,4 @@ -; RUN: llc -march=mipsel -mattr=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=16 +; RUN: llc -march=mipsel -mattr=mips16 -relocation-model=pic -O3 -verify-loop-info < %s | FileCheck %s -check-prefix=16 @iiii = global i32 5, align 4 @jjjj = global i32 -6, align 4