[llvm] r307532 - [PM] Enable registration of out-of-tree passes with PassBuilder
Philip Pfaffe via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 11 16:04:22 PDT 2017
Hi Galina,
There is one additional thing I'm wondering about. I fixed this commit
in r307534 first. The Darwin lld bot remained red because there was an
another error in it. But I didn't get an email about that second error. Is
that intentional or a limitation of Buildbot? It would be nice to get
separate emails for different errors, because it's difficult to filter this
out from all the build fail noise.
Cheers,
Philip
On Jul 11, 2017 02:04, "Galina Kistanova" <gkistanova at gmail.com> wrote:
Hello Philip,
Looks like this commit broke one of our builders:
http://lab.llvm.org:8011/builders/lld-x86_64-darwin13/builds/10240
Please have a look?
Thanks
Galina
On Mon, Jul 10, 2017 at 3:57 AM, Philip Pfaffe via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: pfaffe
> Date: Mon Jul 10 03:57:55 2017
> New Revision: 307532
>
> URL: http://llvm.org/viewvc/llvm-project?rev=307532&view=rev
> Log:
> [PM] Enable registration of out-of-tree passes with PassBuilder
>
> Summary:
> This patch adds a callback registration API to the PassBuilder,
> enabling registering out-of-tree passes with it.
>
> Through the Callback API, callers may register callbacks with the
> various stages at which passes are added into pass managers, including
> parsing of a pass pipeline as well as at extension points within the
> default -O pipelines.
>
> Registering utilities like `require<>` and `invalidate<>` needs to be
> handled manually by the caller, but a helper is provided.
>
> Additionally, adding passes at pipeline extension points is exposed
> through the opt tool. This patch adds a `-passes-ep-X` commandline
> option for every extension point X, which opt parses into pipelines
> inserted into that extension point.
>
> Reviewers: chandlerc
>
> Reviewed By: chandlerc
>
> Subscribers: lksbhm, grosser, davide, mehdi_amini, llvm-commits, mgorny
>
> Differential Revision: https://reviews.llvm.org/D33464
>
> Added:
> llvm/trunk/unittests/IR/PassBuilderCallbacksTest.cpp
> Modified:
> llvm/trunk/include/llvm/Passes/PassBuilder.h
> llvm/trunk/lib/Passes/PassBuilder.cpp
> llvm/trunk/test/Other/new-pm-defaults.ll
> llvm/trunk/test/Other/new-pm-lto-defaults.ll
> llvm/trunk/tools/opt/NewPMDriver.cpp
> llvm/trunk/unittests/IR/CMakeLists.txt
>
> Modified: llvm/trunk/include/llvm/Passes/PassBuilder.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
> Passes/PassBuilder.h?rev=307532&r1=307531&r2=307532&view=diff
> ============================================================
> ==================
> --- llvm/trunk/include/llvm/Passes/PassBuilder.h (original)
> +++ llvm/trunk/include/llvm/Passes/PassBuilder.h Mon Jul 10 03:57:55 2017
> @@ -46,6 +46,19 @@ class PassBuilder {
> Optional<PGOOptions> PGOOpt;
>
> public:
> + /// \brief A struct to capture parsed pass pipeline names.
> + ///
> + /// A pipeline is defined as a series of names, each of which may in
> itself
> + /// recursively contain a nested pipeline. A name is either the name of
> a pass
> + /// (e.g. "instcombine") or the name of a pipeline type (e.g. "cgscc").
> If the
> + /// name is the name of a pass, the InnerPipeline is empty, since passes
> + /// cannot contain inner pipelines. See parsePassPipeline() for a more
> + /// detailed description of the textual pipeline format.
> + struct PipelineElement {
> + StringRef Name;
> + std::vector<PipelineElement> InnerPipeline;
> + };
> +
> /// \brief LLVM-provided high-level optimization levels.
> ///
> /// This enumerates the LLVM-provided high-level optimization levels.
> Each
> @@ -312,7 +325,8 @@ public:
> /// registered.
> AAManager buildDefaultAAPipeline();
>
> - /// \brief Parse a textual pass pipeline description into a \c
> ModulePassManager.
> + /// \brief Parse a textual pass pipeline description into a \c
> + /// ModulePassManager.
> ///
> /// The format of the textual pass pipeline description looks something
> like:
> ///
> @@ -322,8 +336,8 @@ public:
> /// are comma separated. As a special shortcut, if the very first pass
> is not
> /// a module pass (as a module pass manager is), this will
> automatically form
> /// the shortest stack of pass managers that allow inserting that first
> pass.
> - /// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and
> loop passes
> - /// 'lpassN', all of these are valid:
> + /// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and
> loop
> + /// passes 'lpassN', all of these are valid:
> ///
> /// fpass1,fpass2,fpass3
> /// cgpass1,cgpass2,cgpass3
> @@ -336,13 +350,28 @@ public:
> /// module(function(loop(lpass1,lpass2,lpass3)))
> ///
> /// This shortcut is especially useful for debugging and testing small
> pass
> - /// combinations. Note that these shortcuts don't introduce any other
> magic. If
> - /// the sequence of passes aren't all the exact same kind of pass, it
> will be
> - /// an error. You cannot mix different levels implicitly, you must
> explicitly
> - /// form a pass manager in which to nest passes.
> + /// combinations. Note that these shortcuts don't introduce any other
> magic.
> + /// If the sequence of passes aren't all the exact same kind of pass,
> it will
> + /// be an error. You cannot mix different levels implicitly, you must
> + /// explicitly form a pass manager in which to nest passes.
> bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
> bool VerifyEachPass = true, bool DebugLogging =
> false);
>
> + /// {{@ Parse a textual pass pipeline description into a specific
> PassManager
> + ///
> + /// Automatic deduction of an appropriate pass manager stack is not
> supported.
> + /// For example, to insert a loop pass 'lpass' into a
> FunctinoPassManager,
> + /// this is the valid pipeline text:
> + ///
> + /// function(lpass)
> + bool parsePassPipeline(CGSCCPassManager &CGPM, StringRef PipelineText,
> + bool VerifyEachPass = true, bool DebugLogging =
> false);
> + bool parsePassPipeline(FunctionPassManager &FPM, StringRef
> PipelineText,
> + bool VerifyEachPass = true, bool DebugLogging =
> false);
> + bool parsePassPipeline(LoopPassManager &LPM, StringRef PipelineText,
> + bool VerifyEachPass = true, bool DebugLogging =
> false);
> + /// @}}
> +
> /// Parse a textual alias analysis pipeline into the provided AA
> manager.
> ///
> /// The format of the textual AA pipeline is a comma separated list of
> AA
> @@ -360,13 +389,139 @@ public:
> /// returns false.
> bool parseAAPipeline(AAManager &AA, StringRef PipelineText);
>
> -private:
> - /// A struct to capture parsed pass pipeline names.
> - struct PipelineElement {
> - StringRef Name;
> - std::vector<PipelineElement> InnerPipeline;
> - };
> + /// \brief Register a callback for a default optimizer pipeline
> extension
> + /// point
> + ///
> + /// This extension point allows adding passes that perform peephole
> + /// optimizations similar to the instruction combiner. These passes
> will be
> + /// inserted after each instance of the instruction combiner pass.
> + void registerPeepholeEPCallback(
> + const std::function<void(FunctionPassManager &,
> OptimizationLevel)> &C) {
> + PeepholeEPCallbacks.push_back(C);
> + }
> +
> + /// \brief Register a callback for a default optimizer pipeline
> extension
> + /// point
> + ///
> + /// This extension point allows adding late loop canonicalization and
> + /// simplification passes. This is the last point in the loop
> optimization
> + /// pipeline before loop deletion. Each pass added
> + /// here must be an instance of LoopPass.
> + /// This is the place to add passes that can remove loops, such as
> target-
> + /// specific loop idiom recognition.
> + void registerLateLoopOptimizationsEPCallback(
> + const std::function<void(LoopPassManager &, OptimizationLevel)>
> &C) {
> + LateLoopOptimizationsEPCallbacks.push_back(C);
> + }
> +
> + /// \brief Register a callback for a default optimizer pipeline
> extension
> + /// point
> + ///
> + /// This extension point allows adding loop passes to the end of the
> loop
> + /// optimizer.
> + void registerLoopOptimizerEndEPCallback(
> + const std::function<void(LoopPassManager &, OptimizationLevel)>
> &C) {
> + LoopOptimizerEndEPCallbacks.push_back(C);
> + }
> +
> + /// \brief Register a callback for a default optimizer pipeline
> extension
> + /// point
> + ///
> + /// This extension point allows adding optimization passes after most
> of the
> + /// main optimizations, but before the last cleanup-ish optimizations.
> + void registerScalarOptimizerLateEPCallback(
> + const std::function<void(FunctionPassManager &,
> OptimizationLevel)> &C) {
> + ScalarOptimizerLateEPCallbacks.push_back(C);
> + }
> +
> + /// \brief Register a callback for a default optimizer pipeline
> extension
> + /// point
> + ///
> + /// This extension point allows adding CallGraphSCC passes at the end
> of the
> + /// main CallGraphSCC passes and before any function simplification
> passes run
> + /// by CGPassManager.
> + void registerCGSCCOptimizerLateEPCallback(
> + const std::function<void(CGSCCPassManager &, OptimizationLevel)>
> &C) {
> + CGSCCOptimizerLateEPCallbacks.push_back(C);
> + }
> +
> + /// \brief Register a callback for a default optimizer pipeline
> extension
> + /// point
> + ///
> + /// This extension point allows adding optimization passes before the
> + /// vectorizer and other highly target specific optimization passes are
> + /// executed.
> + void registerVectorizerStartEPCallback(
> + const std::function<void(FunctionPassManager &,
> OptimizationLevel)> &C) {
> + VectorizerStartEPCallbacks.push_back(C);
> + }
> +
> + /// \brief Register a callback for parsing an AliasAnalysis Name to
> populate
> + /// the given AAManager \p AA
> + void registerParseAACallback(
> + const std::function<bool(StringRef Name, AAManager &AA)> &C) {
> + AAParsingCallbacks.push_back(C);
> + }
> +
> + /// {{@ Register callbacks for analysis registration with this
> PassBuilder
> + /// instance.
> + /// Callees register their analyses with the given AnalysisManager
> objects.
> + void registerAnalysisRegistrationCallback(
> + const std::function<void(CGSCCAnalysisManager &)> &C) {
> + CGSCCAnalysisRegistrationCallbacks.push_back(C);
> + }
> + void registerAnalysisRegistrationCallback(
> + const std::function<void(FunctionAnalysisManager &)> &C) {
> + FunctionAnalysisRegistrationCallbacks.push_back(C);
> + }
> + void registerAnalysisRegistrationCallback(
> + const std::function<void(LoopAnalysisManager &)> &C) {
> + LoopAnalysisRegistrationCallbacks.push_back(C);
> + }
> + void registerAnalysisRegistrationCallback(
> + const std::function<void(ModuleAnalysisManager &)> &C) {
> + ModuleAnalysisRegistrationCallbacks.push_back(C);
> + }
> + /// @}}
> +
> + /// {{@ Register pipeline parsing callbacks with this pass builder
> instance.
> + /// Using these callbacks, callers can parse both a single pass name,
> as well
> + /// as entire sub-pipelines, and populate the PassManager instance
> + /// accordingly.
> + void registerPipelineParsingCallback(
> + const std::function<bool(StringRef Name, CGSCCPassManager &,
> + ArrayRef<PipelineElement>)> &C) {
> + CGSCCPipelineParsingCallbacks.push_back(C);
> + }
> + void registerPipelineParsingCallback(
> + const std::function<bool(StringRef Name, FunctionPassManager &,
> + ArrayRef<PipelineElement>)> &C) {
> + FunctionPipelineParsingCallbacks.push_back(C);
> + }
> + void registerPipelineParsingCallback(
> + const std::function<bool(StringRef Name, LoopPassManager &,
> + ArrayRef<PipelineElement>)> &C) {
> + LoopPipelineParsingCallbacks.push_back(C);
> + }
> + void registerPipelineParsingCallback(
> + const std::function<bool(StringRef Name, ModulePassManager &,
> + ArrayRef<PipelineElement>)> &C) {
> + ModulePipelineParsingCallbacks.push_back(C);
> + }
> + /// @}}
> +
> + /// \brief Register a callback for a top-level pipeline entry.
> + ///
> + /// If the PassManager type is not given at the top level of the
> pipeline
> + /// text, this Callback should be used to determine the appropriate
> stack of
> + /// PassManagers and populate the passed ModulePassManager.
> + void registerParseTopLevelPipelineCallback(
> + const std::function<bool(ModulePassManager &,
> ArrayRef<PipelineElement>,
> + bool VerifyEachPass, bool DebugLogging)>
> &C) {
> + TopLevelPipelineParsingCallbacks.push_back(C);
> + }
>
> +private:
> static Optional<std::vector<PipelineElement>>
> parsePipelineText(StringRef Text);
>
> @@ -392,7 +547,106 @@ private:
> bool parseModulePassPipeline(ModulePassManager &MPM,
> ArrayRef<PipelineElement> Pipeline,
> bool VerifyEachPass, bool DebugLogging);
> +
> + void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging,
> + OptimizationLevel Level, bool RunProfileGen,
> + std::string ProfileGenFile,
> + std::string ProfileUseFile);
> +
> + void invokePeepholeEPCallbacks(FunctionPassManager &,
> OptimizationLevel);
> +
> + // Extension Point callbacks
> + SmallVector<std::function<void(FunctionPassManager &,
> OptimizationLevel)>, 2>
> + PeepholeEPCallbacks;
> + SmallVector<std::function<void(LoopPassManager &, OptimizationLevel)>,
> 2>
> + LateLoopOptimizationsEPCallbacks;
> + SmallVector<std::function<void(LoopPassManager &, OptimizationLevel)>,
> 2>
> + LoopOptimizerEndEPCallbacks;
> + SmallVector<std::function<void(FunctionPassManager &,
> OptimizationLevel)>, 2>
> + ScalarOptimizerLateEPCallbacks;
> + SmallVector<std::function<void(CGSCCPassManager &,
> OptimizationLevel)>, 2>
> + CGSCCOptimizerLateEPCallbacks;
> + SmallVector<std::function<void(FunctionPassManager &,
> OptimizationLevel)>, 2>
> + VectorizerStartEPCallbacks;
> + // Module callbacks
> + SmallVector<std::function<void(ModuleAnalysisManager &)>, 2>
> + ModuleAnalysisRegistrationCallbacks;
> + SmallVector<std::function<bool(StringRef, ModulePassManager &,
> + ArrayRef<PipelineElement>)>,
> + 2>
> + ModulePipelineParsingCallbacks;
> + SmallVector<std::function<bool(ModulePassManager &,
> ArrayRef<PipelineElement>,
> + bool VerifyEachPass, bool DebugLogging)>,
> + 2>
> + TopLevelPipelineParsingCallbacks;
> + // CGSCC callbacks
> + SmallVector<std::function<void(CGSCCAnalysisManager &)>, 2>
> + CGSCCAnalysisRegistrationCallbacks;
> + SmallVector<std::function<bool(StringRef, CGSCCPassManager &,
> + ArrayRef<PipelineElement>)>,
> + 2>
> + CGSCCPipelineParsingCallbacks;
> + // Function callbacks
> + SmallVector<std::function<void(FunctionAnalysisManager &)>, 2>
> + FunctionAnalysisRegistrationCallbacks;
> + SmallVector<std::function<bool(StringRef, FunctionPassManager &,
> + ArrayRef<PipelineElement>)>,
> + 2>
> + FunctionPipelineParsingCallbacks;
> + // Loop callbacks
> + SmallVector<std::function<void(LoopAnalysisManager &)>, 2>
> + LoopAnalysisRegistrationCallbacks;
> + SmallVector<std::function<bool(StringRef, LoopPassManager &,
> + ArrayRef<PipelineElement>)>,
> + 2>
> + LoopPipelineParsingCallbacks;
> + // AA callbacks
> + SmallVector<std::function<bool(StringRef Name, AAManager &AA)>, 2>
> + AAParsingCallbacks;
> };
> +
> +/// This utility template takes care of adding require<> and invalidate<>
> +/// passes for an analysis to a given \c PassManager. It is intended to
> be used
> +/// during parsing of a pass pipeline when parsing a single PipelineName.
> +/// When registering a new function analysis FancyAnalysis with the pass
> +/// pipeline name "fancy-analysis", a matching ParsePipelineCallback
> could look
> +/// like this:
> +///
> +/// static bool parseFunctionPipeline(StringRef Name,
> FunctionPassManager &FPM,
> +/// ArrayRef<PipelineElement> P) {
> +/// if (parseAnalysisUtilityPasses<FancyAnalysis>("fancy-analysis",
> Name,
> +/// FPM))
> +/// return true;
> +/// return false;
> +/// }
> +template <typename AnalysisT, typename IRUnitT, typename AnalysisManagerT,
> + typename... ExtraArgTs>
> +bool parseAnalysisUtilityPasses(
> + StringRef AnalysisName, StringRef PipelineName,
> + PassManager<IRUnitT, AnalysisManagerT, ExtraArgTs...> &PM) {
> + if (!PipelineName.endswith(">"))
> + return false;
> + // See if this is an invalidate<> pass name
> + if (PipelineName.startswith("invalidate<")) {
> + PipelineName = PipelineName.substr(11, PipelineName.size() - 12);
> + if (PipelineName != AnalysisName)
> + return false;
> + PM.addPass(InvalidateAnalysisPass<AnalysisT>());
> + return true;
> + }
> +
> + // See if this is a require<> pass name
> + if (PipelineName.startswith("require<")) {
> + PipelineName = PipelineName.substr(8, PipelineName.size() - 9);
> + if (PipelineName != AnalysisName)
> + return false;
> + PM.addPass(RequireAnalysisPass<AnalysisT, IRUnitT, AnalysisManagerT,
> + ExtraArgTs...>());
> + return true;
> + }
> +
> + return false;
> +}
> }
>
> #endif
>
> Modified: llvm/trunk/lib/Passes/PassBuilder.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/Pa
> ssBuilder.cpp?rev=307532&r1=307531&r2=307532&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/Passes/PassBuilder.cpp (original)
> +++ llvm/trunk/lib/Passes/PassBuilder.cpp Mon Jul 10 03:57:55 2017
> @@ -281,28 +281,46 @@ AnalysisKey NoOpLoopAnalysis::Key;
>
> } // End anonymous namespace.
>
> +void PassBuilder::invokePeepholeEPCallbacks(
> + FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
> + for (auto &C : PeepholeEPCallbacks)
> + C(FPM, Level);
> +}
> +
> void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) {
> #define MODULE_ANALYSIS(NAME, CREATE_PASS)
> \
> MAM.registerPass([&] { return CREATE_PASS; });
> #include "PassRegistry.def"
> +
> + for (auto &C : ModuleAnalysisRegistrationCallbacks)
> + C(MAM);
> }
>
> void PassBuilder::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) {
> #define CGSCC_ANALYSIS(NAME, CREATE_PASS)
> \
> CGAM.registerPass([&] { return CREATE_PASS; });
> #include "PassRegistry.def"
> +
> + for (auto &C : CGSCCAnalysisRegistrationCallbacks)
> + C(CGAM);
> }
>
> void PassBuilder::registerFunctionAnalyses(FunctionAnalysisManager &FAM)
> {
> #define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
> \
> FAM.registerPass([&] { return CREATE_PASS; });
> #include "PassRegistry.def"
> +
> + for (auto &C : FunctionAnalysisRegistrationCallbacks)
> + C(FAM);
> }
>
> void PassBuilder::registerLoopAnalyses(LoopAnalysisManager &LAM) {
> #define LOOP_ANALYSIS(NAME, CREATE_PASS)
> \
> LAM.registerPass([&] { return CREATE_PASS; });
> #include "PassRegistry.def"
> +
> + for (auto &C : LoopAnalysisRegistrationCallbacks)
> + C(LAM);
> }
>
> FunctionPassManager
> @@ -341,6 +359,8 @@ PassBuilder::buildFunctionSimplification
> if (!isOptimizingForSize(Level))
> FPM.addPass(LibCallsShrinkWrapPass());
>
> + invokePeepholeEPCallbacks(FPM, Level);
> +
> FPM.addPass(TailCallElimPass());
> FPM.addPass(SimplifyCFGPass());
>
> @@ -364,6 +384,10 @@ PassBuilder::buildFunctionSimplification
> LPM1.addPass(SimpleLoopUnswitchPass());
> LPM2.addPass(IndVarSimplifyPass());
> LPM2.addPass(LoopIdiomRecognizePass());
> +
> + for (auto &C : LateLoopOptimizationsEPCallbacks)
> + C(LPM2, Level);
> +
> LPM2.addPass(LoopDeletionPass());
> // Do not enable unrolling in PrepareForThinLTO phase during sample PGO
> // because it changes IR to makes profile annotation in back compile
> @@ -371,6 +395,9 @@ PassBuilder::buildFunctionSimplification
> if (!PrepareForThinLTO || !PGOOpt || PGOOpt->SampleProfileFile.empty())
> LPM2.addPass(LoopUnrollPass::createFull(Level));
>
> + for (auto &C : LoopOptimizerEndEPCallbacks)
> + C(LPM2, Level);
> +
> // We provide the opt remark emitter pass for LICM to use. We only need
> to do
> // this once as it is immutable.
> FPM.addPass(RequireAnalysisPass<OptimizationRemarkEmitterAnalysis,
> Function>());
> @@ -405,6 +432,7 @@ PassBuilder::buildFunctionSimplification
> // Run instcombine after redundancy and dead bit elimination to exploit
> // opportunities opened up by them.
> FPM.addPass(InstCombinePass());
> + invokePeepholeEPCallbacks(FPM, Level);
>
> // Re-consider control flow based optimizations after redundancy
> elimination,
> // redo DCE, etc.
> @@ -413,19 +441,24 @@ PassBuilder::buildFunctionSimplification
> FPM.addPass(DSEPass());
> FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass()));
>
> + for (auto &C : ScalarOptimizerLateEPCallbacks)
> + C(FPM, Level);
> +
> // Finally, do an expensive DCE pass to catch all the dead code exposed
> by
> // the simplifications and basic cleanup after all the simplifications.
> FPM.addPass(ADCEPass());
> FPM.addPass(SimplifyCFGPass());
> FPM.addPass(InstCombinePass());
> + invokePeepholeEPCallbacks(FPM, Level);
>
> return FPM;
> }
>
> -static void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging,
> - PassBuilder::OptimizationLevel Level,
> - bool RunProfileGen, std::string
> ProfileGenFile,
> - std::string ProfileUseFile) {
> +void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM, bool
> DebugLogging,
> + PassBuilder::OptimizationLevel Level,
> + bool RunProfileGen,
> + std::string ProfileGenFile,
> + std::string ProfileUseFile) {
> // Generally running simplification passes and the inliner with an high
> // threshold results in smaller executables, but there may be cases
> where
> // the size grows, so let's be conservative here and skip this
> simplification
> @@ -450,9 +483,8 @@ static void addPGOInstrPasses(ModulePass
> FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies.
> FPM.addPass(SimplifyCFGPass()); // Merge & remove basic blocks.
> FPM.addPass(InstCombinePass()); // Combine silly sequences.
> + invokePeepholeEPCallbacks(FPM, Level);
>
> - // FIXME: Here the old pass manager inserts peephole extensions.
> - // Add them when they're supported.
> CGPipeline.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM)));
>
> MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::
> move(CGPipeline)));
> @@ -533,6 +565,8 @@ PassBuilder::buildModuleSimplificationPi
> // optimizations.
> FunctionPassManager GlobalCleanupPM(DebugLogging);
> GlobalCleanupPM.addPass(InstCombinePass());
> + invokePeepholeEPCallbacks(GlobalCleanupPM, Level);
> +
> GlobalCleanupPM.addPass(SimplifyCFGPass());
> MPM.addPass(createModuleToFunctionPassAdaptor(std::move(
> GlobalCleanupPM)));
>
> @@ -597,6 +631,9 @@ PassBuilder::buildModuleSimplificationPi
> buildFunctionSimplificationPipeline(Level, DebugLogging,
> PrepareForThinLTO)));
>
> + for (auto &C : CGSCCOptimizerLateEPCallbacks)
> + C(MainCGPipeline, Level);
> +
> // We wrap the CGSCC pipeline in a devirtualization repeater. This will
> try
> // to detect when we devirtualize indirect calls and iterate the SCC
> passes
> // in that case to try and catch knock-on inlining or function attrs
> @@ -655,6 +692,9 @@ PassBuilder::buildModuleOptimizationPipe
> // rather than on each loop in an inside-out manner, and so they are
> actually
> // function passes.
>
> + for (auto &C : VectorizerStartEPCallbacks)
> + C(OptimizePM, Level);
> +
> // First rotate loops that may have been un-rotated by prior passes.
> OptimizePM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass()));
>
> @@ -883,8 +923,11 @@ ModulePassManager PassBuilder::buildLTOD
> // simplification opportunities, and both can propagate functions
> through
> // function pointers. When this happens, we often have to resolve
> varargs
> // calls, etc, so let instcombine do this.
> - // FIXME: add peephole extensions here as the legacy PM does.
> - MPM.addPass(createModuleToFunctionPassAdaptor(InstCombinePass()));
> + FunctionPassManager PeepholeFPM(DebugLogging);
> + PeepholeFPM.addPass(InstCombinePass());
> + invokePeepholeEPCallbacks(PeepholeFPM, Level);
> +
> + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(PeepholeFPM)));
>
> // Note: historically, the PruneEH pass was run first to deduce
> nounwind and
> // generally clean up exception handling overhead. It isn't clear this
> is
> @@ -902,10 +945,10 @@ ModulePassManager PassBuilder::buildLTOD
> MPM.addPass(GlobalDCEPass());
>
> FunctionPassManager FPM(DebugLogging);
> -
> // The IPO Passes may leave cruft around. Clean up after them.
> - // FIXME: add peephole extensions here as the legacy PM does.
> FPM.addPass(InstCombinePass());
> + invokePeepholeEPCallbacks(FPM, Level);
> +
> FPM.addPass(JumpThreadingPass());
>
> // Break up allocas
> @@ -952,8 +995,11 @@ ModulePassManager PassBuilder::buildLTOD
> MainFPM.add(AlignmentFromAssumptionsPass());
> #endif
>
> - // FIXME: add peephole extensions to the PM here.
> + // FIXME: Conditionally run LoadCombine here, after it's ported
> + // (in case we still have this pass, given its questionable usefulness).
> +
> MainFPM.addPass(InstCombinePass());
> + invokePeepholeEPCallbacks(MainFPM, Level);
> MainFPM.addPass(JumpThreadingPass());
> MPM.addPass(createModuleToFunctionPassAdaptor(std::move(MainFPM)));
>
> @@ -1036,7 +1082,27 @@ static bool startsWithDefaultPipelineAli
> Name.startswith("lto");
> }
>
> -static bool isModulePassName(StringRef Name) {
> +/// Tests whether registered callbacks will accept a given pass name.
> +///
> +/// When parsing a pipeline text, the type of the outermost pipeline may
> be
> +/// omitted, in which case the type is automatically determined from the
> first
> +/// pass name in the text. This may be a name that is handled through one
> of the
> +/// callbacks. We check this through the oridinary parsing callbacks by
> setting
> +/// up a dummy PassManager in order to not force the client to also
> handle this
> +/// type of query.
> +template <typename PassManagerT, typename CallbacksT>
> +static bool callbacksAcceptPassName(StringRef Name, CallbacksT
> &Callbacks) {
> + if (!Callbacks.empty()) {
> + PassManagerT DummyPM;
> + for (auto &CB : Callbacks)
> + if (CB(Name, DummyPM, {}))
> + return true;
> + }
> + return false;
> +}
> +
> +template <typename CallbacksT>
> +static bool isModulePassName(StringRef Name, CallbacksT &Callbacks) {
> // Manually handle aliases for pre-configured pipeline fragments.
> if (startsWithDefaultPipelineAliasPrefix(Name))
> return DefaultAliasRegex.match(Name);
> @@ -1061,10 +1127,11 @@ static bool isModulePassName(StringRef N
> return true;
> #include "PassRegistry.def"
>
> - return false;
> + return callbacksAcceptPassName<ModulePassManager>(Name, Callbacks);
> }
>
> -static bool isCGSCCPassName(StringRef Name) {
> +template <typename CallbacksT>
> +static bool isCGSCCPassName(StringRef Name, CallbacksT &Callbacks) {
> // Explicitly handle pass manager names.
> if (Name == "cgscc")
> return true;
> @@ -1085,10 +1152,11 @@ static bool isCGSCCPassName(StringRef Na
> return true;
> #include "PassRegistry.def"
>
> - return false;
> + return callbacksAcceptPassName<CGSCCPassManager>(Name, Callbacks);
> }
>
> -static bool isFunctionPassName(StringRef Name) {
> +template <typename CallbacksT>
> +static bool isFunctionPassName(StringRef Name, CallbacksT &Callbacks) {
> // Explicitly handle pass manager names.
> if (Name == "function")
> return true;
> @@ -1107,10 +1175,11 @@ static bool isFunctionPassName(StringRef
> return true;
> #include "PassRegistry.def"
>
> - return false;
> + return callbacksAcceptPassName<FunctionPassManager>(Name, Callbacks);
> }
>
> -static bool isLoopPassName(StringRef Name) {
> +template <typename CallbacksT>
> +static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks) {
> // Explicitly handle pass manager names.
> if (Name == "loop")
> return true;
> @@ -1127,7 +1196,7 @@ static bool isLoopPassName(StringRef Nam
> return true;
> #include "PassRegistry.def"
>
> - return false;
> + return callbacksAcceptPassName<LoopPassManager>(Name, Callbacks);
> }
>
> Optional<std::vector<PassBuilder::PipelineElement>>
> @@ -1228,6 +1297,11 @@ bool PassBuilder::parseModulePass(Module
> MPM.addPass(createRepeatedPass(*Count, std::move(NestedMPM)));
> return true;
> }
> +
> + for (auto &C : ModulePipelineParsingCallbacks)
> + if (C(Name, MPM, InnerPipeline))
> + return true;
> +
> // Normal passes can't have pipelines.
> return false;
> }
> @@ -1240,12 +1314,12 @@ bool PassBuilder::parseModulePass(Module
> assert(Matches.size() == 3 && "Must capture two matched strings!");
>
> OptimizationLevel L = StringSwitch<OptimizationLevel>(Matches[2])
> - .Case("O0", O0)
> - .Case("O1", O1)
> - .Case("O2", O2)
> - .Case("O3", O3)
> - .Case("Os", Os)
> - .Case("Oz", Oz);
> + .Case("O0", O0)
> + .Case("O1", O1)
> + .Case("O2", O2)
> + .Case("O3", O3)
> + .Case("Os", Os)
> + .Case("Oz", Oz);
> if (L == O0)
> // At O0 we do nothing at all!
> return true;
> @@ -1285,6 +1359,9 @@ bool PassBuilder::parseModulePass(Module
> }
> #include "PassRegistry.def"
>
> + for (auto &C : ModulePipelineParsingCallbacks)
> + if (C(Name, MPM, InnerPipeline))
> + return true;
> return false;
> }
>
> @@ -1332,11 +1409,16 @@ bool PassBuilder::parseCGSCCPass(CGSCCPa
> *MaxRepetitions,
> DebugLogging));
> return true;
> }
> +
> + for (auto &C : CGSCCPipelineParsingCallbacks)
> + if (C(Name, CGPM, InnerPipeline))
> + return true;
> +
> // Normal passes can't have pipelines.
> return false;
> }
>
> - // Now expand the basic registered passes from the .inc file.
> +// Now expand the basic registered passes from the .inc file.
> #define CGSCC_PASS(NAME, CREATE_PASS)
> \
> if (Name == NAME) {
> \
> CGPM.addPass(CREATE_PASS);
> \
> @@ -1357,6 +1439,9 @@ bool PassBuilder::parseCGSCCPass(CGSCCPa
> }
> #include "PassRegistry.def"
>
> + for (auto &C : CGSCCPipelineParsingCallbacks)
> + if (C(Name, CGPM, InnerPipeline))
> + return true;
> return false;
> }
>
> @@ -1394,11 +1479,16 @@ bool PassBuilder::parseFunctionPass(Func
> FPM.addPass(createRepeatedPass(*Count, std::move(NestedFPM)));
> return true;
> }
> +
> + for (auto &C : FunctionPipelineParsingCallbacks)
> + if (C(Name, FPM, InnerPipeline))
> + return true;
> +
> // Normal passes can't have pipelines.
> return false;
> }
>
> - // Now expand the basic registered passes from the .inc file.
> +// Now expand the basic registered passes from the .inc file.
> #define FUNCTION_PASS(NAME, CREATE_PASS)
> \
> if (Name == NAME) {
> \
> FPM.addPass(CREATE_PASS);
> \
> @@ -1418,6 +1508,9 @@ bool PassBuilder::parseFunctionPass(Func
> }
> #include "PassRegistry.def"
>
> + for (auto &C : FunctionPipelineParsingCallbacks)
> + if (C(Name, FPM, InnerPipeline))
> + return true;
> return false;
> }
>
> @@ -1445,11 +1538,16 @@ bool PassBuilder::parseLoopPass(LoopPass
> LPM.addPass(createRepeatedPass(*Count, std::move(NestedLPM)));
> return true;
> }
> +
> + for (auto &C : LoopPipelineParsingCallbacks)
> + if (C(Name, LPM, InnerPipeline))
> + return true;
> +
> // Normal passes can't have pipelines.
> return false;
> }
>
> - // Now expand the basic registered passes from the .inc file.
> +// Now expand the basic registered passes from the .inc file.
> #define LOOP_PASS(NAME, CREATE_PASS)
> \
> if (Name == NAME) {
> \
> LPM.addPass(CREATE_PASS);
> \
> @@ -1470,6 +1568,9 @@ bool PassBuilder::parseLoopPass(LoopPass
> }
> #include "PassRegistry.def"
>
> + for (auto &C : LoopPipelineParsingCallbacks)
> + if (C(Name, LPM, InnerPipeline))
> + return true;
> return false;
> }
>
> @@ -1488,6 +1589,9 @@ bool PassBuilder::parseAAPassName(AAMana
> }
> #include "PassRegistry.def"
>
> + for (auto &C : AAParsingCallbacks)
> + if (C(Name, AA))
> + return true;
> return false;
> }
>
> @@ -1554,7 +1658,7 @@ bool PassBuilder::parseModulePassPipelin
> return true;
> }
>
> -// Primary pass pipeline description parsing routine.
> +// Primary pass pipeline description parsing routine for a \c
> ModulePassManager
> // FIXME: Should this routine accept a TargetMachine or require the
> caller to
> // pre-populate the analysis managers with target-specific stuff?
> bool PassBuilder::parsePassPipeline(ModulePassManager &MPM,
> @@ -1568,21 +1672,70 @@ bool PassBuilder::parsePassPipeline(Modu
> // automatically.
> StringRef FirstName = Pipeline->front().Name;
>
> - if (!isModulePassName(FirstName)) {
> - if (isCGSCCPassName(FirstName))
> + if (!isModulePassName(FirstName, ModulePipelineParsingCallbacks)) {
> + if (isCGSCCPassName(FirstName, CGSCCPipelineParsingCallbacks)) {
> Pipeline = {{"cgscc", std::move(*Pipeline)}};
> - else if (isFunctionPassName(FirstName))
> + } else if (isFunctionPassName(FirstName,
> + FunctionPipelineParsingCallbacks)) {
> Pipeline = {{"function", std::move(*Pipeline)}};
> - else if (isLoopPassName(FirstName))
> + } else if (isLoopPassName(FirstName, LoopPipelineParsingCallbacks)) {
> Pipeline = {{"function", {{"loop", std::move(*Pipeline)}}}};
> - else
> + } else {
> + for (auto &C : TopLevelPipelineParsingCallbacks)
> + if (C(MPM, *Pipeline, VerifyEachPass, DebugLogging))
> + return true;
> +
> // Unknown pass name!
> return false;
> + }
> }
>
> return parseModulePassPipeline(MPM, *Pipeline, VerifyEachPass,
> DebugLogging);
> }
>
> +// Primary pass pipeline description parsing routine for a \c
> CGSCCPassManager
> +bool PassBuilder::parsePassPipeline(CGSCCPassManager &CGPM,
> + StringRef PipelineText, bool
> VerifyEachPass,
> + bool DebugLogging) {
> + auto Pipeline = parsePipelineText(PipelineText);
> + if (!Pipeline || Pipeline->empty())
> + return false;
> +
> + StringRef FirstName = Pipeline->front().Name;
> + if (!isCGSCCPassName(FirstName, CGSCCPipelineParsingCallbacks))
> + return false;
> +
> + return parseCGSCCPassPipeline(CGPM, *Pipeline, VerifyEachPass,
> DebugLogging);
> +}
> +
> +// Primary pass pipeline description parsing routine for a \c
> +// FunctionPassManager
> +bool PassBuilder::parsePassPipeline(FunctionPassManager &FPM,
> + StringRef PipelineText, bool
> VerifyEachPass,
> + bool DebugLogging) {
> + auto Pipeline = parsePipelineText(PipelineText);
> + if (!Pipeline || Pipeline->empty())
> + return false;
> +
> + StringRef FirstName = Pipeline->front().Name;
> + if (!isFunctionPassName(FirstName, FunctionPipelineParsingCallbacks))
> + return false;
> +
> + return parseFunctionPassPipeline(FPM, *Pipeline, VerifyEachPass,
> + DebugLogging);
> +}
> +
> +// Primary pass pipeline description parsing routine for a \c
> LoopPassManager
> +bool PassBuilder::parsePassPipeline(LoopPassManager &CGPM,
> + StringRef PipelineText, bool
> VerifyEachPass,
> + bool DebugLogging) {
> + auto Pipeline = parsePipelineText(PipelineText);
> + if (!Pipeline || Pipeline->empty())
> + return false;
> +
> + return parseLoopPassPipeline(CGPM, *Pipeline, VerifyEachPass,
> DebugLogging);
> +}
> +
> bool PassBuilder::parseAAPipeline(AAManager &AA, StringRef PipelineText)
> {
> // If the pipeline just consists of the word 'default' just replace the
> AA
> // manager with our default one.
>
> Modified: llvm/trunk/test/Other/new-pm-defaults.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/ne
> w-pm-defaults.ll?rev=307532&r1=307531&r2=307532&view=diff
> ============================================================
> ==================
> --- llvm/trunk/test/Other/new-pm-defaults.ll (original)
> +++ llvm/trunk/test/Other/new-pm-defaults.ll Mon Jul 10 03:57:55 2017
> @@ -26,6 +26,37 @@
> ; RUN: -passes='lto-pre-link<O2>' -S %s 2>&1 \
> ; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O2
>
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes-ep-peephole='no-op-function' \
> +; RUN: -passes='default<O3>' -S %s 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \
> +; RUN: --check-prefix=CHECK-EP-PEEPHOLE
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes-ep-late-loop-optimizations='no-op-loop' \
> +; RUN: -passes='default<O3>' -S %s 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \
> +; RUN: --check-prefix=CHECK-EP-LOOP-LATE
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes-ep-loop-optimizer-end='no-op-loop' \
> +; RUN: -passes='default<O3>' -S %s 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \
> +; RUN: --check-prefix=CHECK-EP-LOOP-END
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes-ep-scalar-optimizer-late='no-op-function' \
> +; RUN: -passes='default<O3>' -S %s 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \
> +; RUN: --check-prefix=CHECK-EP-SCALAR-LATE
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes-ep-cgscc-optimizer-late='no-op-cgscc' \
> +; RUN: -passes='default<O3>' -S %s 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \
> +; RUN: --check-prefix=CHECK-EP-CGSCC-LATE
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes-ep-vectorizer-start='no-op-function' \
> +; RUN: -passes='default<O3>' -S %s 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O3 \
> +; RUN: --check-prefix=CHECK-EP-VECTORIZER-START
> +
> ; CHECK-O: Starting llvm::Module pass manager run.
> ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module{{.*}}>
> ; CHECK-O-NEXT: Starting llvm::Module pass manager run.
> @@ -53,6 +84,7 @@
> ; CHECK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{
> .*}}PassManager{{.*}}>
> ; CHECK-O-NEXT: Starting llvm::Function pass manager run.
> ; CHECK-O-NEXT: Running pass: InstCombinePass
> +; CHECK-EP-PEEPHOLE-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O-NEXT: Running pass: SimplifyCFGPass
> ; CHECK-O-NEXT: Finished llvm::Function pass manager run.
> ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA
> @@ -84,6 +116,7 @@
> ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass
> ; CHECK-O2-NEXT: Running pass: LibCallsShrinkWrapPass
> ; CHECK-O3-NEXT: Running pass: LibCallsShrinkWrapPass
> +; CHECK-EP-PEEPHOLE-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O-NEXT: Running pass: TailCallElimPass
> ; CHECK-O-NEXT: Running pass: SimplifyCFGPass
> ; CHECK-O-NEXT: Running pass: ReassociatePass
> @@ -105,8 +138,10 @@
> ; CHECK-O-NEXT: Starting Loop pass manager run.
> ; CHECK-O-NEXT: Running pass: IndVarSimplifyPass
> ; CHECK-O-NEXT: Running pass: LoopIdiomRecognizePass
> +; CHECK-EP-LOOP-LATE-NEXT: Running pass: NoOpLoopPass
> ; CHECK-O-NEXT: Running pass: LoopDeletionPass
> ; CHECK-O-NEXT: Running pass: LoopUnrollPass
> +; CHECK-EP-LOOP-END-NEXT: Running pass: NoOpLoopPass
> ; CHECK-O-NEXT: Finished Loop pass manager run.
> ; CHECK-Os-NEXT: Running pass: MergedLoadStoreMotionPass
> ; CHECK-Os-NEXT: Running pass: GVN
> @@ -126,15 +161,19 @@
> ; CHECK-O-NEXT: Running pass: BDCEPass
> ; CHECK-O-NEXT: Running analysis: DemandedBitsAnalysis
> ; CHECK-O-NEXT: Running pass: InstCombinePass
> +; CHECK-EP-PEEPHOLE-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O-NEXT: Running pass: JumpThreadingPass
> ; CHECK-O-NEXT: Running pass: CorrelatedValuePropagationPass
> ; CHECK-O-NEXT: Running pass: DSEPass
> ; CHECK-O-NEXT: Running pass: FunctionToLoopPassAdaptor<{{.*
> }}LICMPass{{.*}}>
> +; CHECK-EP-SCALAR-LATE-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O-NEXT: Running pass: ADCEPass
> ; CHECK-O-NEXT: Running analysis: PostDominatorTreeAnalysis
> ; CHECK-O-NEXT: Running pass: SimplifyCFGPass
> ; CHECK-O-NEXT: Running pass: InstCombinePass
> +; CHECK-EP-PEEPHOLE-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O-NEXT: Finished llvm::Function pass manager run.
> +; CHECK-EP-CGSCC-LATE-NEXT: Running pass: NoOpCGSCCPass
> ; CHECK-O-NEXT: Finished CGSCC pass manager run.
> ; CHECK-O-NEXT: Finished llvm::Module pass manager run.
> ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module{{.*}}>
> @@ -146,6 +185,7 @@
> ; CHECK-O-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{
> .*}}PassManager{{.*}}>
> ; CHECK-O-NEXT: Starting llvm::Function pass manager run.
> ; CHECK-O-NEXT: Running pass: Float2IntPass
> +; CHECK-EP-VECTORIZER-START-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O-NEXT: Running pass: FunctionToLoopPassAdaptor<{{.*
> }}LoopRotatePass
> ; CHECK-O-NEXT: Running pass: LoopDistributePass
> ; CHECK-O-NEXT: Running pass: LoopVectorizePass
>
> Modified: llvm/trunk/test/Other/new-pm-lto-defaults.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/ne
> w-pm-lto-defaults.ll?rev=307532&r1=307531&r2=307532&view=diff
> ============================================================
> ==================
> --- llvm/trunk/test/Other/new-pm-lto-defaults.ll (original)
> +++ llvm/trunk/test/Other/new-pm-lto-defaults.ll Mon Jul 10 03:57:55 2017
> @@ -17,6 +17,10 @@
> ; RUN: opt -disable-verify -debug-pass-manager \
> ; RUN: -passes='lto<Oz>' -S %s 2>&1 \
> ; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O2
> +; RUN: opt -disable-verify -debug-pass-manager \
> +; RUN: -passes='lto<O3>' -S %s -passes-ep-peephole='no-op-function'
> 2>&1 \
> +; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O2 \
> +; RUN: --check-prefix=CHECK-EP-Peephole
>
> ; CHECK-O: Starting llvm::Module pass manager run.
> ; CHECK-O-NEXT: Running pass: PassManager<{{.*}}Module
> @@ -45,13 +49,18 @@
> ; CHECK-O2-NEXT: Running analysis: AssumptionAnalysis
> ; CHECK-O2-NEXT: Running pass: ConstantMergePass
> ; CHECK-O2-NEXT: Running pass: DeadArgumentEliminationPass
> -; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{
> .*}}InstCombinePass>
> +; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{
> .*}}PassManager{{.*}}>
> +; CHECK-O2-NEXT: Starting llvm::Function pass manager run.
> +; CHECK-O2-NEXT: Running pass: InstCombinePass
> +; CHECK-EP-Peephole-NEXT: Running pass: NoOpFunctionPass
> +; CHECK-O2-NEXT: Finished llvm::Function pass manager run.
> ; CHECK-O2-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdap
> tor<{{.*}}InlinerPass>
> ; CHECK-O2-NEXT: Running pass: GlobalOptPass
> ; CHECK-O2-NEXT: Running pass: GlobalDCEPass
> ; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{
> .*}}PassManager{{.*}}>
> ; CHECK-O2-NEXT: Starting llvm::Function pass manager run.
> ; CHECK-O2-NEXT: Running pass: InstCombinePass
> +; CHECK-EP-Peephole-NEXT: Running pass: NoOpFunctionPass
> ; CHECK-O2-NEXT: Running pass: JumpThreadingPass
> ; CHECK-O2-NEXT: Running analysis: LazyValueAnalysis
> ; CHECK-O2-NEXT: Running pass: SROA on foo
>
> Modified: llvm/trunk/tools/opt/NewPMDriver.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/New
> PMDriver.cpp?rev=307532&r1=307531&r2=307532&view=diff
> ============================================================
> ==================
> --- llvm/trunk/tools/opt/NewPMDriver.cpp (original)
> +++ llvm/trunk/tools/opt/NewPMDriver.cpp Mon Jul 10 03:57:55 2017
> @@ -48,6 +48,83 @@ static cl::opt<std::string>
> "pipeline for handling managed aliasing queries"),
> cl::Hidden);
>
> +/// {{@ These options accept textual pipeline descriptions which will be
> +/// inserted into default pipelines at the respective extension points
> +static cl::opt<std::string> PeepholeEPPipeline(
> + "passes-ep-peephole",
> + cl::desc("A textual description of the function pass pipeline
> inserted at "
> + "the Peephole extension points into default pipelines"),
> + cl::Hidden);
> +static cl::opt<std::string> LateLoopOptimizationsEPPipeline(
> + "passes-ep-late-loop-optimizations",
> + cl::desc(
> + "A textual description of the loop pass pipeline inserted at "
> + "the LateLoopOptimizations extension point into default
> pipelines"),
> + cl::Hidden);
> +static cl::opt<std::string> LoopOptimizerEndEPPipeline(
> + "passes-ep-loop-optimizer-end",
> + cl::desc("A textual description of the loop pass pipeline inserted at
> "
> + "the LoopOptimizerEnd extension point into default
> pipelines"),
> + cl::Hidden);
> +static cl::opt<std::string> ScalarOptimizerLateEPPipeline(
> + "passes-ep-scalar-optimizer-late",
> + cl::desc("A textual description of the function pass pipeline
> inserted at "
> + "the ScalarOptimizerLate extension point into default
> pipelines"),
> + cl::Hidden);
> +static cl::opt<std::string> CGSCCOptimizerLateEPPipeline(
> + "passes-ep-cgscc-optimizer-late",
> + cl::desc("A textual description of the cgscc pass pipeline inserted
> at "
> + "the CGSCCOptimizerLate extension point into default
> pipelines"),
> + cl::Hidden);
> +static cl::opt<std::string> VectorizerStartEPPipeline(
> + "passes-ep-vectorizer-start",
> + cl::desc("A textual description of the function pass pipeline
> inserted at "
> + "the VectorizerStart extension point into default
> pipelines"),
> + cl::Hidden);
> +/// @}}
> +
> +/// If one of the EPPipeline command line options was given, register
> callbacks
> +/// for parsing and inserting the given pipeline
> +static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass,
> + bool DebugLogging) {
> + if (!PeepholeEPPipeline.empty())
> + PB.registerPeepholeEPCallback(
> + [&](FunctionPassManager &PM, PassBuilder::OptimizationLevel
> Level) {
> + return PB.parsePassPipeline(PM, PeepholeEPPipeline,
> VerifyEachPass,
> + DebugPM);
> + });
> + if (!LateLoopOptimizationsEPPipeline.empty())
> + PB.registerLateLoopOptimizationsEPCallback(
> + [&](LoopPassManager &PM, PassBuilder::OptimizationLevel Level) {
> + return PB.parsePassPipeline(PM, LateLoopOptimizationsEPPipelin
> e,
> + VerifyEachPass, DebugPM);
> + });
> + if (!LoopOptimizerEndEPPipeline.empty())
> + PB.registerLoopOptimizerEndEPCallback(
> + [&](LoopPassManager &PM, PassBuilder::OptimizationLevel Level) {
> + return PB.parsePassPipeline(PM, LoopOptimizerEndEPPipeline,
> + VerifyEachPass, DebugPM);
> + });
> + if (!ScalarOptimizerLateEPPipeline.empty())
> + PB.registerScalarOptimizerLateEPCallback(
> + [&](FunctionPassManager &PM, PassBuilder::OptimizationLevel
> Level) {
> + return PB.parsePassPipeline(PM, ScalarOptimizerLateEPPipeline,
> + VerifyEachPass, DebugPM);
> + });
> + if (!CGSCCOptimizerLateEPPipeline.empty())
> + PB.registerCGSCCOptimizerLateEPCallback(
> + [&](CGSCCPassManager &PM, PassBuilder::OptimizationLevel Level) {
> + return PB.parsePassPipeline(PM, CGSCCOptimizerLateEPPipeline,
> + VerifyEachPass, DebugPM);
> + });
> + if (!VectorizerStartEPPipeline.empty())
> + PB.registerVectorizerStartEPCallback(
> + [&](FunctionPassManager &PM, PassBuilder::OptimizationLevel
> Level) {
> + return PB.parsePassPipeline(PM, VectorizerStartEPPipeline,
> + VerifyEachPass, DebugPM);
> + });
> +}
> +
> bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
> tool_output_file *Out,
> tool_output_file *ThinLTOLinkOut,
> @@ -56,7 +133,9 @@ bool llvm::runPassPipeline(StringRef Arg
> bool ShouldPreserveAssemblyUseListOrder,
> bool ShouldPreserveBitcodeUseListOrder,
> bool EmitSummaryIndex, bool EmitModuleHash) {
> + bool VerifyEachPass = VK == VK_VerifyEachPass;
> PassBuilder PB(TM);
> + registerEPCallbacks(PB, VerifyEachPass, DebugPM);
>
> // Specially handle the alias analysis manager so that we can register
> // a custom pipeline of AA passes with it.
> @@ -85,8 +164,7 @@ bool llvm::runPassPipeline(StringRef Arg
> if (VK > VK_NoVerifier)
> MPM.addPass(VerifierPass());
>
> - if (!PB.parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass,
> - DebugPM)) {
> + if (!PB.parsePassPipeline(MPM, PassPipeline, VerifyEachPass, DebugPM)) {
> errs() << Arg0 << ": unable to parse pass pipeline description.\n";
> return false;
> }
>
> Modified: llvm/trunk/unittests/IR/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/
> CMakeLists.txt?rev=307532&r1=307531&r2=307532&view=diff
> ============================================================
> ==================
> --- llvm/trunk/unittests/IR/CMakeLists.txt (original)
> +++ llvm/trunk/unittests/IR/CMakeLists.txt Mon Jul 10 03:57:55 2017
> @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
> AsmParser
> Core
> Support
> + Passes
> )
>
> set(IRSources
> @@ -15,6 +16,7 @@ set(IRSources
> DebugTypeODRUniquingTest.cpp
> DominatorTreeTest.cpp
> FunctionTest.cpp
> + PassBuilderCallbacksTest.cpp
> IRBuilderTest.cpp
> InstructionsTest.cpp
> IntrinsicsTest.cpp
>
> Added: llvm/trunk/unittests/IR/PassBuilderCallbacksTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/
> PassBuilderCallbacksTest.cpp?rev=307532&view=auto
> ============================================================
> ==================
> --- llvm/trunk/unittests/IR/PassBuilderCallbacksTest.cpp (added)
> +++ llvm/trunk/unittests/IR/PassBuilderCallbacksTest.cpp Mon Jul 10
> 03:57:55 2017
> @@ -0,0 +1,520 @@
> +//===- unittests/IR/PassBuilderCallbacksTest.cpp - PB Callback Tests
> --===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include <gmock/gmock.h>
> +#include <gtest/gtest.h>
> +#include <llvm/Analysis/CGSCCPassManager.h>
> +#include <llvm/Analysis/LoopAnalysisManager.h>
> +#include <llvm/AsmParser/Parser.h>
> +#include <llvm/IR/LLVMContext.h>
> +#include <llvm/IR/PassManager.h>
> +#include <llvm/Passes/PassBuilder.h>
> +#include <llvm/Support/SourceMgr.h>
> +#include <llvm/Transforms/Scalar/LoopPassManager.h>
> +
> +using namespace llvm;
> +
> +namespace llvm {
> +/// Provide an ostream operator for StringRef.
> +///
> +/// For convenience we provide a custom matcher below for IRUnit's and
> analysis
> +/// result's getName functions, which most of the time returns a
> StringRef. The
> +/// matcher makes use of this operator.
> +static std::ostream &operator<<(std::ostream &O, StringRef S) {
> + return O << S.str();
> +}
> +}
> +
> +namespace {
> +using testing::DoDefault;
> +using testing::Return;
> +using testing::Expectation;
> +using testing::Invoke;
> +using testing::WithArgs;
> +using testing::_;
> +
> +/// \brief A CRTP base for analysis mock handles
> +///
> +/// This class reconciles mocking with the value semantics implementation
> of the
> +/// AnalysisManager. Analysis mock handles should derive from this class
> and
> +/// call \c setDefault() in their constroctur for wiring up the defaults
> defined
> +/// by this base with their mock run() and invalidate() implementations.
> +template <typename DerivedT, typename IRUnitT,
> + typename AnalysisManagerT = AnalysisManager<IRUnitT>,
> + typename... ExtraArgTs>
> +class MockAnalysisHandleBase {
> +public:
> + class Analysis : public AnalysisInfoMixin<Analysis> {
> + friend AnalysisInfoMixin<Analysis>;
> + friend MockAnalysisHandleBase;
> + static AnalysisKey Key;
> +
> + DerivedT *Handle;
> +
> + Analysis(DerivedT &Handle) : Handle(&Handle) {
> + static_assert(std::is_base_of<MockAnalysisHandleBase,
> DerivedT>::value,
> + "Must pass the derived type to this template!");
> + }
> +
> + public:
> + class Result {
> + friend MockAnalysisHandleBase;
> +
> + DerivedT *Handle;
> +
> + Result(DerivedT &Handle) : Handle(&Handle) {}
> +
> + public:
> + // Forward invalidation events to the mock handle.
> + bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
> + typename AnalysisManagerT::Invalidator &Inv) {
> + return Handle->invalidate(IR, PA, Inv);
> + }
> + };
> +
> + Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs...
> ExtraArgs) {
> + return Handle->run(IR, AM, ExtraArgs...);
> + }
> + };
> +
> + Analysis getAnalysis() { return Analysis(static_cast<DerivedT
> &>(*this)); }
> + typename Analysis::Result getResult() {
> + return typename Analysis::Result(static_cast<DerivedT &>(*this));
> + }
> +
> +protected:
> + // FIXME: MSVC seems unable to handle a lambda argument to Invoke from
> within
> + // the template, so we use a boring static function.
> + static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA,
> + typename AnalysisManagerT::Invalidator
> &Inv) {
> + auto PAC = PA.template getChecker<Analysis>();
> + return !PAC.preserved() &&
> + !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
> + }
> +
> + /// Derived classes should call this in their constructor to set up
> default
> + /// mock actions. (We can't do this in our constructor because this has
> to
> + /// run after the DerivedT is constructed.)
> + void setDefaults() {
> + ON_CALL(static_cast<DerivedT &>(*this),
> + run(_, _, testing::Matcher<ExtraArgTs>(_)...))
> + .WillByDefault(Return(this->getResult()));
> + ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))
> + .WillByDefault(Invoke(&invalidateCallback));
> + }
> +};
> +
> +/// \brief A CRTP base for pass mock handles
> +///
> +/// This class reconciles mocking with the value semantics implementation
> of the
> +/// PassManager. Pass mock handles should derive from this class and
> +/// call \c setDefault() in their constroctur for wiring up the defaults
> defined
> +/// by this base with their mock run() and invalidate() implementations.
> +template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT,
> + typename... ExtraArgTs>
> +AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT,
> + ExtraArgTs...>::Analysis::Key;
> +
> +template <typename DerivedT, typename IRUnitT,
> + typename AnalysisManagerT = AnalysisManager<IRUnitT>,
> + typename... ExtraArgTs>
> +class MockPassHandleBase {
> +public:
> + class Pass : public PassInfoMixin<Pass> {
> + friend MockPassHandleBase;
> +
> + DerivedT *Handle;
> +
> + Pass(DerivedT &Handle) : Handle(&Handle) {
> + static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
> + "Must pass the derived type to this template!");
> + }
> +
> + public:
> + PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
> + ExtraArgTs... ExtraArgs) {
> + return Handle->run(IR, AM, ExtraArgs...);
> + }
> + };
> +
> + Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
> +
> +protected:
> + /// Derived classes should call this in their constructor to set up
> default
> + /// mock actions. (We can't do this in our constructor because this has
> to
> + /// run after the DerivedT is constructed.)
> + void setDefaults() {
> + ON_CALL(static_cast<DerivedT &>(*this),
> + run(_, _, testing::Matcher<ExtraArgTs>(_)...))
> + .WillByDefault(Return(PreservedAnalyses::all()));
> + }
> +};
> +
> +/// Mock handles for passes for the IRUnits Module, CGSCC, Function, Loop.
> +/// These handles define the appropriate run() mock interface for the
> respective
> +/// IRUnit type.
> +template <typename IRUnitT> struct MockPassHandle;
> +template <>
> +struct MockPassHandle<Loop>
> + : MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,
> + LoopStandardAnalysisResults &, LPMUpdater &> {
> + MOCK_METHOD4(run,
> + PreservedAnalyses(Loop &, LoopAnalysisManager &,
> + LoopStandardAnalysisResults &,
> LPMUpdater &));
> + MockPassHandle() { setDefaults(); }
> +};
> +
> +template <>
> +struct MockPassHandle<Function>
> + : MockPassHandleBase<MockPassHandle<Function>, Function> {
> + MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager
> &));
> +
> + MockPassHandle() { setDefaults(); }
> +};
> +
> +template <>
> +struct MockPassHandle<LazyCallGraph::SCC>
> + : MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>,
> LazyCallGraph::SCC,
> + CGSCCAnalysisManager, LazyCallGraph &,
> + CGSCCUpdateResult &> {
> + MOCK_METHOD4(run,
> + PreservedAnalyses(LazyCallGraph::SCC &,
> CGSCCAnalysisManager &,
> + LazyCallGraph &G, CGSCCUpdateResult
> &UR));
> +
> + MockPassHandle() { setDefaults(); }
> +};
> +
> +template <>
> +struct MockPassHandle<Module>
> + : MockPassHandleBase<MockPassHandle<Module>, Module> {
> + MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));
> +
> + MockPassHandle() { setDefaults(); }
> +};
> +
> +/// Mock handles for analyses for the IRUnits Module, CGSCC, Function,
> Loop.
> +/// These handles define the appropriate run() and invalidate() mock
> interfaces
> +/// for the respective IRUnit type.
> +template <typename IRUnitT> struct MockAnalysisHandle;
> +template <>
> +struct MockAnalysisHandle<Loop>
> + : MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,
> + LoopAnalysisManager,
> + LoopStandardAnalysisResults &> {
> +
> + MOCK_METHOD3_T(run, typename Analysis::Result(Loop &,
> LoopAnalysisManager &,
> +
> LoopStandardAnalysisResults &));
> +
> + MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,
> + LoopAnalysisManager::Invalidator &));
> +
> + MockAnalysisHandle<Loop>() { this->setDefaults(); }
> +};
> +
> +template <>
> +struct MockAnalysisHandle<Function>
> + : MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {
> + MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager
> &));
> +
> + MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,
> + FunctionAnalysisManager::Invalidator &));
> +
> + MockAnalysisHandle<Function>() { setDefaults(); }
> +};
> +
> +template <>
> +struct MockAnalysisHandle<LazyCallGraph::SCC>
> + : MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,
> + LazyCallGraph::SCC, CGSCCAnalysisManager,
> + LazyCallGraph &> {
> + MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,
> + CGSCCAnalysisManager &,
> LazyCallGraph &));
> +
> + MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const
> PreservedAnalyses &,
> + CGSCCAnalysisManager::Invalidator &));
> +
> + MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); }
> +};
> +
> +template <>
> +struct MockAnalysisHandle<Module>
> + : MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {
> + MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));
> +
> + MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,
> + ModuleAnalysisManager::Invalidator &));
> +
> + MockAnalysisHandle<Module>() { setDefaults(); }
> +};
> +
> +static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
> + SMDiagnostic Err;
> + return parseAssemblyString(IR, Err, C);
> +}
> +
> +template <typename PassManagerT> class PassBuilderCallbacksTest;
> +
> +/// This test fixture is shared between all the actual tests below and
> +/// takes care of setting up appropriate defaults.
> +///
> +/// The template specialization serves to extract the IRUnit and AM types
> from
> +/// the given PassManagerT.
> +template <typename TestIRUnitT, typename... ExtraPassArgTs,
> + typename... ExtraAnalysisArgTs>
> +class PassBuilderCallbacksTest<PassManager<
> + TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,
> + ExtraPassArgTs...>> : public testing::Test {
> +protected:
> + using IRUnitT = TestIRUnitT;
> + using AnalysisManagerT = AnalysisManager<TestIRUnitT,
> ExtraAnalysisArgTs...>;
> + using PassManagerT =
> + PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;
> + using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;
> +
> + LLVMContext Context;
> + std::unique_ptr<Module> M;
> +
> + PassBuilder PB;
> + ModulePassManager PM;
> + LoopAnalysisManager LAM;
> + FunctionAnalysisManager FAM;
> + CGSCCAnalysisManager CGAM;
> + ModuleAnalysisManager AM;
> +
> + MockPassHandle<IRUnitT> PassHandle;
> + MockAnalysisHandle<IRUnitT> AnalysisHandle;
> +
> + static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT
> &AM,
> + ExtraAnalysisArgTs &&...
> Args) {
> + (void)AM.template getResult<AnalysisT>(
> + U, std::forward<ExtraAnalysisArgTs>(Args)...);
> + return PreservedAnalyses::all();
> + }
> +
> + PassBuilderCallbacksTest()
> + : M(parseIR(Context,
> + "declare void @bar()\n"
> + "define void @foo(i32 %n) {\n"
> + "entry:\n"
> + " br label %loop\n"
> + "loop:\n"
> + " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"
> + " %iv.next = add i32 %iv, 1\n"
> + " tail call void @bar()\n"
> + " %cmp = icmp eq i32 %iv, %n\n"
> + " br i1 %cmp, label %exit, label %loop\n"
> + "exit:\n"
> + " ret void\n"
> + "}\n")),
> + PM(true), LAM(true), FAM(true), CGAM(true), AM(true) {
> +
> + /// Register a callback for analysis registration.
> + ///
> + /// The callback is a function taking a reference to an AnalyisManager
> + /// object. When called, the callee gets to register its own analyses
> with
> + /// this PassBuilder instance.
> + PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM)
> {
> + // Register our mock analysis
> + AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });
> + });
> +
> + /// Register a callback for pipeline parsing.
> + ///
> + /// During parsing of a textual pipeline, the PassBuilder will call
> these
> + /// callbacks for each encountered pass name that it does not know.
> This
> + /// includes both simple pass names as well as names of
> sub-pipelines. In
> + /// the latter case, the InnerPipeline is not empty.
> + PB.registerPipelineParsingCallback(
> + [this](StringRef Name, PassManagerT &PM,
> + ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
> + /// Handle parsing of the names of analysis utilities such as
> + /// require<test-analysis> and invalidate<test-analysis> for our
> + /// analysis mock handle
> + if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis",
> Name, PM))
> + return true;
> +
> + /// Parse the name of our pass mock handle
> + if (Name == "test-transform") {
> + PM.addPass(PassHandle.getPass());
> + return true;
> + }
> + return false;
> + });
> +
> + /// Register builtin analyses and cross-register the analysis proxies
> + PB.registerModuleAnalyses(AM);
> + PB.registerCGSCCAnalyses(CGAM);
> + PB.registerFunctionAnalyses(FAM);
> + PB.registerLoopAnalyses(LAM);
> + PB.crossRegisterProxies(LAM, FAM, CGAM, AM);
> + }
> +};
> +
> +/// 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<Funct
> ionPassManager>;
> +using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;
> +
> +/// Test parsing of the name of our mock pass for all IRUnits.
> +///
> +/// The pass should by default run our mock analysis and then preserve it.
> +TEST_F(ModuleCallbacksTest, Passes) {
> + EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
> + EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
> + .WillOnce(Invoke(getAnalysisResult));
> +
> + StringRef PipelineText = "test-transform";
> + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> + PM.run(*M, AM);
> +}
> +
> +TEST_F(FunctionCallbacksTest, Passes) {
> + EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
> + EXPECT_CALL(PassHandle, run(HasName("foo"), _))
> + .WillOnce(Invoke(getAnalysisResult));
> +
> + 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"), _, _, _))
> + .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
> +
> + 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)"), _, _, _))
> + .WillOnce(WithArgs<0, 1, 2>(Invoke(getAnalysisResult)));
> +
> + 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.
> +///
> +/// We first require<>, then invalidate<> it, expecting the analysis to
> be run
> +/// once and subsequently invalidated.
> +TEST_F(ModuleCallbacksTest, AnalysisUtilities) {
> + EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
> + EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
> +
> + StringRef PipelineText = "require<test-analysis>,invali
> date<test-analysis>";
> + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> + PM.run(*M, AM);
> +}
> +
> +TEST_F(CGSCCCallbacksTest, PassUtilities) {
> + EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
> + EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));
> +
> + StringRef PipelineText = "require<test-analysis>,invali
> date<test-analysis>";
> + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> + PM.run(*M, AM);
> +}
> +
> +TEST_F(FunctionCallbacksTest, AnalysisUtilities) {
> + EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
> + EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));
> +
> + StringRef PipelineText = "require<test-analysis>,invali
> date<test-analysis>";
> + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> + PM.run(*M, AM);
> +}
> +
> +TEST_F(LoopCallbacksTest, PassUtilities) {
> + EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
> + EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));
> +
> + StringRef PipelineText = "require<test-analysis>,invali
> date<test-analysis>";
> +
> + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> + PM.run(*M, AM);
> +}
> +
> +/// Test parsing of the top-level pipeline.
> +///
> +/// The ParseTopLevelPipeline callback takes over parsing of the entire
> pipeline
> +/// from PassBuilder if it encounters an unknown pipeline entry at the
> top level
> +/// (i.e., the first entry on the pipeline).
> +/// This test parses a pipeline named 'another-pipeline', whose only
> elements
> +/// may be the test-transform pass or the analysis utilities
> +TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {
> + PB.registerParseTopLevelPipelineCallback([this](
> + ModulePassManager &MPM, ArrayRef<PassBuilder::PipelineElement>
> Pipeline,
> + bool VerifyEachPass, bool DebugLogging) {
> + auto &FirstName = Pipeline.front().Name;
> + auto &InnerPipeline = Pipeline.front().InnerPipeline;
> + if (FirstName == "another-pipeline") {
> + for (auto &E : InnerPipeline) {
> + if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis",
> E.Name, PM))
> + continue;
> +
> + if (E.Name == "test-transform") {
> + PM.addPass(PassHandle.getPass());
> + continue;
> + }
> + return false;
> + }
> + }
> + return true;
> + });
> +
> + EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
> + EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
> + .WillOnce(Invoke(getAnalysisResult));
> + EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
> +
> + StringRef PipelineText =
> + "another-pipeline(test-transform,invalidate<test-analysis>)";
> + ASSERT_TRUE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> + PM.run(*M, AM);
> +
> + /// Test the negative case
> + PipelineText = "another-pipeline(instcombine)";
> + ASSERT_FALSE(PB.parsePassPipeline(PM, PipelineText, true))
> + << "Pipeline was: " << PipelineText;
> +}
> +} // end anonymous namespace
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170712/cc91a63c/attachment-0001.html>
More information about the llvm-commits
mailing list