Index: include/llvm/Pass.h =================================================================== --- include/llvm/Pass.h +++ include/llvm/Pass.h @@ -29,6 +29,7 @@ #ifndef LLVM_PASS_H #define LLVM_PASS_H +#include #include namespace llvm { @@ -82,17 +83,40 @@ 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 @@ /// 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 @@ 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); }; Index: include/llvm/PassAnalysisSupport.h =================================================================== --- include/llvm/PassAnalysisSupport.h +++ include/llvm/PassAnalysisSupport.h @@ -206,6 +206,9 @@ 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 @@ 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 Index: lib/Analysis/CallGraphSCCPass.cpp =================================================================== --- lib/Analysis/CallGraphSCCPass.cpp +++ lib/Analysis/CallGraphSCCPass.cpp @@ -414,6 +414,7 @@ initializeAnalysisImpl(P); // Actually run this pass on the current SCC. + P->setExecuted(true); Changed |= RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate, DevirtualizedCall); Index: lib/Analysis/LoopInfo.cpp =================================================================== --- lib/Analysis/LoopInfo.cpp +++ lib/Analysis/LoopInfo.cpp @@ -727,8 +727,10 @@ // 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); + } } } Index: lib/Analysis/LoopPass.cpp =================================================================== --- lib/Analysis/LoopPass.cpp +++ lib/Analysis/LoopPass.cpp @@ -198,6 +198,7 @@ PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader()); TimeRegion PassTimer(getPassTimer(P)); + P->setExecuted(true); Changed |= P->runOnLoop(CurrentLoop, *this); } LoopWasDeleted = CurrentLoop->isInvalid(); Index: lib/CodeGen/MachineDominators.cpp =================================================================== --- lib/CodeGen/MachineDominators.cpp +++ lib/CodeGen/MachineDominators.cpp @@ -69,7 +69,7 @@ } void MachineDominatorTree::verifyAnalysis() const { - if (VerifyMachineDomInfo) + if (VerifyMachineDomInfo && isExecuted()) verifyDomTree(); } Index: lib/CodeGen/MachineFunctionPass.cpp =================================================================== --- lib/CodeGen/MachineFunctionPass.cpp +++ lib/CodeGen/MachineFunctionPass.cpp @@ -38,8 +38,10 @@ 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); Index: lib/IR/LegacyPassManager.cpp =================================================================== --- lib/IR/LegacyPassManager.cpp +++ lib/IR/LegacyPassManager.cpp @@ -955,6 +955,9 @@ AvailableAnalysis.erase(Pos); } } + + if (!P->getAsImmutablePass()) + P->setExecuted(false); } /// Add pass P into the PassVector. Update @@ -1293,6 +1296,7 @@ PassManagerPrettyStackEntry X(BP, *I); TimeRegion PassTimer(getPassTimer(BP)); + BP->setExecuted(true); LocalChanged |= BP->runOnBasicBlock(*I); } @@ -1459,7 +1463,9 @@ 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 @@ PassManagerPrettyStackEntry X(FP, F); TimeRegion PassTimer(getPassTimer(FP)); + FP->setExecuted(true); LocalChanged |= FP->runOnFunction(F); } @@ -1530,8 +1537,10 @@ 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 @@ PassManagerPrettyStackEntry X(MP, M); TimeRegion PassTimer(getPassTimer(MP)); + MP->setExecuted(true); LocalChanged |= MP->runOnModule(M); } @@ -1690,7 +1700,9 @@ 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(); } Index: lib/IR/Pass.cpp =================================================================== --- lib/IR/Pass.cpp +++ lib/IR/Pass.cpp @@ -146,13 +146,16 @@ 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; Index: test/CodeGen/Generic/externally_available.ll =================================================================== --- test/CodeGen/Generic/externally_available.ll +++ 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() { Index: test/CodeGen/Mips/mul.ll =================================================================== --- test/CodeGen/Mips/mul.ll +++ 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