[New PM] Introducing PassInstrumentation framework
authorFedor Sergeev <fedor.sergeev@azul.com>
Wed, 19 Sep 2018 22:42:57 +0000 (22:42 +0000)
committerFedor Sergeev <fedor.sergeev@azul.com>
Wed, 19 Sep 2018 22:42:57 +0000 (22:42 +0000)
Pass Execution Instrumentation interface enables customizable instrumentation
of pass execution, as per "RFC: Pass Execution Instrumentation interface"
posted 06/07/2018 on llvm-dev@

The intent is to provide a common machinery to implement all
the pass-execution-debugging features like print-before/after,
opt-bisect, time-passes etc.

Here we get a basic implementation consisting of:
* PassInstrumentationCallbacks class that handles registration of callbacks
  and access to them.

* PassInstrumentation class that handles instrumentation-point interfaces
  that call into PassInstrumentationCallbacks.

* Callbacks accept StringRef which is just a name of the Pass right now.
  There were some ideas to pass an opaque wrapper for the pointer to pass instance,
  however it appears that pointer does not actually identify the instance
  (adaptors and managers might have the same address with the pass they govern).
  Hence it was decided to go simple for now and then later decide on what the proper
  mental model of identifying a "pass in a phase of pipeline" is.

* Callbacks accept llvm::Any serving as a wrapper for const IRUnit*, to remove direct dependencies
  on different IRUnits (e.g. Analyses).

* PassInstrumentationAnalysis analysis is explicitly requested from PassManager through
  usual AnalysisManager::getResult. All pass managers were updated to run that
  to get PassInstrumentation object for instrumentation calls.

* Using tuples/index_sequence getAnalysisResult helper to extract generic AnalysisManager's extra
  args out of a generic PassManager's extra args. This is the only way I was able to explicitly
  run getResult for PassInstrumentationAnalysis out of a generic code like PassManager::run or
  RepeatedPass::run.
  TODO: Upon lengthy discussions we agreed to accept this as an initial implementation
  and then get rid of getAnalysisResult by improving RepeatedPass implementation.

* PassBuilder takes PassInstrumentationCallbacks object to pass it further into
  PassInstrumentationAnalysis. Callbacks registration should be performed directly
  through PassInstrumentationCallbacks.

* new-pm tests updated to account for PassInstrumentationAnalysis being run

* Added PassInstrumentation tests to PassBuilderCallbacks unit tests.
  Other unit tests updated with registration of the now-required PassInstrumentationAnalysis.

Reviewers: chandlerc, philip.pfaffe
Differential Revision: https://reviews.llvm.org/D47858

llvm-svn: 342597

22 files changed:
llvm/include/llvm/Analysis/CGSCCPassManager.h
llvm/include/llvm/IR/PassInstrumentation.h [new file with mode: 0644]
llvm/include/llvm/IR/PassManager.h
llvm/include/llvm/Passes/PassBuilder.h
llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
llvm/lib/Analysis/CGSCCPassManager.cpp
llvm/lib/FuzzMutate/IRMutator.cpp
llvm/lib/IR/CMakeLists.txt
llvm/lib/IR/PassInstrumentation.cpp [new file with mode: 0644]
llvm/lib/Passes/PassRegistry.def
llvm/lib/Transforms/Scalar/LoopPassManager.cpp
llvm/test/Other/loop-pm-invalidation.ll
llvm/test/Other/new-pass-manager.ll
llvm/test/Other/new-pm-defaults.ll
llvm/test/Other/new-pm-lto-defaults.ll
llvm/test/Other/new-pm-thinlto-defaults.ll
llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll
llvm/test/Transforms/LoopRotate/pr35210.ll
llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
llvm/unittests/IR/PassBuilderCallbacksTest.cpp
llvm/unittests/IR/PassManagerTest.cpp
llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp

index 5e83ea2..f150064 100644 (file)
@@ -364,6 +364,10 @@ public:
                             InvalidSCCSet,       nullptr,   nullptr,
                             InlinedInternalEdges};
 
