[llvm] r307532 - [PM] Enable registration of out-of-tree passes with PassBuilder
Galina Kistanova via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 10 17:04:25 PDT 2017
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/
> PassBuilder.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(createModuleToFunctionPassAdap
> tor(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/
> new-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/
> new-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/
> NewPMDriver.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<
> FunctionPassManager>;
> +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>,
> invalidate<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>,
> invalidate<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>,
> invalidate<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>,
> invalidate<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/20170710/47dd0501/attachment-0001.html>
More information about the llvm-commits
mailing list