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