+    // Request PassInstrumentation from analysis manager, will use it to run
+    // instrumenting callbacks for the passes later.
+    PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(M);
+
     PreservedAnalyses PA = PreservedAnalyses::all();
     CG.buildRefSCCs();
     for (auto RCI = CG.postorder_ref_scc_begin(),
@@ -428,8 +432,17 @@ public:
 
             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<LazyCallGraph::SCC>(Pass, *C))
+              continue;
+
             PreservedAnalyses PassPA = Pass.run(*C, CGAM, CG, UR);
 
+            PI.runAfterPass<LazyCallGraph::SCC>(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 @@ public:
       if (CG.lookupSCC(*N) != CurrentC)
         continue;
 
-      PreservedAnalyses PassPA = Pass.run(N->getFunction(), FAM);
+      Function &F = N->getFunction();
+
+      PassInstrumentation PI = FAM.getResult<PassInstrumentationAnalysis>(F);
+      if (!PI.runBeforePass<Function>(Pass, F))
+        continue;
+
+      PreservedAnalyses PassPA = Pass.run(F, FAM);
+
+      PI.runAfterPass<Function>(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 @@ public:
   PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM,
                         LazyCallGraph &CG, CGSCCUpdateResult &UR) {
     PreservedAnalyses PA = PreservedAnalyses::all();
+    PassInstrumentation PI =
+        AM.getResult<PassInstrumentationAnalysis>(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 @@ public:
     auto CallCounts = ScanSCC(*C, CallHandles);
 
     for (int Iteration = 0;; ++Iteration) {
+
+      if (!PI.runBeforePass<LazyCallGraph::SCC>(Pass, *C))
+        continue;
+
       PreservedAnalyses PassPA = Pass.run(*C, AM, CG, UR);
 
+      PI.runAfterPass<LazyCallGraph::SCC>(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) {
diff --git a/llvm/include/llvm/IR/PassInstrumentation.h b/llvm/include/llvm/IR/PassInstrumentation.h
new file mode 100644 (file)
index 0000000..3fdda6c
--- /dev/null
@@ -0,0 +1,150 @@
+//===- 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.
+///
+///   - PassInstrumentationCallbacks registers callbacks and provides access
+///     to them for PassInstrumentation.
+///
+/// PassInstrumentation object is being used as a result of
+/// PassInstrumentationAnalysis (so it is intended to be easily copyable).
+///
+/// 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/FunctionExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/TypeName.h"
+#include <type_traits>
+
+namespace llvm {
+
+class PreservedAnalyses;
+
+/// 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;
+
+  template <typename CallableT> void registerBeforePassCallback(CallableT C) {
+    BeforePassCallbacks.emplace_back(std::move(C));
+  }
+
+  template <typename CallableT> void registerAfterPassCallback(CallableT C) {
+    AfterPassCallbacks.emplace_back(std::move(C));
+  }
+
+private:
+  friend class PassInstrumentation;
+
+  SmallVector<llvm::unique_function<BeforePassFunc>, 4> BeforePassCallbacks;
+  SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks;
+};
+
+/// This class provides instrumentation entry points for the Pass Manager,
+/// doing calls to callbacks registered in PassInstrumentationCallbacks.
+class PassInstrumentation {
+  PassInstrumentationCallbacks *Callbacks;
+
+public:
+  /// Callbacks object is not owned by PassInstrumentation, its life-time
+  /// should at least match the life-time of corresponding
+  /// PassInstrumentationAnalysis (which usually is till the end of current
+  /// compilation).
+  PassInstrumentation(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 <typename IRUnitT, typename PassT>
+  bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const {
+    if (!Callbacks)
+      return true;
+
+    bool ShouldRun = true;
+    for (auto &C : Callbacks->BeforePassCallbacks)
+      ShouldRun &= C(Pass.name(), llvm::Any(&IR));
+    return ShouldRun;
+  }
+
+  /// AfterPass instrumentation point - takes \p Pass instance that has
+  /// just been executed and constant reference to IR it operates on.
+  template <typename IRUnitT, typename PassT>
+  void runAfterPass(const PassT &Pass, const IRUnitT &IR) const {
+    if (Callbacks)
+      for (auto &C : Callbacks->AfterPassCallbacks)
+        C(Pass.name(), llvm::Any(&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 <typename IRUnitT, typename... ExtraArgsT>
+  bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &,
+                  ExtraArgsT...) {
+    return false;
+  }
+};
+
+} // namespace llvm
+
+#endif
index 3c18bbd..f318237 100644 (file)
@@ -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,43 @@ struct AnalysisInfoMixin : PassInfoMixin<DerivedT> {
   }
 };
 
+namespace detail {
+
+/// Actual unpacker of extra arguments in getAnalysisResult,
+/// passes only those tuple arguments that are mentioned in index_sequence.
+template <typename PassT, typename IRUnitT, typename AnalysisManagerT,
+          typename... ArgTs, size_t... Ns>
+typename PassT::Result
+getAnalysisResultUnpackTuple(AnalysisManagerT &AM, IRUnitT &IR,
+                             std::tuple<ArgTs...> Args,
+                             llvm::index_sequence<Ns...>) {
+  (void)Args;
+  return AM.template getResult<PassT>(IR, std::get<Ns>(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, typename IRUnitT, typename... AnalysisArgTs,
+          typename... MainArgTs>
+typename PassT::Result
+getAnalysisResult(AnalysisManager<IRUnitT, AnalysisArgTs...> &AM, IRUnitT &IR,
+                  std::tuple<MainArgTs...> Args) {
+  return (getAnalysisResultUnpackTuple<
+          PassT, IRUnitT>)(AM, IR, Args,
+                           llvm::index_sequence_for<AnalysisArgTs...>{});
+}
+
+} // namespace detail
+
+// Forward declare the pass instrumentation analysis explicitly queried in
+// generic PassManager code.
+// FIXME: figure out a way to move PassInstrumentationAnalysis into its own
+// header.
+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 +483,34 @@ public:
                         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<PassInstrumentationAnalysis>(
+            AM, IR, std::tuple<ExtraArgTs...>(ExtraArgs...));
+
     if (DebugLogging)
       dbgs() << "Starting " << getTypeName<IRUnitT>() << " 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<IRUnitT>(*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<IRUnitT>(*P, IR);
 
       // Update the analysis manager as each pass runs and potentially
       // invalidates analyses.
@@ -510,6 +567,32 @@ extern template class PassManager<Function>;
 /// Convenience typedef for a pass manager over functions.
 using FunctionPassManager = PassManager<Function>;
 
+/// 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.
+/// FIXME: figure out a way to move PassInstrumentationAnalysis into its own
+/// header.
+class PassInstrumentationAnalysis
+    : public AnalysisInfoMixin<PassInstrumentationAnalysis> {
+  friend AnalysisInfoMixin<PassInstrumentationAnalysis>;
+  static AnalysisKey Key;
+
+  PassInstrumentationCallbacks *Callbacks;
+
+public:
+  /// PassInstrumentationCallbacks object is shared, owned by something else,
+  /// not this analysis.
+  PassInstrumentationAnalysis(PassInstrumentationCallbacks *Callbacks = nullptr)
+      : Callbacks(Callbacks) {}
+
+  using Result = PassInstrumentation;
+
+  template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
+  Result run(IRUnitT &, AnalysisManagerT &, ExtraArgTs &&...) {
+    return PassInstrumentation(Callbacks);
+  }
+};
+
 /// A container for analyses that lazily runs them and caches their
 /// results.
 ///
@@ -1192,13 +1275,24 @@ public:
     FunctionAnalysisManager &FAM =
         AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
 
+    // Request PassInstrumentation from analysis manager, will use it to run
+    // instrumenting callbacks for the passes later.
+    PassInstrumentation PI = AM.getResult<PassInstrumentationAnalysis>(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<Function>(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 @@ public:
   RepeatedPass(int Count, PassT P) : Count(Count), P(std::move(P)) {}
 
   template <typename IRUnitT, typename AnalysisManagerT, typename... Ts>
-  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<PassInstrumentationAnalysis>(
+            AM, IR, std::tuple<Ts...>(Args...));
+
     auto PA = PreservedAnalyses::all();
-    for (int i = 0; i < Count; ++i)
-      PA.intersect(P.run(Arg, AM, std::forward<Ts>(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<IRUnitT>(P, IR))
+        continue;
+      PA.intersect(P.run(IR, AM, std::forward<Ts>(Args)...));
+      PI.runAfterPass(P, IR);
+    }
     return PA;
   }
 
index 24a93bc..02d3dc3 100644 (file)
@@ -58,6 +58,7 @@ struct PGOOptions {
 class PassBuilder {
   TargetMachine *TM;
   Optional<PGOOptions> PGOOpt;
+  PassInstrumentationCallbacks *PIC;
 
 public:
   /// A struct to capture parsed pass pipeline names.
@@ -172,8 +173,9 @@ public:
   };
 
   explicit PassBuilder(TargetMachine *TM = nullptr,
-                       Optional<PGOOptions> PGOOpt = None)
-      : TM(TM), PGOOpt(PGOOpt) {}
+                       Optional<PGOOptions> PGOOpt = None,
+                       PassInstrumentationCallbacks *PIC = nullptr)
+      : TM(TM), PGOOpt(PGOOpt), PIC(PIC) {}
 
   /// Cross register the analysis managers through their proxies.
   ///
index 0d691f3..e54960d 100644 (file)
@@ -276,7 +276,15 @@ public:
     // 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<PassInstrumentationAnalysis>(F);
+
+    PreservedAnalyses PA = PreservedAnalyses::all();
+    // Check the PassInstrumentation's BeforePass callbacks before running the
+    // canonicalization pipeline.
+    if (PI.runBeforePass<Function>(LoopCanonicalizationFPM, F)) {
+      PA = LoopCanonicalizationFPM.run(F, AM);
+      PI.runAfterPass<Function>(LoopCanonicalizationFPM, F);
+    }
 
     // Get the loop structure for this function
     LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
@@ -337,8 +345,15 @@ public:
       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<Loop>(Pass, *L))
+        continue;
       PreservedAnalyses PassPA = Pass.run(*L, LAM, LAR, Updater);
+
+      PI.runAfterPass<Loop>(Pass, *L);
+
       // FIXME: We should verify the set of analyses relevant to Loop passes
       // are preserved.
 
index b325afb..6965235 100644 (file)
@@ -54,6 +54,11 @@ PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &,
             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<PassInstrumentationAnalysis>(InitialC, G);
+
   PreservedAnalyses PA = PreservedAnalyses::all();
 
   if (DebugLogging)
@@ -67,8 +72,15 @@ PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &,
     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 2dc7dfb..40e402c 100644 (file)
@@ -73,6 +73,7 @@ static void eliminateDeadCode(Function &F) {
   FPM.addPass(DCEPass());
   FunctionAnalysisManager FAM;
   FAM.registerPass([&] { return TargetLibraryAnalysis(); });
+  FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
   FPM.run(F, FAM);
 }
 
index a194b84..2586f98 100644 (file)
@@ -42,6 +42,7 @@ add_llvm_library(LLVMCore
   Operator.cpp
   OptBisect.cpp
   Pass.cpp
+  PassInstrumentation.cpp
   PassManager.cpp
   PassRegistry.cpp
   PassTimingInfo.cpp
diff --git a/llvm/lib/IR/PassInstrumentation.cpp b/llvm/lib/IR/PassInstrumentation.cpp
new file mode 100644 (file)
index 0000000..5aa2bc6
--- /dev/null
@@ -0,0 +1,22 @@
+//===- 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/IR/PassManager.h"
+
+namespace llvm {
+
+AnalysisKey PassInstrumentationAnalysis::Key;
+
+} // namespace llvm
index 5748c0d..b070b0e 100644 (file)
@@ -26,6 +26,7 @@ MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
 MODULE_ANALYSIS("profile-summary", ProfileSummaryAnalysis())
 MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
 MODULE_ANALYSIS("verify", VerifierAnalysis())
+MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
 
 #ifndef MODULE_ALIAS_ANALYSIS
 #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS)                               \
@@ -84,6 +85,7 @@ MODULE_PASS("verify", VerifierPass())
 #endif
 CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
 CGSCC_ANALYSIS("fam-proxy", FunctionAnalysisManagerCGSCCProxy())
+CGSCC_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
 #undef CGSCC_ANALYSIS
 
 #ifndef CGSCC_PASS
@@ -121,6 +123,7 @@ FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
 FUNCTION_ANALYSIS("targetir",
                   TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())
 FUNCTION_ANALYSIS("verify", VerifierAnalysis())
+FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
 
 #ifndef FUNCTION_ALIAS_ANALYSIS
 #define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS)                             \
@@ -226,6 +229,7 @@ FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass())
 LOOP_ANALYSIS("no-op-loop", NoOpLoopAnalysis())
 LOOP_ANALYSIS("access-info", LoopAccessAnalysis())
 LOOP_ANALYSIS("ivusers", IVUsersAnalysis())
+LOOP_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
 #undef LOOP_ANALYSIS
 
 #ifndef LOOP_PASS
index 10f6fcd..6759bd2 100644 (file)
@@ -30,12 +30,22 @@ PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
   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<PassInstrumentationAnalysis>(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<Loop>(*Pass, L))
+      continue;
+
     PreservedAnalyses PassPA = Pass->run(L, AM, AR, U);
 
+    PI.runAfterPass<Loop>(*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 a6f5302..20acb35 100644 (file)
@@ -73,6 +73,7 @@ define void @one_loop(i1* %ptr) {
 ; 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 @@ define void @one_loop(i1* %ptr) {
 ; 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 @@ define void @one_loop(i1* %ptr) {
 ; 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 @@ define void @one_loop(i1* %ptr) {
 ; 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 @@ define void @nested_loops(i1* %ptr) {
 ; 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 @@ define void @nested_loops(i1* %ptr) {
 ; 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 @@ define void @nested_loops(i1* %ptr) {
 ; 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 @@ define void @nested_loops(i1* %ptr) {
 ; 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 @@ define void @dead_loop() {
 ; 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 @@ define void @dead_loop() {
 ; 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 @@ define void @dead_loop() {
 ; 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 @@ define void @dead_loop() {
 ; 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 @@ define void @dead_loop() {
 ; 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 320fd04..5f5ba19 100644 (file)
@@ -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
 ; 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
 ; 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
 ; 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
 ; 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 10580e4..114514a 100644 (file)
@@ -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
 ; 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{{.*}}>
 ; 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 741ed64..92b4153 100644 (file)
@@ -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 dae51eb..ece33c8 100644 (file)
@@ -47,7 +47,8 @@
 ; RUN:     -passes='thinlto<O2>' -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{{.*}}>
 ; 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 164f7a6..ba9f087 100644 (file)
@@ -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 e92ae4b..3033ca8 100644 (file)
@@ -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<header><exiting>,%bb4<latch>
 ; CHECK-NEXT: Folding loop latch bb4 into bb
 ; CHECK-NEXT: Invalidating all non-preserved analyses for: bb
index aa0be73..60da2bb 100644 (file)
@@ -231,6 +231,13 @@ public:
     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 e46fc17..fb01fd1 100644 (file)
@@ -7,14 +7,18 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <functional>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <llvm/ADT/Any.h>
 #include <llvm/Analysis/CGSCCPassManager.h>
 #include <llvm/Analysis/LoopAnalysisManager.h>
 #include <llvm/AsmParser/Parser.h>
 #include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/PassInstrumentation.h>
 #include <llvm/IR/PassManager.h>
 #include <llvm/Passes/PassBuilder.h>
+#include <llvm/Support/Regex.h>
 #include <llvm/Support/SourceMgr.h>
 #include <llvm/Transforms/Scalar/LoopPassManager.h>
 
@@ -32,7 +36,10 @@ static std::ostream &operator<<(std::ostream &O, StringRef S) {
 }
 
 namespace {
+using testing::AnyNumber;
+using testing::AtLeast;
 using testing::DoDefault;
+using testing::Not;
 using testing::Return;
 using testing::Expectation;
 using testing::Invoke;
@@ -87,6 +94,7 @@ public:
   typename Analysis::Result getResult() {
     return typename Analysis::Result(static_cast<DerivedT &>(*this));
   }
+  static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
 
 protected:
   // FIXME: MSVC seems unable to handle a lambda argument to Invoke from within
@@ -143,6 +151,8 @@ public:
     }
   };
 
+  static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
+
   Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
 
 protected:
@@ -258,6 +268,81 @@ static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
   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 <typename IRUnitT> 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<const Module *>(WrappedIR))
+    return any_cast<const Module *>(WrappedIR)->getName();
+  if (any_isa<const Function *>(WrappedIR))
+    return any_cast<const Function *>(WrappedIR)->getName();
+  if (any_isa<const Loop *>(WrappedIR))
+    return any_cast<const Loop *>(WrappedIR)->getName();
+  if (any_isa<const LazyCallGraph::SCC *>(WrappedIR))
+    return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName();
+  return "<UNKNOWN>";
+}
+/// 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));
+}
+
+struct MockPassInstrumentationCallbacks {
+  PassInstrumentationCallbacks Callbacks;
+
+  MockPassInstrumentationCallbacks() {
+    ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));
+  }
+  MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));
+  MOCK_METHOD2(runAfterPass, void(StringRef PassID, llvm::Any));
+
+  void registerPassInstrumentation() {
+    Callbacks.registerBeforePassCallback([this](StringRef P, llvm::Any IR) {
+      return this->runBeforePass(P, IR);
+    });
+    Callbacks.registerAfterPassCallback(
+        [this](StringRef P, llvm::Any IR) { this->runAfterPass(P, IR); });
+  }
+
+  void ignoreNonMockPassInstrumentation(StringRef IRName) {
+    // 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).
+    // Make sure to avoid ignoring Mock passes/analysis, we definitely want
+    // to check these explicitly.
+    EXPECT_CALL(*this,
+                runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))
+        .Times(AnyNumber());
+    EXPECT_CALL(*this, runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName)))
+        .Times(AnyNumber());
+  }
+};
+
 template <typename PassManagerT> class PassBuilderCallbacksTest;
 
 /// This test fixture is shared between all the actual tests below and
@@ -280,6 +365,8 @@ protected:
   LLVMContext Context;
   std::unique_ptr<Module> M;
 
+  MockPassInstrumentationCallbacks CallbacksHandle;
+
   PassBuilder PB;
   ModulePassManager PM;
   LoopAnalysisManager LAM;
@@ -312,6 +399,7 @@ protected:
                   "exit:\n"
                   "  ret void\n"
                   "}\n")),
+        CallbacksHandle(), PB(nullptr, None, &CallbacksHandle.Callbacks),
         PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
 
     /// Register a callback for analysis registration.
@@ -356,25 +444,6 @@ protected:
   }
 };
 
-/// 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<ModulePassManager>;
 using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
 using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
@@ -391,6 +460,57 @@ TEST_F(ModuleCallbacksTest, Passes) {
   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("<string>"), _));
+  EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
+      .WillOnce(Invoke(getAnalysisResult));
+
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation not specifically mentioned below can be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+
+  // PassInstrumentation calls should happen in-sequence, in the same order
+  // as passes/analyses are scheduled.
+  ::testing::Sequence PISequence;
+  EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
+                                             HasName("<string>")))
+      .InSequence(PISequence);
+  EXPECT_CALL(CallbacksHandle,
+              runAfterPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
+      .InSequence(PISequence);
+
+  StringRef PipelineText = "test-transform";
+  ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+      << "Pipeline was: " << PipelineText;
+
+  PM.run(*M, AM);
+}
+
+TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation run here can safely be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+
+  // Skip the pass by returning false.
+  EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
+                                             HasName("<string>")))
+      .WillOnce(Return(false));
+
+  EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);
+  EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);
+
+  // As the pass is skipped there is no afterPass as well.
+  EXPECT_CALL(CallbacksHandle, 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 +525,56 @@ TEST_F(FunctionCallbacksTest, Passes) {
   PM.run(*M, AM);
 }
 
+TEST_F(FunctionCallbacksTest, InstrumentedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation not specifically mentioned below can be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+
+  EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
+  EXPECT_CALL(PassHandle, run(HasName("foo"), _))
+      .WillOnce(Invoke(getAnalysisResult));
+
+  // PassInstrumentation calls should happen in-sequence, in the same order
+  // as passes/analyses are scheduled.
+  ::testing::Sequence PISequence;
+  EXPECT_CALL(CallbacksHandle,
+              runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
+      .InSequence(PISequence);
+  EXPECT_CALL(CallbacksHandle,
+              runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo")))
+      .InSequence(PISequence);
+
+  StringRef PipelineText = "test-transform";
+  ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+      << "Pipeline was: " << PipelineText;
+  PM.run(*M, AM);
+}
+
+TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation run here can safely be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+
+  // Skip the pass by returning false.
+  EXPECT_CALL(CallbacksHandle,
+              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(CallbacksHandle, 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 +586,58 @@ TEST_F(LoopCallbacksTest, Passes) {
   PM.run(*M, AM);
 }
 
+TEST_F(LoopCallbacksTest, InstrumentedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation not specifically mentioned below can be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
+
+  EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
+  EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
+      .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
+
+  // PassInstrumentation calls should happen in-sequence, in the same order
+  // as passes/analyses are scheduled.
+  ::testing::Sequence PISequence;
+  EXPECT_CALL(CallbacksHandle,
+              runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
+      .InSequence(PISequence);
+  EXPECT_CALL(CallbacksHandle,
+              runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop")))
+      .InSequence(PISequence);
+
+  StringRef PipelineText = "test-transform";
+  ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+      << "Pipeline was: " << PipelineText;
+  PM.run(*M, AM);
+}
+
+TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation run here can safely be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
+
+  // Skip the pass by returning false.
+  EXPECT_CALL(CallbacksHandle,
+              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(CallbacksHandle, 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 +649,57 @@ TEST_F(CGSCCCallbacksTest, Passes) {
   PM.run(*M, AM);
 }
 
+TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation not specifically mentioned below can be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
+
+  EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
+  EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
+      .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
+
+  // PassInstrumentation calls should happen in-sequence, in the same order
+  // as passes/analyses are scheduled.
+  ::testing::Sequence PISequence;
+  EXPECT_CALL(CallbacksHandle,
+              runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
+      .InSequence(PISequence);
+  EXPECT_CALL(CallbacksHandle,
+              runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
+      .InSequence(PISequence);
+
+  StringRef PipelineText = "test-transform";
+  ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
+      << "Pipeline was: " << PipelineText;
+  PM.run(*M, AM);
+}
+
+TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {
+  CallbacksHandle.registerPassInstrumentation();
+  // Non-mock instrumentation run here can safely be ignored.
+  CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
+  CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
+
+  // Skip the pass by returning false.
+  EXPECT_CALL(CallbacksHandle,
+              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(CallbacksHandle, 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 7709453..13b87f1 100644 (file)
@@ -406,6 +406,9 @@ TEST_F(PassManagerTest, Basic) {
   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 @@ struct CustomizedPass : PassInfoMixin<CustomizedPass> {
 TEST_F(PassManagerTest, CustomizedPassManagerArgs) {
   CustomizedAnalysisManager AM;
   AM.registerPass([&] { return CustomizedAnalysis(); });
+  PassInstrumentationCallbacks PIC;
+  AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
 
   CustomizedPassManager PM;
 
@@ -688,6 +693,10 @@ TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
   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 57fb57e..9f0b6f0 100644 (file)
@@ -308,6 +308,11 @@ public:
     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); });