aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Analysis/CGSCCPassManager.h33
-rw-r--r--llvm/include/llvm/IR/PassInstrumentation.h150
-rw-r--r--llvm/include/llvm/IR/PassManager.h122
-rw-r--r--llvm/include/llvm/Passes/PassBuilder.h6
-rw-r--r--llvm/include/llvm/Transforms/Scalar/LoopPassManager.h19
-rw-r--r--llvm/lib/Analysis/CGSCCPassManager.cpp12
-rw-r--r--llvm/lib/FuzzMutate/IRMutator.cpp1
-rw-r--r--llvm/lib/IR/CMakeLists.txt1
-rw-r--r--llvm/lib/IR/PassInstrumentation.cpp22
-rw-r--r--llvm/lib/Passes/PassRegistry.def4
-rw-r--r--llvm/lib/Transforms/Scalar/LoopPassManager.cpp10
-rw-r--r--llvm/test/Other/loop-pm-invalidation.ll17
-rw-r--r--llvm/test/Other/new-pass-manager.ll6
-rw-r--r--llvm/test/Other/new-pm-defaults.ll6
-rw-r--r--llvm/test/Other/new-pm-lto-defaults.ll4
-rw-r--r--llvm/test/Other/new-pm-thinlto-defaults.ll6
-rw-r--r--llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll3
-rw-r--r--llvm/test/Transforms/LoopRotate/pr35210.ll1
-rw-r--r--llvm/unittests/Analysis/CGSCCPassManagerTest.cpp7
-rw-r--r--llvm/unittests/IR/PassBuilderCallbacksTest.cpp311
-rw-r--r--llvm/unittests/IR/PassManagerTest.cpp9
-rw-r--r--llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp5
22 files changed, 720 insertions, 35 deletions
diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h
index 5e83ea2..f150064 100644
--- a/llvm/include/llvm/Analysis/CGSCCPassManager.h
+++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h
@@ -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
index 0000000..3fdda6c
--- /dev/null
+++ b/llvm/include/llvm/IR/PassInstrumentation.h
@@ -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
diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index 3c18bbd..f318237 100644
--- a/llvm/include/llvm/IR/PassManager.h
+++ b/llvm/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,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;
}
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 24a93bc..02d3dc3 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -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.
///
diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
index 0d691f3..e54960d 100644
--- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
+++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
@@ -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.
diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp
index b325afb..6965235 100644
--- a/llvm/lib/Analysis/CGSCCPassManager.cpp
+++ b/llvm/lib/Analysis/CGSCCPassManager.cpp
@@ -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;
diff --git a/llvm/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp
index 2dc7dfb..40e402c 100644
--- a/llvm/lib/FuzzMutate/IRMutator.cpp
+++ b/llvm/lib/FuzzMutate/IRMutator.cpp
@@ -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);
}
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index a194b84..2586f98 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -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
index 0000000..5aa2bc6
--- /dev/null
+++ b/llvm/lib/IR/PassInstrumentation.cpp
@@ -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
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 5748c0d..b070b0e 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -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
diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
index 10f6fcd..6759bd2 100644
--- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
@@ -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));
diff --git a/llvm/test/Other/loop-pm-invalidation.ll b/llvm/test/Other/loop-pm-invalidation.ll
index a6f5302..20acb35 100644
--- a/llvm/test/Other/loop-pm-invalidation.ll
+++ b/llvm/test/Other/loop-pm-invalidation.ll
@@ -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:
diff --git a/llvm/test/Other/new-pass-manager.ll b/llvm/test/Other/new-pass-manager.ll
index 320fd04..5f5ba19 100644
--- a/llvm/test/Other/new-pass-manager.ll
+++ b/llvm/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
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index 10580e4..114514a 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/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{{.*}}>
@@ -149,6 +152,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
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 741ed64..92b4153 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/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
diff --git a/llvm/test/Other/new-pm-thinlto-defaults.ll b/llvm/test/Other/new-pm-thinlto-defaults.ll
index dae51eb..ece33c8 100644
--- a/llvm/test/Other/new-pm-thinlto-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-defaults.ll
@@ -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{{.*}}>
@@ -133,6 +136,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
diff --git a/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll b/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll
index 164f7a6..ba9f087 100644
--- a/llvm/test/Transforms/Inline/cgscc-incremental-invalidate.ll
+++ b/llvm/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.
diff --git a/llvm/test/Transforms/LoopRotate/pr35210.ll b/llvm/test/Transforms/LoopRotate/pr35210.ll
index e92ae4b4..3033ca8 100644
--- a/llvm/test/Transforms/LoopRotate/pr35210.ll
+++ b/llvm/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<header><exiting>,%bb4<latch>
; CHECK-NEXT: Folding loop latch bb4 into bb
; CHECK-NEXT: Invalidating all non-preserved analyses for: bb
diff --git a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
index aa0be73..60da2bb 100644
--- a/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
+++ b/llvm/unittests/Analysis/CGSCCPassManagerTest.cpp
@@ -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); });
diff --git a/llvm/unittests/IR/PassBuilderCallbacksTest.cpp b/llvm/unittests/IR/PassBuilderCallbacksTest.cpp
index e46fc17..024e7d6 100644
--- a/llvm/unittests/IR/PassBuilderCallbacksTest.cpp
+++ b/llvm/unittests/IR/PassBuilderCallbacksTest.cpp
@@ -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> std::string getName(const IRUnitT &IR) {
+ return IR.getName();
+}
+
+template <> std::string getName(const StringRef &name) { return name; }
+
+template <> std::string getName(const llvm::Any &WrappedIR) {
+ if (any_isa<const Module *>(WrappedIR))
+ return any_cast<const Module *>(WrappedIR)->getName().str();
+ if (any_isa<const Function *>(WrappedIR))
+ return any_cast<const Function *>(WrappedIR)->getName().str();
+ if (any_isa<const Loop *>(WrappedIR))
+ return any_cast<const Loop *>(WrappedIR)->getName().str();
+ 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.
///
diff --git a/llvm/unittests/IR/PassManagerTest.cpp b/llvm/unittests/IR/PassManagerTest.cpp
index 7709453..13b87f1 100644
--- a/llvm/unittests/IR/PassManagerTest.cpp
+++ b/llvm/unittests/IR/PassManagerTest.cpp
@@ -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);
diff --git a/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp b/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
index 57fb57e..9f0b6f0 100644
--- a/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
+++ b/llvm/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
@@ -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); });