<div dir="auto"><div>Hi Galina,<div dir="auto"><br></div><div dir="auto">There is one additional thing I'm wondering about. I fixed this commit in r307534 first. The Darwin lld bot remained red because there was an another error in it. But I didn't get an email about that second error. Is that intentional or a limitation of Buildbot? It would be nice to get separate emails for different errors, because it's difficult to filter this out from all the build fail noise.</div><div dir="auto"><br></div><div dir="auto">Cheers,</div><div dir="auto">Philip</div><br><div class="gmail_extra"><br><div class="gmail_quote">On Jul 11, 2017 02:04, "Galina Kistanova" <<a href="mailto:gkistanova@gmail.com">gkistanova@gmail.com</a>> wrote:<br type="attribution"><blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><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" target="_blank">http://lab.llvm.org:8011/<wbr>builders/lld-x86_64-darwin13/<wbr>builds/10240</a><br><br>Please have a look?<br><br>Thanks<font color="#888888"><br><br>Galina<br></font></div><div class="elided-text"><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-pr<wbr>oject?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/D3346<wbr>4</a><br>
<br>
Added:<br>
llvm/trunk/unittests/IR/PassBu<wbr>ilderCallbacksTest.cpp<br>
Modified:<br>
llvm/trunk/include/llvm/Passes<wbr>/PassBuilder.h<br>
llvm/trunk/lib/Passes/PassBuil<wbr>der.cpp<br>
llvm/trunk/test/Other/new-pm-d<wbr>efaults.ll<br>
llvm/trunk/test/Other/new-pm-l<wbr>to-defaults.ll<br>
llvm/trunk/tools/opt/NewPMDriv<wbr>er.cpp<br>
llvm/trunk/unittests/IR/CMakeL<wbr>ists.txt<br>
<br>
Modified: llvm/trunk/include/llvm/Passes<wbr>/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-pr<wbr>oject/llvm/trunk/include/llvm/<wbr>Passes/PassBuilder.h?rev=30753<wbr>2&r1=307531&r2=307532&view=<wbr>diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/include/llvm/Passes<wbr>/PassBuilder.h (original)<br>
+++ llvm/trunk/include/llvm/Passes<wbr>/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,l<wbr>pass2,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(ModulePassMa<wbr>nager &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(CGSCCPassMan<wbr>ager &CGPM, StringRef PipelineText,<br>
+ bool VerifyEachPass = true, bool DebugLogging = false);<br>
+ bool parsePassPipeline(FunctionPass<wbr>Manager &FPM, StringRef PipelineText,<br>
+ bool VerifyEachPass = true, bool DebugLogging = false);<br>
+ bool parsePassPipeline(LoopPassMana<wbr>ger &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(FunctionPas<wbr>sManager &, 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(LoopPassMan<wbr>ager &, 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(LoopPassMan<wbr>ager &, OptimizationLevel)> &C) {<br>
+ LoopOptimizerEndEPCallbacks.pu<wbr>sh_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(FunctionPas<wbr>sManager &, 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(CGSCCPassMa<wbr>nager &, 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(FunctionPas<wbr>sManager &, OptimizationLevel)> &C) {<br>
+ VectorizerStartEPCallbacks.pus<wbr>h_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(C<wbr>);<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(CGSCCAnalys<wbr>isManager &)> &C) {<br>
+ CGSCCAnalysisRegistrationCallb<wbr>acks.push_back(C);<br>
+ }<br>
+ void registerAnalysisRegistrationCa<wbr>llback(<br>
+ const std::function<void(FunctionAna<wbr>lysisManager &)> &C) {<br>
+ FunctionAnalysisRegistrationCa<wbr>llbacks.push_back(C);<br>
+ }<br>
+ void registerAnalysisRegistrationCa<wbr>llback(<br>
+ const std::function<void(LoopAnalysi<wbr>sManager &)> &C) {<br>
+ LoopAnalysisRegistrationCallba<wbr>cks.push_back(C);<br>
+ }<br>
+ void registerAnalysisRegistrationCa<wbr>llback(<br>
+ const std::function<void(ModuleAnaly<wbr>sisManager &)> &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.p<wbr>ush_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(ModulePassM<wbr>anager &, ArrayRef<PipelineElement>,<br>
+ bool VerifyEachPass, bool DebugLogging)> &C) {<br>
+ TopLevelPipelineParsingCallbac<wbr>ks.push_back(C);<br>
+ }<br>
<br>
+private:<br>
static Optional<std::vector<PipelineE<wbr>lement>><br>
parsePipelineText(StringRef Text);<br>
<br>
@@ -392,7 +547,106 @@ private:<br>
bool parseModulePassPipeline(Module<wbr>PassManager &MPM,<br>
ArrayRef<PipelineElement> Pipeline,<br>
bool VerifyEachPass, bool DebugLogging);<br>
+<br>
+ void addPGOInstrPasses(ModulePassMa<wbr>nager &MPM, bool DebugLogging,<br>
+ OptimizationLevel Level, bool RunProfileGen,<br>
+ std::string ProfileGenFile,<br>
+ std::string ProfileUseFile);<br>
+<br>
+ void invokePeepholeEPCallbacks(Func<wbr>tionPassManager &, OptimizationLevel);<br>
+<br>
+ // Extension Point callbacks<br>
+ SmallVector<std::function<void<wbr>(FunctionPassManager &, OptimizationLevel)>, 2><br>
+ PeepholeEPCallbacks;<br>
+ SmallVector<std::function<void<wbr>(LoopPassManager &, OptimizationLevel)>, 2><br>
+ LateLoopOptimizationsEPCallbac<wbr>ks;<br>
+ SmallVector<std::function<void<wbr>(LoopPassManager &, OptimizationLevel)>, 2><br>
+ LoopOptimizerEndEPCallbacks;<br>
+ SmallVector<std::function<void<wbr>(FunctionPassManager &, OptimizationLevel)>, 2><br>
+ ScalarOptimizerLateEPCallbacks<wbr>;<br>
+ SmallVector<std::function<void<wbr>(CGSCCPassManager &, OptimizationLevel)>, 2><br>
+ CGSCCOptimizerLateEPCallbacks;<br>
+ SmallVector<std::function<void<wbr>(FunctionPassManager &, OptimizationLevel)>, 2><br>
+ VectorizerStartEPCallbacks;<br>
+ // Module callbacks<br>
+ SmallVector<std::function<void<wbr>(ModuleAnalysisManager &)>, 2><br>
+ ModuleAnalysisRegistrationCall<wbr>backs;<br>
+ SmallVector<std::function<bool<wbr>(StringRef, ModulePassManager &,<br>
+ ArrayRef<PipelineElement>)>,<br>
+ 2><br>
+ ModulePipelineParsingCallbacks<wbr>;<br>
+ SmallVector<std::function<bool<wbr>(ModulePassManager &, ArrayRef<PipelineElement>,<br>
+ bool VerifyEachPass, bool DebugLogging)>,<br>
+ 2><br>
+ TopLevelPipelineParsingCallbac<wbr>ks;<br>
+ // CGSCC callbacks<br>
+ SmallVector<std::function<void<wbr>(CGSCCAnalysisManager &)>, 2><br>
+ CGSCCAnalysisRegistrationCallb<wbr>acks;<br>
+ SmallVector<std::function<bool<wbr>(StringRef, CGSCCPassManager &,<br>
+ ArrayRef<PipelineElement>)>,<br>
+ 2><br>
+ CGSCCPipelineParsingCallbacks;<br>
+ // Function callbacks<br>
+ SmallVector<std::function<void<wbr>(FunctionAnalysisManager &)>, 2><br>
+ FunctionAnalysisRegistrationCa<wbr>llbacks;<br>
+ SmallVector<std::function<bool<wbr>(StringRef, FunctionPassManager &,<br>
+ ArrayRef<PipelineElement>)>,<br>
+ 2><br>
+ FunctionPipelineParsingCallbac<wbr>ks;<br>
+ // Loop callbacks<br>
+ SmallVector<std::function<void<wbr>(LoopAnalysisManager &)>, 2><br>
+ LoopAnalysisRegistrationCallba<wbr>cks;<br>
+ SmallVector<std::function<bool<wbr>(StringRef, LoopPassManager &,<br>
+ ArrayRef<PipelineElement>)>,<br>
+ 2><br>
+ LoopPipelineParsingCallbacks;<br>
+ // AA callbacks<br>
+ SmallVector<std::function<bool<wbr>(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(StringRe<wbr>f Name, FunctionPassManager &FPM,<br>
+/// ArrayRef<PipelineElement> P) {<br>
+/// if (parseAnalysisUtilityPasses<Fa<wbr>ncyAnalysis>("fancy-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("inva<wbr>lidate<")) {<br>
+ PipelineName = PipelineName.substr(11, PipelineName.size() - 12);<br>
+ if (PipelineName != AnalysisName)<br>
+ return false;<br>
+ PM.addPass(InvalidateAnalysisP<wbr>ass<AnalysisT>());<br>
+ return true;<br>
+ }<br>
+<br>
+ // See if this is a require<> pass name<br>
+ if (PipelineName.startswith("requ<wbr>ire<")) {<br>
+ PipelineName = PipelineName.substr(8, PipelineName.size() - 9);<br>
+ if (PipelineName != AnalysisName)<br>
+ return false;<br>
+ PM.addPass(RequireAnalysisPass<wbr><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/PassBuil<wbr>der.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-pr<wbr>oject/llvm/trunk/lib/Passes/Pa<wbr>ssBuilder.cpp?rev=307532&r1=30<wbr>7531&r2=307532&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/lib/Passes/PassBuil<wbr>der.cpp (original)<br>
+++ llvm/trunk/lib/Passes/PassBuil<wbr>der.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::invokePeepholeEPC<wbr>allbacks(<br>
+ FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {<br>
+ for (auto &C : PeepholeEPCallbacks)<br>
+ C(FPM, Level);<br>
+}<br>
+<br>
void PassBuilder::registerModuleAna<wbr>lyses(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::registerCGSCCAnal<wbr>yses(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::registerFunctionA<wbr>nalyses(FunctionAnalysisManage<wbr>r &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::registerLoopAnaly<wbr>ses(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::buildFunctionSimp<wbr>lification<br>
if (!isOptimizingForSize(Level))<br>
FPM.addPass(LibCallsShrinkWra<wbr>pPass());<br>
<br>
+ invokePeepholeEPCallbacks(FPM, Level);<br>
+<br>
FPM.addPass(TailCallElimPass(<wbr>));<br>
FPM.addPass(SimplifyCFGPass()<wbr>);<br>
<br>
@@ -364,6 +384,10 @@ PassBuilder::buildFunctionSimp<wbr>lification<br>
LPM1.addPass(SimpleLoopUnswit<wbr>chPass());<br>
LPM2.addPass(IndVarSimplifyPa<wbr>ss());<br>
LPM2.addPass(LoopIdiomRecogni<wbr>zePass());<br>
+<br>
+ for (auto &C : LateLoopOptimizationsEPCallbac<wbr>ks)<br>
+ C(LPM2, Level);<br>
+<br>
LPM2.addPass(<wbr>LoopDeletionPass());<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::buildFunctionSimp<wbr>lification<br>
if (!PrepareForThinLTO || !PGOOpt || PGOOpt->SampleProfileFile.empt<wbr>y())<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(RequireAnalysisPa<wbr>ss<OptimizationRemarkEmitterAn<wbr>alysis, Function>());<br>
@@ -405,6 +432,7 @@ PassBuilder::buildFunctionSimp<wbr>lification<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::buildFunctionSimp<wbr>lification<br>
FPM.addPass(DSEPass());<br>
FPM.addPass(createFunctionToL<wbr>oopPassAdaptor(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(ModulePassMa<wbr>nager &MPM, bool DebugLogging,<br>
- PassBuilder::OptimizationLevel Level,<br>
- bool RunProfileGen, std::string ProfileGenFile,<br>
- std::string ProfileUseFile) {<br>
+void PassBuilder::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(createCGSC<wbr>CToFunctionPassAdaptor(std::<wbr>move(FPM)));<br>
<br>
MPM.addPass(createModuleToPos<wbr>tOrderCGSCCPassAdaptor(std::<wbr>move(CGPipeline)));<br>
@@ -533,6 +565,8 @@ PassBuilder::buildModuleSimpli<wbr>ficationPi<br>
// optimizations.<br>
FunctionPassManager GlobalCleanupPM(DebugLogging);<br>
GlobalCleanupPM.addPass(InstC<wbr>ombinePass());<br>
+ invokePeepholeEPCallbacks(Glob<wbr>alCleanupPM, Level);<br>
+<br>
GlobalCleanupPM.addPass(Simpl<wbr>ifyCFGPass());<br>
MPM.addPass(createModuleToFun<wbr>ctionPassAdaptor(std::move(<wbr>GlobalCleanupPM)));<br>
<br>
@@ -597,6 +631,9 @@ PassBuilder::buildModuleSimpli<wbr>ficationPi<br>
<wbr>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::buildModuleOptimi<wbr>zationPipe<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(createFunc<wbr>tionToLoopPassAdaptor(<wbr>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(createModuleToFunc<wbr>tionPassAdaptor(<wbr>InstCombinePass()));<br>
+ FunctionPassManager PeepholeFPM(DebugLogging);<br>
+ PeepholeFPM.addPass(InstCombin<wbr>ePass());<br>
+ invokePeepholeEPCallbacks(Peep<wbr>holeFPM, Level);<br>
+<br>
+ MPM.addPass(createModuleToFunc<wbr>tionPassAdaptor(std::move(<wbr>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(<wbr>JumpThreadingPass());<br>
<br>
// Break up allocas<br>
@@ -952,8 +995,11 @@ ModulePassManager PassBuilder::buildLTOD<br>
MainFPM.add(AlignmentFromAssu<wbr>mptionsPass());<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(InstCombinePa<wbr>ss());<br>
+ invokePeepholeEPCallbacks(Main<wbr>FPM, Level);<br>
MainFPM.addPass(JumpThreading<wbr>Pass());<br>
MPM.addPass(createModuleToFun<wbr>ctionPassAdaptor(std::move(<wbr>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(String<wbr>Ref 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 (startsWithDefaultPipelineAlia<wbr>sPrefix(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<Module<wbr>PassManager>(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<CGSCCP<wbr>assManager>(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<Functi<wbr>onPassManager>(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<LoopPa<wbr>ssManager>(Name, Callbacks);<br>
}<br>
<br>
Optional<std::vector<PassBuil<wbr>der::PipelineElement>><br>
@@ -1228,6 +1297,11 @@ bool PassBuilder::parseModulePass(M<wbr>odule<br>
MPM.addPass(createRepeatedPas<wbr>s(*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(M<wbr>odule<br>
assert(Matches.size() == 3 && "Must capture two matched strings!");<br>
<br>
OptimizationLevel L = StringSwitch<OptimizationLevel<wbr>>(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(M<wbr>odule<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(CG<wbr>SCCPa<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(CG<wbr>SCCPa<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::parseFunctionPass<wbr>(Func<br>
FPM.addPass(createRepeatedPas<wbr>s(*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::parseFunctionPass<wbr>(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(Loo<wbr>pPass<br>
LPM.addPass(createRepeatedPas<wbr>s(*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(Loo<wbr>pPass<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(A<wbr>AMana<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::parseModulePassPi<wbr>pelin<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::parsePassPipeline<wbr>(ModulePassManager &MPM,<br>
@@ -1568,21 +1672,70 @@ bool PassBuilder::parsePassPipeline<wbr>(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::parsePassPipeline<wbr>(CGSCCPassManager &CGPM,<br>
+ StringRef PipelineText, bool VerifyEachPass,<br>
+ bool DebugLogging) {<br>
+ auto Pipeline = parsePipelineText(PipelineText<wbr>);<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::parsePassPipeline<wbr>(FunctionPassManager &FPM,<br>
+ StringRef PipelineText, bool VerifyEachPass,<br>
+ bool DebugLogging) {<br>
+ auto Pipeline = parsePipelineText(PipelineText<wbr>);<br>
+ if (!Pipeline || Pipeline->empty())<br>
+ return false;<br>
+<br>
+ StringRef FirstName = Pipeline->front().Name;<br>
+ if (!isFunctionPassName(FirstName<wbr>, 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::parsePassPipeline<wbr>(LoopPassManager &CGPM,<br>
+ StringRef PipelineText, bool VerifyEachPass,<br>
+ bool DebugLogging) {<br>
+ auto Pipeline = parsePipelineText(PipelineText<wbr>);<br>
+ if (!Pipeline || Pipeline->empty())<br>
+ return false;<br>
+<br>
+ return parseLoopPassPipeline(CGPM, *Pipeline, VerifyEachPass, DebugLogging);<br>
+}<br>
+<br>
bool PassBuilder::parseAAPipeline(A<wbr>AManager &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-d<wbr>efaults.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-pr<wbr>oject/llvm/trunk/test/Other/ne<wbr>w-pm-defaults.ll?rev=307532&r1<wbr>=307531&r2=307532&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/Other/new-pm-d<wbr>efaults.ll (original)<br>
+++ llvm/trunk/test/Other/new-pm-d<wbr>efaults.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-fu<wbr>nction' \<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-PEEPH<wbr>OLE<br>
+; RUN: opt -disable-verify -debug-pass-manager \<br>
+; RUN: -passes-ep-late-loop-optimiza<wbr>tions='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-<wbr>end='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-l<wbr>ate='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-SCALA<wbr>R-LATE<br>
+; RUN: opt -disable-verify -debug-pass-manager \<br>
+; RUN: -passes-ep-cgscc-optimizer-la<wbr>te='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-<wbr>CGSCC-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-VECTO<wbr>RIZER-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<{{.*}}Glob<wbr>alsAA<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-NEXT<wbr>: 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-l<wbr>to-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-pr<wbr>oject/llvm/trunk/test/Other/ne<wbr>w-pm-lto-defaults.ll?rev=30753<wbr>2&r1=307531&r2=307532&view=<wbr>diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/test/Other/new-pm-l<wbr>to-defaults.ll (original)<br>
+++ llvm/trunk/test/Other/new-pm-l<wbr>to-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-fun<wbr>ction' 2>&1 \<br>
+; RUN: | FileCheck %s --check-prefix=CHECK-O --check-prefix=CHECK-O2 \<br>
+; RUN: --check-prefix=CHECK-EP-Peeph<wbr>ole<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/NewPMDriv<wbr>er.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-pr<wbr>oject/llvm/trunk/tools/opt/New<wbr>PMDriver.cpp?rev=307532&r1=307<wbr>531&r2=307532&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/tools/opt/NewPMDriv<wbr>er.cpp (original)<br>
+++ llvm/trunk/tools/opt/NewPMDriv<wbr>er.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-optimizat<wbr>ions",<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-la<wbr>te",<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-lat<wbr>e",<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(PassBuilde<wbr>r &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 (!LateLoopOptimizationsEPPipel<wbr>ine.empty())<br>
+ PB.registerLateLoopOptimizatio<wbr>nsEPCallback(<br>
+ [&](LoopPassManager &PM, PassBuilder::OptimizationLevel Level) {<br>
+ return PB.parsePassPipeline(PM, LateLoopOptimizationsEPPipelin<wbr>e,<br>
+ VerifyEachPass, DebugPM);<br>
+ });<br>
+ if (!LoopOptimizerEndEPPipeline.e<wbr>mpty())<br>
+ PB.registerLoopOptimizerEndEPC<wbr>allback(<br>
+ [&](LoopPassManager &PM, PassBuilder::OptimizationLevel Level) {<br>
+ return PB.parsePassPipeline(PM, LoopOptimizerEndEPPipeline,<br>
+ VerifyEachPass, DebugPM);<br>
+ });<br>
+ if (!ScalarOptimizerLateEPPipelin<wbr>e.empty())<br>
+ PB.registerScalarOptimizerLate<wbr>EPCallback(<br>
+ [&](FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) {<br>
+ return PB.parsePassPipeline(PM, ScalarOptimizerLateEPPipeline,<br>
+ VerifyEachPass, DebugPM);<br>
+ });<br>
+ if (!CGSCCOptimizerLateEPPipeline<wbr>.empty())<br>
+ PB.registerCGSCCOptimizerLateE<wbr>PCallback(<br>
+ [&](CGSCCPassManager &PM, PassBuilder::OptimizationLevel Level) {<br>
+ return PB.parsePassPipeline(PM, CGSCCOptimizerLateEPPipeline,<br>
+ VerifyEachPass, DebugPM);<br>
+ });<br>
+ if (!VectorizerStartEPPipeline.em<wbr>pty())<br>
+ PB.registerVectorizerStartEPCa<wbr>llback(<br>
+ [&](FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) {<br>
+ return PB.parsePassPipeline(PM, VectorizerStartEPPipeline,<br>
+ VerifyEachPass, DebugPM);<br>
+ });<br>
+}<br>
+<br>
bool llvm::runPassPipeline(StringRe<wbr>f Arg0, Module &M, TargetMachine *TM,<br>
tool_output_file *Out,<br>
tool_output_file *ThinLTOLinkOut,<br>
@@ -56,7 +133,9 @@ bool llvm::runPassPipeline(StringRe<wbr>f 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(StringRe<wbr>f 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/CMakeL<wbr>ists.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-pr<wbr>oject/llvm/trunk/unittests/IR/<wbr>CMakeLists.txt?rev=307532&r1=<wbr>307531&r2=307532&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/IR/CMakeL<wbr>ists.txt (original)<br>
+++ llvm/trunk/unittests/IR/CMakeL<wbr>ists.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/PassBu<wbr>ilderCallbacksTest.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-pr<wbr>oject/llvm/trunk/unittests/IR/<wbr>PassBuilderCallbacksTest.cpp?<wbr>rev=307532&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- llvm/trunk/unittests/IR/PassBu<wbr>ilderCallbacksTest.cpp (added)<br>
+++ llvm/trunk/unittests/IR/PassBu<wbr>ilderCallbacksTest.cpp Mon Jul 10 03:57:55 2017<br>
@@ -0,0 +1,520 @@<br>
+//===- unittests/IR/PassBuilderCallba<wbr>cksTest.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/CGSCCPassManage<wbr>r.h><br>
+#include <llvm/Analysis/LoopAnalysisMan<wbr>ager.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/LoopPa<wbr>ssManager.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<D<wbr>erivedT &>(*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<IRU<wbr>nitT>>();<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->ge<wbr>tResult()));<br>
+ ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))<br>
+ .WillByDefault(Invoke(&invalid<wbr>ateCallback));<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<Derived<wbr>T, IRUnitT, AnalysisManagerT,<br>
+ ExtraArgTs...>::Analysis::<wbr>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(Preserve<wbr>dAnalyses::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<MockPassHan<wbr>dle<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<MockPassHan<wbr>dle<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<MockPassHan<wbr>dle<LazyCallGraph::SCC>, LazyCallGraph::SCC,<br>
+ CGSCCAnalysisManager, LazyCallGraph &,<br>
+ CGSCCUpdateResult &> {<br>
+ MOCK_METHOD4(run,<br>
+ PreservedAnalyses(LazyCallGra<wbr>ph::SCC &, CGSCCAnalysisManager &,<br>
+ LazyCallGraph &G, CGSCCUpdateResult &UR));<br>
+<br>
+ MockPassHandle() { setDefaults(); }<br>
+};<br>
+<br>
+template <><br>
+struct MockPassHandle<Module><br>
+ : MockPassHandleBase<MockPassHan<wbr>dle<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<MockAna<wbr>lysisHandle<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::Invalidat<wbr>or &));<br>
+<br>
+ MockAnalysisHandle<Loop>() { this->setDefaults(); }<br>
+};<br>
+<br>
+template <><br>
+struct MockAnalysisHandle<Function><br>
+ : MockAnalysisHandleBase<MockAna<wbr>lysisHandle<Function>, Function> {<br>
+ MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));<br>
+<br>
+ MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,<br>
+ FunctionAnalysisManager::Inval<wbr>idator &));<br>
+<br>
+ MockAnalysisHandle<Function>() { setDefaults(); }<br>
+};<br>
+<br>
+template <><br>
+struct MockAnalysisHandle<LazyCallGra<wbr>ph::SCC><br>
+ : MockAnalysisHandleBase<MockAna<wbr>lysisHandle<LazyCallGraph::<wbr>SCC>,<br>
+ LazyCallGraph::SCC, CGSCCAnalysisManager,<br>
+ LazyCallGraph &> {<br>
+ MOCK_METHOD3(run, Analysis::Result(LazyCallGraph<wbr>::SCC &,<br>
+ CGSCCAnalysisManager &, LazyCallGraph &));<br>
+<br>
+ MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,<br>
+ CGSCCAnalysisManager::Invalida<wbr>tor &));<br>
+<br>
+ MockAnalysisHandle<LazyCallGra<wbr>ph::SCC>() { setDefaults(); }<br>
+};<br>
+<br>
+template <><br>
+struct MockAnalysisHandle<Module><br>
+ : MockAnalysisHandleBase<MockAna<wbr>lysisHandle<Module>, Module> {<br>
+ MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));<br>
+<br>
+ MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,<br>
+ ModuleAnalysisManager::Invalid<wbr>ator &));<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<PassM<wbr>anager<<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>::A<wbr>nalysis;<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<ExtraAnalysisArgT<wbr>s>(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.registerAnalysisRegistratio<wbr>nCallback([this](<wbr>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.registerPipelineParsingCall<wbr>back(<br>
+ [this](StringRef Name, PassManagerT &PM,<br>
+ ArrayRef<PassBuilder::Pipelin<wbr>eElement> 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<An<wbr>alysisT>("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(FA<wbr>M);<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<Modul<wbr>ePassManager>;<br>
+using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCC<wbr>PassManager>;<br>
+using FunctionCallbacksTest = PassBuilderCallbacksTest<Funct<wbr>ionPassManager>;<br>
+using LoopCallbacksTest = PassBuilderCallbacksTest<LoopP<wbr>assManager>;<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(getAnalysisRe<wbr>sult));<br>
+<br>
+ StringRef PipelineText = "test-transform";<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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(getAnalysisRe<wbr>sult));<br>
+<br>
+ StringRef PipelineText = "test-transform";<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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.parsePassPipeli<wbr>ne(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.parsePassPipeli<wbr>ne(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>,invali<wbr>date<test-analysis>";<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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>,invali<wbr>date<test-analysis>";<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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>,invali<wbr>date<test-analysis>";<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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>,invali<wbr>date<test-analysis>";<br>
+<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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.registerParseTopLevelPipeli<wbr>neCallback([this](<br>
+ ModulePassManager &MPM, ArrayRef<PassBuilder::Pipeline<wbr>Element> Pipeline,<br>
+ bool VerifyEachPass, bool DebugLogging) {<br>
+ auto &FirstName = Pipeline.front().Name;<br>
+ auto &InnerPipeline = Pipeline.front().InnerPipeline<wbr>;<br>
+ if (FirstName == "another-pipeline") {<br>
+ for (auto &E : InnerPipeline) {<br>
+ if (parseAnalysisUtilityPasses<An<wbr>alysisT>("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(getAnalysisRe<wbr>sult));<br>
+ EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>")<wbr>, _, _));<br>
+<br>
+ StringRef PipelineText =<br>
+ "another-pipeline(test-transfo<wbr>rm,invalidate<test-analysis>)"<wbr>;<br>
+ ASSERT_TRUE(PB.parsePassPipeli<wbr>ne(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.parsePassPipel<wbr>ine(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" target="_blank">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>
</div></blockquote></div><br></div></div></div>