Index: include/llvm/Analysis/CGSCCPassManager.h =================================================================== --- include/llvm/Analysis/CGSCCPassManager.h +++ include/llvm/Analysis/CGSCCPassManager.h @@ -364,6 +364,10 @@ InvalidSCCSet, nullptr, nullptr, InlinedInternalEdges}; + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult(M); + PreservedAnalyses PA = PreservedAnalyses::all(); CG.buildRefSCCs(); for (auto RCI = CG.postorder_ref_scc_begin(), @@ -428,8 +432,17 @@ UR.UpdatedRC = nullptr; UR.UpdatedC = nullptr; + + // Check the PassInstrumentation's BeforePass callbacks before + // running the pass, skip its execution completely if asked to + // (callback returns false). + if (!PI.runBeforePass(Pass, *C)) + continue; + PreservedAnalyses PassPA = Pass.run(*C, CGAM, CG, UR); + PI.runAfterPass(Pass, *C); + // Update the SCC and RefSCC if necessary. C = UR.UpdatedC ? UR.UpdatedC : C; RC = UR.UpdatedRC ? UR.UpdatedRC : RC; @@ -615,12 +628,20 @@ if (CG.lookupSCC(*N) != CurrentC) continue; - PreservedAnalyses PassPA = Pass.run(N->getFunction(), FAM); + Function &F = N->getFunction(); + + PassInstrumentation PI = FAM.getResult(F); + if (!PI.runBeforePass(Pass, F)) + continue; + + PreservedAnalyses PassPA = Pass.run(F, FAM); + + PI.runAfterPass(Pass, F); // We know that the function pass couldn't have invalidated any other // function's analyses (that's the contract of a function pass), so // directly handle the function analysis manager's invalidation here. - FAM.invalidate(N->getFunction(), PassPA); + FAM.invalidate(F, PassPA); // Then intersect the preserved set so that invalidation of module // analyses will eventually occur when the module pass completes. @@ -690,6 +711,8 @@ PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR) { PreservedAnalyses PA = PreservedAnalyses::all(); + PassInstrumentation PI = + AM.getResult(InitialC, CG); // The SCC may be refined while we are running passes over it, so set up // a pointer that we can update. @@ -733,8 +756,14 @@ auto CallCounts = ScanSCC(*C, CallHandles); for (int Iteration = 0;; ++Iteration) { + + if (!PI.runBeforePass(Pass, *C)) + continue; + PreservedAnalyses PassPA = Pass.run(*C, AM, CG, UR); + PI.runAfterPass(Pass, *C); + // If the SCC structure has changed, bail immediately and let the outer // CGSCC layer handle any iteration to reflect the refined structure. if (UR.UpdatedC && UR.UpdatedC != C) { Index: include/llvm/IR/PassInstrumentation.h =================================================================== --- /dev/null +++ include/llvm/IR/PassInstrumentation.h @@ -0,0 +1,179 @@ +//===- llvm/IR/PassInstrumentation.h ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the Pass Instrumentation classes that provide +/// instrumentation points into the pass execution by PassManager. +/// +/// There are two main classes: +/// - PassInstrumentation provides a set of instrumentation points for +/// pass managers to call on. It is light on copy since it is queries +/// through the analysis framework as a result of the analysis. +/// +/// - PassInstrumentationCallbacks registers callbacks and provides access +/// - to them for PassInstrumentation. +/// +/// PassInstrumentation object is light on copy since it is being +/// used as a result of PassInstrumentationAnalysis. +/// +/// Intended scheme of use for Pass Instrumentation is as follows: +/// - register instrumentation callbacks in PassInstrumentationCallbacks +/// instance. PassBuilder provides helper for that. +/// +/// - register PassInstrumentationAnalysis with all the PassManagers. +/// PassBuilder handles that automatically when registering analyses. +/// +/// - Pass Manager requests PassInstrumentationAnalysis from analysis manager +/// and gets PassInstrumentation as its result. +/// +/// - Pass Manager invokes PassInstrumentation entry points appropriately, +/// passing StringRef identification ("name") of the pass currently being +/// executed and IRUnit it works on. There can be different schemes of +/// providing names in future, currently it is just a name() of the pass. +/// +/// - PassInstrumentation wraps address of IRUnit into llvm::Any and passes +/// control to all the registered callbacks. Note that we specifically wrap +/// 'const IRUnitT*' so as to avoid any accidental changes to IR in +/// instrumenting callbacks. +/// +/// - Some instrumentation points (BeforePass) allow to control execution +/// of a pass. For those callbacks returning false means pass will not be +/// executed. +/// +/// TODO: currently there is no way for a pass to opt-out of execution control +/// (e.g. become unskippable). PassManager is the only entity that determines +/// how pass instrumentation affects pass execution. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_PASSINSTRUMENTATION_H +#define LLVM_IR_PASSINSTRUMENTATION_H + +#include "llvm/ADT/Any.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/TypeName.h" +#include + +namespace llvm { + +class PreservedAnalyses; + +/// This class provides a simple way to track execution of passes. +/// It is intended as a helper for individual instrumentation callbacks +/// that need to track pass execution. +class PassExecutionCounter { + unsigned count = 0; + +public: + PassExecutionCounter() = default; + PassExecutionCounter(const PassExecutionCounter &PC) = default; + PassExecutionCounter(PassExecutionCounter &&PC) = default; + + PassExecutionCounter &operator=(const PassExecutionCounter &PC) { + count = PC.count; + return *this; + } + + operator int() const { return count; } + + /// preincrement, advance the counter + void operator++() { count++; } +}; + +/// This class manages callbacks registration, as well as provides a way for +/// PassInstrumentation to pass control to the registered callbacks. +class PassInstrumentationCallbacks { +public: + // Before/After Pass callbacks accept IRUnits, so they need to take them + // as pointers, wrapped with llvm::Any + using BeforePassFunc = bool(StringRef, Any); + using AfterPassFunc = void(StringRef, Any); + using BeforeAnalysisFunc = void(StringRef, Any); + using AfterAnalysisFunc = void(StringRef, Any); + +public: + PassInstrumentationCallbacks() {} + + /// Copying PassInstrumentationCallbacks is not intended. + PassInstrumentationCallbacks(const PassInstrumentationCallbacks &) = delete; + void operator=(const PassInstrumentationCallbacks &) = delete; + + void registerBeforePassCallback(const std::function &C) { + BeforePassCallbacks.push_back(C); + } + + void registerAfterPassCallback(const std::function &C) { + AfterPassCallbacks.push_back(C); + } + +private: + // Instrumentation calls should not be used as a public interface. + // Only for consumption by PassInstrumentation. + friend class PassInstrumentation; + + /// BeforePass instrumentation point - takes \p PassID identifier for the + /// pass instance to be executed and constant reference to IR it operates on. + /// Note, that PassID currently is not meant to be unique per-pass-instance. + /// \Returns true if pass is allowed to be executed. + template + bool runBeforePass(StringRef PassID, const IRUnitT &) const; + + /// AfterPass instrumentation point - takes \p PassID identifier for the pass + /// instance that has just been and constant reference to IR it operated on. + /// Note, that PassID currently is not meant to be unique per-pass-instance. + template + void runAfterPass(StringRef PassID, const IRUnitT &) const; + + // instrumentation callbacks + SmallVector, 4> BeforePassCallbacks; + SmallVector, 4> AfterPassCallbacks; +}; + +/// This class provides instrumentation entry points for the Pass Manager, +/// doing calls to callbacks registered in PassInstrumentationCallbacks. +class PassInstrumentation { + const PassInstrumentationCallbacks *Callbacks; + +public: + PassInstrumentation(const PassInstrumentationCallbacks *CB = nullptr) + : Callbacks(CB) {} + + /// BeforePass instrumentation point - takes \p Pass instance to be executed + /// and constant reference to IR it operates on. \Returns true if pass is + /// allowed to be executed. + template + bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const { + if (Callbacks) + return Callbacks->runBeforePass(Pass.name(), IR); + return true; + } + + /// AfterPass instrumentation point - takes \p PassID instance that has + /// just been executed and constant reference to IR it operates on. + template + void runAfterPass(const PassT &Pass, const IRUnitT &IR) const { + if (Callbacks) + Callbacks->runAfterPass(Pass.name(), IR); + } + + /// Handle invalidation from the pass manager when PassInstrumentation + /// is used as the result of PassInstrumentationAnalysis. + /// + /// On attempt to invalidate just return false. There is nothing to become + /// invalid here. + template + bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &, + ExtraArgsT...) { + return false; + } +}; + +} // namespace llvm + +#endif Index: include/llvm/IR/PassManager.h =================================================================== --- include/llvm/IR/PassManager.h +++ include/llvm/IR/PassManager.h @@ -44,6 +44,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassInstrumentation.h" #include "llvm/IR/PassManagerInternal.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TypeName.h" @@ -402,6 +403,41 @@ } }; +namespace detail { + +/// Actual unpacker of extra arguments in getAnalysisResult, +/// passes only those tuple arguments that are mentioned in index_sequence. +template +typename PassT::Result +getAnalysisResultUnpackTuple(AnalysisManagerT &AM, IRUnitT &IR, + std::tuple Args, + llvm::index_sequence) { + (void)Args; + return AM.template getResult(IR, std::get(Args)...); +} + +/// Helper for *partial* unpacking of extra arguments in getAnalysisResult. +/// +/// Arguments passed in tuple come from PassManager, so they might have extra +/// arguments after those AnalysisManager's ExtraArgTs ones that we need to +/// pass to getResult. +template +typename PassT::Result +getAnalysisResult(AnalysisManager &AM, IRUnitT &IR, + std::tuple Args) { + return (getAnalysisResultUnpackTuple< + PassT, IRUnitT>)(AM, IR, Args, + llvm::index_sequence_for{}); +} + +} // namespace detail + +// Forward declare the pass instrumentation analysis explicitly queried in +// generic PassManager code. +class PassInstrumentationAnalysis; + /// Manages a sequence of passes over a particular unit of IR. /// /// A pass manager contains a sequence of passes to run over a particular unit @@ -445,15 +481,34 @@ ExtraArgTs... ExtraArgs) { PreservedAnalyses PA = PreservedAnalyses::all(); + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + // Here we use std::tuple wrapper over getResult which helps to extract + // AnalysisManager's arguments out of the whole ExtraArgs set. + PassInstrumentation PI = + detail::getAnalysisResult( + AM, IR, std::tuple(ExtraArgs...)); + if (DebugLogging) dbgs() << "Starting " << getTypeName() << " pass manager run.\n"; for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { + auto *P = Passes[Idx].get(); if (DebugLogging) - dbgs() << "Running pass: " << Passes[Idx]->name() << " on " - << IR.getName() << "\n"; + dbgs() << "Running pass: " << P->name() << " on " << IR.getName() + << "\n"; + + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(*P, IR)) + continue; + + PreservedAnalyses PassPA = P->run(IR, AM, ExtraArgs...); - PreservedAnalyses PassPA = Passes[Idx]->run(IR, AM, ExtraArgs...); + // Call onto PassInstrumentation's AfterPass callbacks immediately after + // running the pass. + PI.runAfterPass(*P, IR); // Update the analysis manager as each pass runs and potentially // invalidates analyses. @@ -510,6 +565,30 @@ /// Convenience typedef for a pass manager over functions. using FunctionPassManager = PassManager; +/// Pseudo-analysis pass that exposes the \c PassInstrumentation to pass +/// managers. Goes before AnalysisManager definition to provide its +/// internals (e.g PassInstrumentationAnalysis::ID) for use there if needed. +class PassInstrumentationAnalysis + : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; + + /// Shared PassInstrumentation object. Owned by something else, not this + /// analysis. + PassInstrumentationCallbacks *PIC; + +public: + PassInstrumentationAnalysis(PassInstrumentationCallbacks *PIC = nullptr) + : PIC(PIC) {} + + using Result = PassInstrumentation; + + template + Result run(IRUnitT &, AnalysisManagerT &, ExtraArgTs &&...) { + return PassInstrumentation(PIC); + } +}; + /// A container for analyses that lazily runs them and caches their /// results. /// @@ -680,6 +759,10 @@ AnalysisResultLists.clear(); } + template bool isRegisteredAnalysis() const { + return AnalysisPasses.count(PassT::ID()) != 0; + } + /// Get the result of an analysis pass for a given IR unit. /// /// Runs the analysis if a cached result is not available. @@ -1192,13 +1275,24 @@ FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult(M); + PreservedAnalyses PA = PreservedAnalyses::all(); for (Function &F : M) { if (F.isDeclaration()) continue; + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(Pass, F)) + continue; PreservedAnalyses PassPA = Pass.run(F, FAM); + PI.runAfterPass(Pass, F); + // We know that the function pass couldn't have invalidated any other // function's analyses (that's the contract of a function pass), so // directly handle the function analysis manager's invalidation here. @@ -1302,10 +1396,26 @@ RepeatedPass(int Count, PassT P) : Count(Count), P(std::move(P)) {} template - PreservedAnalyses run(IRUnitT &Arg, AnalysisManagerT &AM, Ts &&... Args) { + PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, Ts &&... Args) { + + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + // Here we use std::tuple wrapper over getResult which helps to extract + // AnalysisManager's arguments out of the whole Args set. + PassInstrumentation PI = + detail::getAnalysisResult( + AM, IR, std::tuple(Args...)); + auto PA = PreservedAnalyses::all(); - for (int i = 0; i < Count; ++i) - PA.intersect(P.run(Arg, AM, std::forward(Args)...)); + for (int i = 0; i < Count; ++i) { + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(P, IR)) + continue; + PA.intersect(P.run(IR, AM, std::forward(Args)...)); + PI.runAfterPass(P, IR); + } return PA; } Index: include/llvm/IR/PassManagerInternal.h =================================================================== --- include/llvm/IR/PassManagerInternal.h +++ include/llvm/IR/PassManagerInternal.h @@ -48,7 +48,7 @@ ExtraArgTs... ExtraArgs) = 0; /// Polymorphic method to access the name of a pass. - virtual StringRef name() = 0; + virtual StringRef name() const = 0; }; /// A template wrapper used to implement the polymorphic API. @@ -80,7 +80,7 @@ return Pass.run(IR, AM, ExtraArgs...); } - StringRef name() override { return PassT::name(); } + StringRef name() const override { return PassT::name(); } PassT Pass; }; @@ -250,7 +250,7 @@ ExtraArgTs... ExtraArgs) = 0; /// Polymorphic method to access the name of a pass. - virtual StringRef name() = 0; + virtual StringRef name() const = 0; }; /// Wrapper to model the analysis pass concept. @@ -290,13 +290,14 @@ AnalysisResultConcept> run(IRUnitT &IR, AnalysisManager &AM, ExtraArgTs... ExtraArgs) override { - return llvm::make_unique(Pass.run(IR, AM, ExtraArgs...)); + return llvm::make_unique( + Pass.run(IR, AM, std::forward(ExtraArgs)...)); } /// The model delegates to a static \c PassT::name method. /// /// The returned string ref must point to constant immutable data! - StringRef name() override { return PassT::name(); } + StringRef name() const override { return PassT::name(); } PassT Pass; }; Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -58,6 +58,11 @@ class PassBuilder { TargetMachine *TM; Optional PGOOpt; + PassInstrumentationCallbacks *PIC; + + PassInstrumentationCallbacks *getPassInstrumentationCallbacks() const { + return PIC; + } public: /// A struct to capture parsed pass pipeline names. @@ -172,8 +177,9 @@ }; explicit PassBuilder(TargetMachine *TM = nullptr, - Optional PGOOpt = None) - : TM(TM), PGOOpt(PGOOpt) {} + Optional PGOOpt = None, + PassInstrumentationCallbacks *PIC = nullptr) + : TM(TM), PGOOpt(PGOOpt), PIC(PIC) {} /// Cross register the analysis managers through their proxies. /// @@ -555,6 +561,18 @@ TopLevelPipelineParsingCallbacks.push_back(C); } + /// Calls registration function \p C on PassInstrumentationCallbacks object + /// to register pass instrumentation callbacks there. + /// + /// \Returns false if there is no pass instrumentation object available. + bool registerPassInstrumentation( + const std::function &C) { + if (!PIC) + return false; + C(*PIC); + return true; + } + private: static Optional> parsePipelineText(StringRef Text); Index: include/llvm/Transforms/Scalar/LoopPassManager.h =================================================================== --- include/llvm/Transforms/Scalar/LoopPassManager.h +++ include/llvm/Transforms/Scalar/LoopPassManager.h @@ -276,7 +276,15 @@ // pass pipeline to put loops into their canonical form. Note that we can // directly build up function analyses after this as the function pass // manager handles all the invalidation at that layer. - PreservedAnalyses PA = LoopCanonicalizationFPM.run(F, AM); + PassInstrumentation PI = AM.getResult(F); + + PreservedAnalyses PA = PreservedAnalyses::all(); + // Check the PassInstrumentation's BeforePass callbacks before running the + // canonicalization pipeline. + if (PI.runBeforePass(LoopCanonicalizationFPM, F)) { + PA = LoopCanonicalizationFPM.run(F, AM); + PI.runAfterPass(LoopCanonicalizationFPM, F); + } // Get the loop structure for this function LoopInfo &LI = AM.getResult(F); @@ -337,8 +345,15 @@ assert(L->isRecursivelyLCSSAForm(LAR.DT, LI) && "Loops must remain in LCSSA form!"); #endif - + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(Pass, *L)) + continue; PreservedAnalyses PassPA = Pass.run(*L, LAM, LAR, Updater); + + PI.runAfterPass(Pass, *L); + // FIXME: We should verify the set of analyses relevant to Loop passes // are preserved. Index: lib/Analysis/CGSCCPassManager.cpp =================================================================== --- lib/Analysis/CGSCCPassManager.cpp +++ lib/Analysis/CGSCCPassManager.cpp @@ -54,6 +54,11 @@ CGSCCUpdateResult &>::run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM, LazyCallGraph &G, CGSCCUpdateResult &UR) { + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = + AM.getResult(InitialC, G); + PreservedAnalyses PA = PreservedAnalyses::all(); if (DebugLogging) @@ -67,8 +72,15 @@ if (DebugLogging) dbgs() << "Running pass: " << Pass->name() << " on " << *C << "\n"; + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns false). + if (!PI.runBeforePass(*Pass, *C)) + continue; + PreservedAnalyses PassPA = Pass->run(*C, AM, G, UR); + PI.runAfterPass(*Pass, *C); + // Update the SCC if necessary. C = UR.UpdatedC ? UR.UpdatedC : C; Index: lib/FuzzMutate/IRMutator.cpp =================================================================== --- lib/FuzzMutate/IRMutator.cpp +++ lib/FuzzMutate/IRMutator.cpp @@ -73,6 +73,7 @@ FPM.addPass(DCEPass()); FunctionAnalysisManager FAM; FAM.registerPass([&] { return TargetLibraryAnalysis(); }); + FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); FPM.run(F, FAM); } Index: lib/IR/CMakeLists.txt =================================================================== --- lib/IR/CMakeLists.txt +++ lib/IR/CMakeLists.txt @@ -42,6 +42,7 @@ Operator.cpp OptBisect.cpp Pass.cpp + PassInstrumentation.cpp PassManager.cpp PassRegistry.cpp PassTimingInfo.cpp Index: lib/IR/PassInstrumentation.cpp =================================================================== --- /dev/null +++ lib/IR/PassInstrumentation.cpp @@ -0,0 +1,63 @@ +//===- PassInstrumentation.cpp - Pass Instrumentation interface -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file provides the implementation of PassInstrumentation class. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/PassInstrumentation.h" +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +template +bool PassInstrumentationCallbacks::runBeforePass(StringRef PassID, + const IRUnitT &IR) const { + bool shouldRun = true; + for (auto &C : BeforePassCallbacks) + shouldRun &= C(PassID, llvm::Any(&IR)); + return shouldRun; +} + +template +void PassInstrumentationCallbacks::runAfterPass(StringRef PassID, + const IRUnitT &IR) const { + for (auto &C : AfterPassCallbacks) + C(PassID, llvm::Any(&IR)); +} + +template bool +PassInstrumentationCallbacks::runBeforePass(StringRef PassID, + const Module &IR) const; +template bool +PassInstrumentationCallbacks::runBeforePass(StringRef PassID, + const Function &IR) const; +template bool PassInstrumentationCallbacks::runBeforePass(StringRef PassID, + const Loop &IR) const; +template bool +PassInstrumentationCallbacks::runBeforePass(StringRef PassID, + const LazyCallGraph::SCC &IR) const; +template void +PassInstrumentationCallbacks::runAfterPass(StringRef PassID, + const Module &IR) const; +template void +PassInstrumentationCallbacks::runAfterPass(StringRef PassID, + const Function &IR) const; +template void PassInstrumentationCallbacks::runAfterPass(StringRef PassID, + const Loop &IR) const; +template void +PassInstrumentationCallbacks::runAfterPass(StringRef PassID, + const LazyCallGraph::SCC &IR) const; + +AnalysisKey PassInstrumentationAnalysis::Key; + +} // namespace llvm Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -315,6 +315,10 @@ MAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + MAM.registerPass([&] { + return PassInstrumentationAnalysis(this->getPassInstrumentationCallbacks()); + }); + for (auto &C : ModuleAnalysisRegistrationCallbacks) C(MAM); } @@ -324,6 +328,10 @@ CGAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + CGAM.registerPass([&] { + return PassInstrumentationAnalysis(this->getPassInstrumentationCallbacks()); + }); + for (auto &C : CGSCCAnalysisRegistrationCallbacks) C(CGAM); } @@ -333,6 +341,10 @@ FAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + FAM.registerPass([&] { + return PassInstrumentationAnalysis(this->getPassInstrumentationCallbacks()); + }); + for (auto &C : FunctionAnalysisRegistrationCallbacks) C(FAM); } @@ -342,6 +354,10 @@ LAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + LAM.registerPass([&] { + return PassInstrumentationAnalysis(this->getPassInstrumentationCallbacks()); + }); + for (auto &C : LoopAnalysisRegistrationCallbacks) C(LAM); } Index: lib/Transforms/Scalar/LoopPassManager.cpp =================================================================== --- lib/Transforms/Scalar/LoopPassManager.cpp +++ lib/Transforms/Scalar/LoopPassManager.cpp @@ -30,12 +30,22 @@ if (DebugLogging) dbgs() << "Starting Loop pass manager run.\n"; + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult(L, AR); for (auto &Pass : Passes) { if (DebugLogging) dbgs() << "Running pass: " << Pass->name() << " on " << L; + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns false). + if (!PI.runBeforePass(*Pass, L)) + continue; + PreservedAnalyses PassPA = Pass->run(L, AM, AR, U); + PI.runAfterPass(*Pass, L); + // If the loop was deleted, abort the run and return to the outer walk. if (U.skipCurrentLoop()) { PA.intersect(std::move(PassPA)); Index: test/Other/loop-pm-invalidation.ll =================================================================== --- test/Other/loop-pm-invalidation.ll +++ test/Other/loop-pm-invalidation.ll @@ -73,6 +73,7 @@ ; CHECK-LOOP-INV-NEXT: Running analysis: TargetIRAnalysis ; CHECK-LOOP-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}LoopAnalysis @@ -90,6 +91,7 @@ ; CHECK-LOOP-INV-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-LOOP-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Function pass manager run. @@ -108,6 +110,7 @@ ; CHECK-SCEV-INV-NEXT: Running analysis: TargetIRAnalysis ; CHECK-SCEV-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ScalarEvolutionAnalysis @@ -123,6 +126,7 @@ ; CHECK-SCEV-INV-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-SCEV-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Function pass manager run. @@ -153,9 +157,11 @@ ; CHECK-LOOP-INV-NEXT: Running analysis: TargetIRAnalysis ; CHECK-LOOP-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}LoopAnalysis @@ -174,9 +180,11 @@ ; CHECK-LOOP-INV-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-LOOP-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Function pass manager run. @@ -195,9 +203,11 @@ ; CHECK-SCEV-INV-NEXT: Running analysis: TargetIRAnalysis ; CHECK-SCEV-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ScalarEvolutionAnalysis @@ -214,9 +224,11 @@ ; CHECK-SCEV-INV-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-SCEV-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Function pass manager run. @@ -254,6 +266,7 @@ ; CHECK-LOOP-INV-NEXT: Running analysis: TargetIRAnalysis ; CHECK-LOOP-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}LoopAnalysis @@ -271,6 +284,7 @@ ; CHECK-LOOP-INV-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-LOOP-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-LOOP-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-LOOP-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-LOOP-INV-NEXT: Finished {{.*}}Function pass manager run. @@ -289,6 +303,7 @@ ; CHECK-SCEV-INV-NEXT: Running analysis: TargetIRAnalysis ; CHECK-SCEV-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ScalarEvolutionAnalysis @@ -304,6 +319,7 @@ ; CHECK-SCEV-INV-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-SCEV-INV-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Loop pass manager run. ; CHECK-SCEV-INV-NEXT: Finished {{.*}}Function pass manager run. @@ -322,6 +338,7 @@ ; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Running analysis: TargetIRAnalysis ; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Loop ; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Starting {{.*}}Loop pass manager run. +; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Running pass: NoOpLoopPass ; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Running pass: LoopDeletionPass ; CHECK-SCEV-INV-AFTER-DELETE-NEXT: Clearing all analysis results for: Index: test/Other/new-pass-manager.ll =================================================================== --- test/Other/new-pass-manager.ll +++ test/Other/new-pass-manager.ll @@ -24,6 +24,7 @@ ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*(FunctionAnalysisManager|AnalysisManager<.*Function.*>).*}},{{.*}}Module> ; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis ; CHECK-CGSCC-PASS-NEXT: Running analysis: TargetLibraryAnalysis +; CHECK-CGSCC-PASS-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-CGSCC-PASS-NEXT: Starting CGSCC pass manager run ; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass ; CHECK-CGSCC-PASS-NEXT: Finished CGSCC pass manager run @@ -38,6 +39,7 @@ ; CHECK-FUNCTION-PASS: Starting llvm::Module pass manager run ; CHECK-FUNCTION-PASS-NEXT: Running pass: ModuleToFunctionPassAdaptor ; CHECK-FUNCTION-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-FUNCTION-PASS-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run ; CHECK-FUNCTION-PASS-NEXT: Running pass: NoOpFunctionPass ; CHECK-FUNCTION-PASS-NEXT: Finished llvm::Function pass manager run @@ -408,6 +410,7 @@ ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*(FunctionAnalysisManager|AnalysisManager<.*Function.*>).*}},{{.*}}Module> ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: TargetLibraryAnalysis +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting CGSCC pass manager run ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: RepeatedPass ; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting CGSCC pass manager run @@ -428,6 +431,7 @@ ; CHECK-REPEAT-FUNCTION-PASS: Starting llvm::Module pass manager run ; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: ModuleToFunctionPassAdaptor ; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-REPEAT-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run ; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: RepeatedPass ; CHECK-REPEAT-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run @@ -448,6 +452,7 @@ ; CHECK-REPEAT-LOOP-PASS: Starting llvm::Module pass manager run ; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: ModuleToFunctionPassAdaptor ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Function pass manager run ; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: FunctionToLoopPassAdaptor ; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Function pass manager run @@ -464,6 +469,7 @@ ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: TargetIRAnalysis ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> ; CHECK-REPEAT-LOOP-PASS-NEXT: Starting Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: RepeatedPass ; CHECK-REPEAT-LOOP-PASS-NEXT: Starting Loop pass manager run ; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: NoOpLoopPass Index: test/Other/new-pm-defaults.ll =================================================================== --- test/Other/new-pm-defaults.ll +++ test/Other/new-pm-defaults.ll @@ -67,7 +67,8 @@ ; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \ ; RUN: --check-prefix=CHECK-EP-PIPELINE-START -; CHECK-O: Starting llvm::Module pass manager run. +; CHECK-O: Running analysis: PassInstrumentationAnalysis +; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module{{.*}}> ; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass @@ -78,6 +79,7 @@ ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Starting llvm::Function pass manager run. ; CHECK-O-NEXT: Running pass: SimplifyCFGPass ; CHECK-O-NEXT: Running analysis: TargetIRAnalysis @@ -110,6 +112,7 @@ ; CHECK-O-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}LazyCallGraph{{.*}}> ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy ; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Starting CGSCC pass manager run. ; CHECK-O-NEXT: Running pass: InlinerPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy<{{.*}}LazyCallGraph{{.*}}> @@ -145,6 +148,7 @@ ; CHECK-O-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy ; CHECK-O-NEXT: Starting Loop pass manager run. +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Running pass: LoopInstSimplifyPass ; CHECK-O-NEXT: Running pass: LoopSimplifyCFGPass ; CHECK-O-NEXT: Running pass: LoopRotatePass Index: test/Other/new-pm-lto-defaults.ll =================================================================== --- test/Other/new-pm-lto-defaults.ll +++ test/Other/new-pm-lto-defaults.ll @@ -23,7 +23,8 @@ ; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O2 \ ; RUN: --check-prefix=CHECK-O3 --check-prefix=CHECK-EP-Peephole -; CHECK-O: Starting llvm::Module pass manager run. +; CHECK-O: Running analysis: PassInstrumentationAnalysis +; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module ; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: GlobalDCEPass @@ -32,6 +33,7 @@ ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> ; CHECK-O2-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Module +; CHECK-O2-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O2-NEXT: Starting llvm::Function pass manager run. ; CHECK-O2-NEXT: Running pass: CallSiteSplittingPass on foo ; CHECK-O2-NEXT: Running analysis: TargetLibraryAnalysis on foo Index: test/Other/new-pm-thinlto-defaults.ll =================================================================== --- test/Other/new-pm-thinlto-defaults.ll +++ test/Other/new-pm-thinlto-defaults.ll @@ -47,7 +47,8 @@ ; RUN: -passes='thinlto' -S %s 2>&1 \ ; RUN: | FileCheck %s --check-prefixes=CHECK-O,CHECK-O2,CHECK-POSTLINK-O,CHECK-POSTLINK-O2 ; -; CHECK-O: Starting llvm::Module pass manager run. +; CHECK-O: Running analysis: PassInstrumentationAnalysis +; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module{{.*}}> ; CHECK-O-NEXT: Starting llvm::Module pass manager run. ; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass @@ -64,6 +65,7 @@ ; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> ; CHECK-PRELINK-O-NODIS-NEXT: Running analysis: InnerAnalysisManagerProxy +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Starting llvm::Function pass manager run. ; CHECK-O-NEXT: Running pass: SimplifyCFGPass ; CHECK-O-NEXT: Running analysis: TargetIRAnalysis @@ -95,6 +97,7 @@ ; CHECK-O-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}LazyCallGraph{{.*}}> ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy ; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Starting CGSCC pass manager run. ; CHECK-O-NEXT: Running pass: InlinerPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy<{{.*}}LazyCallGraph{{.*}}> @@ -129,6 +132,7 @@ ; CHECK-O-NEXT: Running analysis: ScalarEvolutionAnalysis ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy ; CHECK-O-NEXT: Starting Loop pass manager run. +; CHECK-O-NEXT: Running analysis: PassInstrumentationAnalysis ; CHECK-O-NEXT: Running pass: LoopInstSimplifyPass ; CHECK-O-NEXT: Running pass: LoopSimplifyCFGPass ; CHECK-O-NEXT: Running pass: LoopRotatePass Index: test/Transforms/Inline/cgscc-incremental-invalidate.ll =================================================================== --- test/Transforms/Inline/cgscc-incremental-invalidate.ll +++ test/Transforms/Inline/cgscc-incremental-invalidate.ll @@ -33,7 +33,8 @@ ; CHECK-NEXT: Running pass: DominatorTreeVerifierPass on test1_g ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_g ; CHECK-NEXT: Finished llvm::Function pass manager run. -; CHECK-NEXT: Starting llvm::Function pass manager run. +; CHECK-NOT: Invalidating analysis: +; CHECK: Starting llvm::Function pass manager run. ; CHECK-NEXT: Running pass: DominatorTreeVerifierPass on test1_h ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_h ; CHECK-NEXT: Finished llvm::Function pass manager run. Index: test/Transforms/LoopRotate/pr35210.ll =================================================================== --- test/Transforms/LoopRotate/pr35210.ll +++ test/Transforms/LoopRotate/pr35210.ll @@ -21,6 +21,7 @@ ; CHECK-NEXT: Running analysis: TargetIRAnalysis on f ; CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy{{.*}} on f ; CHECK-NEXT: Starting Loop pass manager run. +; CHECK-NEXT: Running analysis: PassInstrumentationAnalysis on bb ; CHECK-NEXT: Running pass: LoopRotatePass on Loop at depth 1 containing: %bb
,%bb4 ; CHECK-NEXT: Folding loop latch bb4 into bb ; CHECK-NEXT: Invalidating all non-preserved analyses for: bb Index: unittests/Analysis/CGSCCPassManagerTest.cpp =================================================================== --- unittests/Analysis/CGSCCPassManagerTest.cpp +++ unittests/Analysis/CGSCCPassManagerTest.cpp @@ -231,6 +231,13 @@ MAM.registerPass([&] { return TargetLibraryAnalysis(); }); MAM.registerPass([&] { return LazyCallGraphAnalysis(); }); MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); + + // Register required pass instrumentation analysis. + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + CGAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + + // Cross-register proxies. MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); }); CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); }); CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); }); Index: unittests/IR/PassBuilderCallbacksTest.cpp =================================================================== --- unittests/IR/PassBuilderCallbacksTest.cpp +++ unittests/IR/PassBuilderCallbacksTest.cpp @@ -7,14 +7,18 @@ // //===----------------------------------------------------------------------===// +#include #include #include +#include #include #include #include #include +#include #include #include +#include #include #include @@ -32,6 +36,8 @@ } namespace { +using testing::AnyNumber; +using testing::AtLeast; using testing::DoDefault; using testing::Return; using testing::Expectation; @@ -87,6 +93,7 @@ typename Analysis::Result getResult() { return typename Analysis::Result(static_cast(*this)); } + static StringRef getName() { return llvm::getTypeName(); } protected: // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within @@ -143,6 +150,8 @@ } }; + static StringRef getName() { return llvm::getTypeName(); } + Pass getPass() { return Pass(static_cast(*this)); } protected: @@ -253,11 +262,68 @@ MockAnalysisHandle() { setDefaults(); } }; +struct MockPassInstrumentationCallbacks { + MockPassInstrumentationCallbacks() { + ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true)); + // Generic EXPECT_CALLs are needed to match instrumentation on unimportant + // parts of a pipeline that we do not care about (e.g. various passes added + // by default by PassBuilder - Verifier pass etc). + EXPECT_CALL(*this, runBeforePass(_, _)).Times(AnyNumber()); + EXPECT_CALL(*this, runAfterPass(_, _)).Times(AnyNumber()); + } + MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any)); + MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any)); +}; + static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { SMDiagnostic Err; return parseAssemblyString(IR, Err, C); } +/// Helper for HasName matcher that returns getName both for IRUnit and +/// for IRUnit pointer wrapper into llvm::Any (wrapped by PassInstrumentation). +template StringRef getName(const IRUnitT &IR) { + return IR.getName(); +} + +template <> StringRef getName(const StringRef &name) { return name; } + +template <> StringRef getName(const llvm::Any &WrappedIR) { + if (any_isa(WrappedIR)) + return any_cast(WrappedIR)->getName(); + if (any_isa(WrappedIR)) + return any_cast(WrappedIR)->getName(); + if (any_isa(WrappedIR)) + return any_cast(WrappedIR)->getName(); + if (any_isa(WrappedIR)) + return any_cast(WrappedIR)->getName(); + return ""; +} +/// Define a custom matcher for objects which support a 'getName' method. +/// +/// LLVM often has IR objects or analysis objects which expose a name +/// and in tests it is convenient to match these by name for readability. +/// Usually, this name is either a StringRef or a plain std::string. This +/// matcher supports any type exposing a getName() method of this form whose +/// return value is compatible with an std::ostream. For StringRef, this uses +/// the shift operator defined above. +/// +/// It should be used as: +/// +/// HasName("my_function") +/// +/// No namespace or other qualification is required. +MATCHER_P(HasName, Name, "") { + *result_listener << "has name '" << getName(arg) << "'"; + return Name == getName(arg); +} + +MATCHER_P(HasNameRegex, Name, "") { + *result_listener << "has name '" << getName(arg) << "'"; + llvm::Regex r(Name); + return r.match(getName(arg)); +} + template class PassBuilderCallbacksTest; /// This test fixture is shared between all the actual tests below and @@ -280,6 +346,7 @@ LLVMContext Context; std::unique_ptr M; + PassInstrumentationCallbacks PIC; PassBuilder PB; ModulePassManager PM; LoopAnalysisManager LAM; @@ -289,6 +356,7 @@ MockPassHandle PassHandle; MockAnalysisHandle AnalysisHandle; + MockPassInstrumentationCallbacks PICallbacks; static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM, ExtraAnalysisArgTs &&... Args) { @@ -312,7 +380,8 @@ "exit:\n" " ret void\n" "}\n")), - PM(true), LAM(true), FAM(true), CGAM(true), AM(true) { + PIC(), PB(nullptr, None, &PIC), PM(true), LAM(true), FAM(true), + CGAM(true), AM(true) { /// Register a callback for analysis registration. /// @@ -347,6 +416,16 @@ return false; }); + /// Register pass instrumentation + PB.registerPassInstrumentation([this](PassInstrumentationCallbacks &PIC) { + using namespace std::placeholders; + PIC.registerBeforePassCallback( + std::bind(&MockPassInstrumentationCallbacks::runBeforePass, + &PICallbacks, _1, _2)); + PIC.registerAfterPassCallback( + std::bind(&MockPassInstrumentationCallbacks::runAfterPass, + &PICallbacks, _1, _2)); + }); /// Register builtin analyses and cross-register the analysis proxies PB.registerModuleAnalyses(AM); PB.registerCGSCCAnalyses(CGAM); @@ -356,25 +435,6 @@ } }; -/// Define a custom matcher for objects which support a 'getName' method. -/// -/// LLVM often has IR objects or analysis objects which expose a name -/// and in tests it is convenient to match these by name for readability. -/// Usually, this name is either a StringRef or a plain std::string. This -/// matcher supports any type exposing a getName() method of this form whose -/// return value is compatible with an std::ostream. For StringRef, this uses -/// the shift operator defined above. -/// -/// It should be used as: -/// -/// HasName("my_function") -/// -/// No namespace or other qualification is required. -MATCHER_P(HasName, Name, "") { - *result_listener << "has name '" << arg.getName() << "'"; - return Name == arg.getName(); -} - using ModuleCallbacksTest = PassBuilderCallbacksTest; using CGSCCCallbacksTest = PassBuilderCallbacksTest; using FunctionCallbacksTest = PassBuilderCallbacksTest; @@ -391,6 +451,47 @@ StringRef PipelineText = "test-transform"; ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) << "Pipeline was: " << PipelineText; + + PM.run(*M, AM); +} + +TEST_F(ModuleCallbacksTest, InstrumentedPasses) { + EXPECT_CALL(AnalysisHandle, run(HasName(""), _)); + EXPECT_CALL(PassHandle, run(HasName(""), _)) + .WillOnce(Invoke(getAnalysisResult)); + + { + testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), + HasName(""))); + EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), + HasName(""))); + } + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + + PM.run(*M, AM); +} + +TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) { + // Skip the pass by returning false. + EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), + HasName(""))) + .WillOnce(Return(false)); + + EXPECT_CALL(AnalysisHandle, run(HasName(""), _)).Times(0); + EXPECT_CALL(PassHandle, run(HasName(""), _)).Times(0); + + // As the pass is skipped there is no afterPass as well. + EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); } @@ -405,6 +506,44 @@ PM.run(*M, AM); } +TEST_F(FunctionCallbacksTest, InstrumentedPasses) { + EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)); + EXPECT_CALL(PassHandle, run(HasName("foo"), _)) + .WillOnce(Invoke(getAnalysisResult)); + + { + testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, + runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))); + EXPECT_CALL(PICallbacks, + runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"))); + } + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) { + // Skip the pass by returning false. + EXPECT_CALL(PICallbacks, + runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo"))) + .WillOnce(Return(false)); + + EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0); + EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0); + + // As the pass is skipped there is no afterPass as well. + EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + TEST_F(LoopCallbacksTest, Passes) { EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) @@ -416,6 +555,43 @@ PM.run(*M, AM); } +TEST_F(LoopCallbacksTest, InstrumentedPasses) { + EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)); + EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)) + .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); + { + testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, + runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))); + EXPECT_CALL(PICallbacks, + runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"))); + } + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) { + // Skip the pass by returning false. + EXPECT_CALL(PICallbacks, + runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop"))) + .WillOnce(Return(false)); + + EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0); + EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0); + + // As the pass is skipped there is no afterPass as well. + EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + TEST_F(CGSCCCallbacksTest, Passes) { EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) @@ -427,6 +603,45 @@ PM.run(*M, AM); } +TEST_F(CGSCCCallbacksTest, InstrumentedPasses) { + EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)); + EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)) + .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult))); + + { + testing::InSequence InstrumentationExpectationsSequenced; + EXPECT_CALL(PICallbacks, runBeforePass(HasNameRegex("MockPassHandle"), + HasName("(foo)"))); + EXPECT_CALL(PICallbacks, + runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"))); + } + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + +TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) { + // Skip the pass by returning false. + EXPECT_CALL(PICallbacks, + runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)"))) + .WillOnce(Return(false)); + + // neither Analysis nor Pass are called. + EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0); + EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0); + + // As the pass is skipped there is no afterPass as well. + EXPECT_CALL(PICallbacks, runAfterPass(HasNameRegex("MockPassHandle"), _)) + .Times(0); + + StringRef PipelineText = "test-transform"; + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true)) + << "Pipeline was: " << PipelineText; + PM.run(*M, AM); +} + /// Test parsing of the names of analysis utilities for our mock analysis /// for all IRUnits. /// Index: unittests/IR/PassManagerTest.cpp =================================================================== --- unittests/IR/PassManagerTest.cpp +++ unittests/IR/PassManagerTest.cpp @@ -406,6 +406,9 @@ MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + ModulePassManager MPM; // Count the runs over a Function. @@ -556,6 +559,8 @@ TEST_F(PassManagerTest, CustomizedPassManagerArgs) { CustomizedAnalysisManager AM; AM.registerPass([&] { return CustomizedAnalysis(); }); + PassInstrumentationCallbacks PIC; + AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); }); CustomizedPassManager PM; @@ -688,6 +693,10 @@ MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); + PassInstrumentationCallbacks PIC; + MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); }); + FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); }); + int InstrCount = 0, FunctionCount = 0; ModulePassManager MPM(/*DebugLogging*/ true); FunctionPassManager FPM(/*DebugLogging*/ true); Index: unittests/Transforms/Scalar/LoopPassManagerTest.cpp =================================================================== --- unittests/Transforms/Scalar/LoopPassManagerTest.cpp +++ unittests/Transforms/Scalar/LoopPassManagerTest.cpp @@ -308,6 +308,11 @@ FAM.registerPass([&] { return TargetLibraryAnalysis(); }); FAM.registerPass([&] { return TargetIRAnalysis(); }); + // Register required pass instrumentation analysis. + LAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + FAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); + // Cross-register proxies. LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); }); FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });