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(),
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;
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.
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.
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) {
--- /dev/null
+//===- 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
#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"
}
};
+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
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.
/// 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.
///
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.
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;
}
class PassBuilder {
TargetMachine *TM;
Optional<PGOOptions> PGOOpt;
+ PassInstrumentationCallbacks *PIC;
public:
/// A struct to capture parsed pass pipeline names.
};
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.
///
// 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);
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.
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)
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;
FPM.addPass(DCEPass());
FunctionAnalysisManager FAM;
FAM.registerPass([&] { return TargetLibraryAnalysis(); });
+ FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
FPM.run(F, FAM);
}
Operator.cpp
OptBisect.cpp
Pass.cpp
+ PassInstrumentation.cpp
PassManager.cpp
PassRegistry.cpp
PassTimingInfo.cpp
--- /dev/null
+//===- 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
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) \
#endif
CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
CGSCC_ANALYSIS("fam-proxy", FunctionAnalysisManagerCGSCCProxy())
+CGSCC_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
#undef CGSCC_ANALYSIS
#ifndef CGSCC_PASS
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) \
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
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));
; 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
; 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.
; 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
; 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.
; 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
; 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.
; 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
; 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.
; 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
; 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.
; 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
; 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.
; 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:
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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
; 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.
; 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
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); });
//
//===----------------------------------------------------------------------===//
+#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>
}
namespace {
+using testing::AnyNumber;
+using testing::AtLeast;
using testing::DoDefault;
+using testing::Not;
using testing::Return;
using testing::Expectation;
using testing::Invoke;
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
}
};
+ static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
+
Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
protected:
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
LLVMContext Context;
std::unique_ptr<Module> M;
+ MockPassInstrumentationCallbacks CallbacksHandle;
+
PassBuilder PB;
ModulePassManager PM;
LoopAnalysisManager LAM;
"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.
}
};
-/// 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>;
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);
}
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"), _, _, _))
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)"), _, _, _))
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.
///
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.
TEST_F(PassManagerTest, CustomizedPassManagerArgs) {
CustomizedAnalysisManager AM;
AM.registerPass([&] { return CustomizedAnalysis(); });
+ PassInstrumentationCallbacks PIC;
+ AM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
CustomizedPassManager PM;
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);
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); });