Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -17,6 +17,7 @@ #define LLVM_PASSES_PASSBUILDER_H #include "llvm/ADT/Optional.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/IR/PassManager.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" @@ -26,6 +27,7 @@ class StringRef; class AAManager; class TargetMachine; +class HookManager; /// A struct capturing PGO tunables. struct PGOOptions { @@ -45,6 +47,8 @@ TargetMachine *TM; Optional PGOOpt; + const HookManager &HM; + public: /// \brief LLVM-provided high-level optimization levels. /// @@ -133,8 +137,9 @@ }; explicit PassBuilder(TargetMachine *TM = nullptr, - Optional PGOOpt = None) - : TM(TM), PGOOpt(PGOOpt) {} + Optional PGOOpt = None, + HookManager *HM = nullptr) + : TM(TM), PGOOpt(PGOOpt), HM(HM ? *HM : GlobalHookManager()) {} /// \brief Cross register the analysis managers through their proxies. /// @@ -287,6 +292,9 @@ /// returns false. bool parseAAPipeline(AAManager &AA, StringRef PipelineText); + /// \brief Access the global singleton hook manager instance + static HookManager &GlobalHookManager(); + private: /// A struct to capture parsed pass pipeline names. struct PipelineElement { @@ -320,6 +328,390 @@ ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); }; -} +template struct HookTable { typedef Tag TableTag; }; + +template , + typename _PassManagerT = PassManager<_IRUnitT>> +struct CustomPipelineHookTable : public HookTable<_IRUnitT> { + typedef _IRUnitT IRUnitT; + typedef _AnalysisManagerT AnalysisManagerT; + typedef _PassManagerT PassManagerT; + typedef std::function AnalysisPassHook; + typedef std::function TransformPassHook; + + SmallVector Analyses; + StringMap Transforms; + StringMap RequireUtilities; + StringMap InvalidateUtilities; +}; + +struct FunctionPipelineHookTable : public CustomPipelineHookTable { + typedef std::function AAPassHook; + StringMap AliasAnalyses; +}; + +using ModulePipelineHookTable = CustomPipelineHookTable; +using SCCPipelineHookTable = + CustomPipelineHookTable; +using LoopPipelineHookTable = + CustomPipelineHookTable; + +template > +struct ExtensionHookTable : public HookTable { + typedef _PassManagerT PassManagerT; + typedef std::function TransformPassHook; + SmallVector Transforms; +}; + +//{{@ Extension Point Tags +namespace EP { +/// EarlyAsPossible - This extension point allows adding passes before +/// any other transformations, allowing them to see the code as it is coming +/// out of the frontend. +struct EarlyAsPossible {}; + +/// ModuleOptimizerEarly - This extension point allows adding passes +/// just before the main module-level optimization passes. +struct ModuleOptimizerEarly {}; + +/// LoopOptimizerEnd - This extension point allows adding loop passes to +/// the end of the loop optimizer. +struct LoopOptimizerEnd {}; + +/// ScalarOptimizerLate - This extension point allows adding optimization +/// passes after most of the main optimizations, but before the last +/// cleanup-ish optimizations. +struct ScalarOptimizerLate {}; + +/// OptimizerLast -- This extension point allows adding passes that +/// run after everything else. +struct OptimizerLast {}; + +/// VectorizerStart - This extension point allows adding optimization +/// passes before the vectorizer and other highly target specific +/// optimization passes are executed. +struct VectorizerStart {}; + +/// EnabledOnOptLevel0 - This extension point allows adding passes that +/// should not be disabled by O0 optimization level. The passes will be +/// inserted after the inlining pass. +struct EnabledOnOptLevel0 {}; + +/// Peephole - This extension point allows adding passes that perform +/// peephole optimizations similar to the instruction combiner. These passes +/// will be inserted after each instance of the instruction combiner pass. +struct Peephole {}; + +/// LateLoopOptimizations - This extension point allows adding late loop +/// canonicalization and simplification passes. This is the last point in +/// the loop optimization pipeline before loop deletion. Each pass added +/// here must be an instance of LoopPass. +/// This is the place to add passes that can remove loops, such as target- +/// specific loop idiom recognition. +struct LateLoopOptimizations {}; + +/// CGSCCOptimizerLate - This extension point allows adding CallGraphSCC +/// passes at the end of the main CallGraphSCC passes and before any +/// function simplification passes run by CGPassManager. +struct CGSCCOptimizerLate {}; +} // namespace EP +//@}} + +/// \brief This class manages the registration of hooks through which +/// out-of-tree or plugin passes are able to register themselves with a +/// \c PassManager or \c AnalysisManager. +/// +/// Such a hook is a Callable with a single argument, the Pass- or +/// AnalysisManager which passes can be added to. Passes are registered by name +/// or with a specific extension point. +/// +/// When used within a PassBuilder instance, the name is used when parsing a +/// textual pipeline description. If the name matches a name of a built-in pass, +/// this name is effectively "stolen", thus overriding the built-in pass. When +/// constructing default pipelines, such as the O.pipelines, the PassBuilder +/// will invoke transform pass hooks registered with specific extension points +/// at specific places in the pipeline. +/// +/// To install a hook in an instance of this class, interfaces are supplied +/// to handle analysis, transform and AA passes, respectively. Installing a hook +/// for an analysis pass also automatically generates default hooks for the +/// require<> and invalidate<> utility passes +class HookManager { + + // {{@ Helpers for accessing elements of an std::tuple by a Tag typedef + template struct get_type_index { + static constexpr auto value = N; + }; + template + struct get_type_index { + static constexpr auto value = N; + }; + template + struct get_type_index { + static constexpr auto value = get_type_index::value; + }; + + template + static auto get_tag_index(std::tuple &t) -> decltype( + std::get::value>(t)) { + return std::get::value>( + t); + } + + template + static auto get_tag_index(const std::tuple &t) -> decltype( + std::get::value>(t)) { + return std::get::value>( + t); + } + //@}} + + /// \brief The static table containing the registered hooks for the different + /// pass types and extension points. + std::tuple, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable, + ExtensionHookTable> + Tables; + + //{{@ \brief Compile-time accessor for the individual tables + template + auto getTable() -> decltype(HookManager::get_tag_index(Tables)) { + return HookManager::get_tag_index(Tables); + } + + template + auto getTable() const -> decltype(HookManager::get_tag_index(Tables)) { + return HookManager::get_tag_index(Tables); + } + //@}} + + //{{@ Shortcuts for accessing typedefs of a table entry + template + using TableT = typename std::remove_reference(Tables))>::type; + template + using AnalysisManagerT = typename TableT::AnalysisManagerT; + template + using PassManagerT = typename TableT::PassManagerT; + template using IRUnitT = typename TableT::IRUnitT; + //@}} + +public: + /// \brief Register a hook for a transform pass. + /// + /// If a hook has already been registered with the same Name, this hook is + /// overwritten. + template + void registerTransformPassHook(StringRef Name, Callable TransformCB) { + auto &C = getTable(); + C.Transforms.insert({Name, TransformCB}); + } + + /// \brief Register a hook for an analysis pass. + /// + /// Besides the pass Name, this interface also takes the Pass type as template + /// argument, used to install default hooks for the require<> and invalidate<> + /// utilities. + /// If a hook has already been registered with the same Name, the + /// utilitypasses for that name are overwritten. + template + void registerAnalysisPassHook(StringRef Name, Callable AnalysisCB) { + auto &C = getTable(); + C.Analyses.push_back(AnalysisCB); + C.RequireUtilities.insert( + {Name, [](PassManagerT &) { + return RequireAnalysisPass>(); + }}); + C.InvalidateUtilities.insert({Name, [](PassManagerT &) { + return InvalidateAnalysisPass(); + }}); + } + + /// \brief Register a hook for an alias analysis pass. + /// + /// If a hook has already been registered with the same Name, this hook is + /// overwritten. + template + void registerAAPassHook(StringRef Name, Callable AACB) { + auto &C = getTable(); + C.AliasAnalyses.insert({Name, AACB}); + } + + /// \brief Register a hook for an extension point + template + void registerExtensionPointHook(Callable EPCB) { + auto &C = getTable(); + C.Transforms.push_back(EPCB); + } + + //@{ + /// Public interface for the \c PassBuilder to query or invoke registered + /// hooks. + template + void registerAnalyses(AnalysisManagerT &AM) const { + auto &C = getTable(); + for (auto &H : C.Analyses) + H(AM); + } + + template bool hasPassName(StringRef Name) const { + auto &C = getTable(); + if (C.Transforms.count(Name) > 0) + return true; + StringRef slice = getRequireUtilityName(Name); + if (!slice.empty()) + if (C.RequireUtilities.count(slice)) + return true; + slice = getInvalidateUtilityName(Name); + if (!slice.empty()) + if (C.InvalidateUtilities.count(slice)) + return true; + return false; + } + + template + bool parsePassName(StringRef Name, PassManagerT &PM) const { + auto &C = getTable(); + auto T = C.Transforms.find(Name); + if (T != C.Transforms.end()) { + T->getValue()(PM); + return true; + } + StringRef slice = getRequireUtilityName(Name); + if (!slice.empty()) { + auto R = C.RequireUtilities.find(slice); + if (R != C.RequireUtilities.end()) { + R->getValue()(PM); + return true; + } + } + slice = getInvalidateUtilityName(Name); + if (!slice.empty()) { + auto I = C.InvalidateUtilities.find(slice); + if (I != C.InvalidateUtilities.end()) { + I->getValue()(PM); + return true; + } + } + return false; + } + + bool parseAAPassName(StringRef Name, AAManager &AA) const { + auto &C = getTable(); + auto A = C.AliasAnalyses.find(Name); + if (A != C.AliasAnalyses.end()) { + A->getValue()(AA); + return true; + } + return false; + } + + template + void injectExtensions(_PassManagerT &PM) const { + auto &C = getTable(); + for (auto &P : C.Transforms) + P(PM); + } + //@} +private: + inline StringRef getRequireUtilityName(StringRef Name) const { + if (Name.endswith(">") && Name.startswith("require<")) + return Name.slice(8, Name.size() - 1); + return StringRef(); + } + + inline StringRef getInvalidateUtilityName(StringRef Name) const { + if (Name.endswith(">") && Name.startswith("invalidate<")) + return Name.slice(11, Name.size() - 1); + return StringRef(); + } +}; + +//{@ +/// \brief Convenience types to install global hooks for a pass. Constructing an +/// instance of this will perform the registration of a hook with the given +/// arguments, or register a default hook for the given PassT. +template struct RegisterAnalysisPass { + struct DefaultHook { + template void operator()(AnalysisManagerT &AM) { + AM.registerPass([] { return PassT(); }); + } + }; + + RegisterAnalysisPass(StringRef Name) + : RegisterAnalysisPass(Name, DefaultHook()) {} + + template + RegisterAnalysisPass(StringRef Name, Callable AnalysisCB) { + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerAnalysisPassHook(Name, AnalysisCB); + } +}; + +template struct RegisterTransformPass { + struct DefaultHook { + template void operator()(PassManagerT &PM) { + PM.addPass(PassT()); + } + }; + RegisterTransformPass(StringRef Name) + : RegisterTransformPass(Name, DefaultHook()) {} + + template + RegisterTransformPass(StringRef Name, Callable TransformCB) { + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerTransformPassHook(Name, TransformCB); + } +}; + +template struct RegisterAAPass { + struct DefaultHook { + template void operator()(AnalysisManagerT &AM) { + AM.registerPass([] { return PassT(); }); + } + void operator()(AAManager &AA) { AA.registerFunctionAnalysis(); } + }; + + RegisterAAPass(StringRef Name) + : RegisterAAPass(Name, DefaultHook(), DefaultHook()) {} + + /// An alias analysis pass is both an AAPass and an AnalysisPass, thus it + /// needs two hooks. + template + RegisterAAPass(StringRef Name, Callable AnalysisCB, AACallable AACB) { + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerAnalysisPassHook(Name, AnalysisCB); + HM.registerAAPassHook(Name, AACB); + } +}; + +template struct InjectExtensionPoint { + struct DefaultHook { + template void operator()(PassManagerT &PM) { + PM.addPass(PassT()); + } + }; + + InjectExtensionPoint() : InjectExtensionPoint(DefaultHook()) {} + + template InjectExtensionPoint(Callable EPCB) { + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerExtensionPointHook(EPCB); + } +}; // namespace llvm + +//@} +} // namespace llvm #endif Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -57,6 +57,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/GCOVProfiler.h" @@ -258,26 +259,39 @@ } // End anonymous namespace. +HookManager &PassBuilder::GlobalHookManager() { + static HookManager instance; + return instance; +} + void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) { -#define MODULE_ANALYSIS(NAME, CREATE_PASS) \ + HM.registerAnalyses(MAM); + +#define MODULE_ANALYSIS(NAME, CREATE_PASS) \ MAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" } void PassBuilder::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) { -#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ + HM.registerAnalyses(CGAM); + +#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ CGAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" } void PassBuilder::registerFunctionAnalyses(FunctionAnalysisManager &FAM) { -#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ + HM.registerAnalyses(FAM); + +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ FAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" } void PassBuilder::registerLoopAnalyses(LoopAnalysisManager &LAM) { -#define LOOP_ANALYSIS(NAME, CREATE_PASS) \ + HM.registerAnalyses(LAM); + +#define LOOP_ANALYSIS(NAME, CREATE_PASS) \ LAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" } @@ -306,6 +320,7 @@ if (!isOptimizingForSize(Level)) FPM.addPass(LibCallsShrinkWrapPass()); + HM.injectExtensions(FPM); FPM.addPass(TailCallElimPass()); FPM.addPass(SimplifyCFGPass()); @@ -333,8 +348,10 @@ #endif LPM2.addPass(IndVarSimplifyPass()); LPM2.addPass(LoopIdiomRecognizePass()); + HM.injectExtensions(LPM2); LPM2.addPass(LoopDeletionPass()); LPM2.addPass(LoopUnrollPass::createFull(Level)); + HM.injectExtensions(LPM2); // We provide the opt remark emitter pass for LICM to use. We only need to do // this once as it is immutable. @@ -367,6 +384,7 @@ // Run instcombine after redundancy and dead bit elimination to exploit // opportunities opened up by them. FPM.addPass(InstCombinePass()); + HM.injectExtensions(FPM); // Re-consider control flow based optimizations after redundancy elimination, // redo DCE, etc. @@ -375,16 +393,20 @@ FPM.addPass(DSEPass()); FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass())); + HM.injectExtensions(FPM); + // Finally, do an expensive DCE pass to catch all the dead code exposed by // the simplifications and basic cleanup after all the simplifications. FPM.addPass(ADCEPass()); FPM.addPass(SimplifyCFGPass()); FPM.addPass(InstCombinePass()); + HM.injectExtensions(FPM); return FPM; } -static void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, +static void addPGOInstrPasses(const HookManager &HM, ModulePassManager &MPM, + bool DebugLogging, PassBuilder::OptimizationLevel Level, bool RunProfileGen, std::string ProfileGenFile, std::string ProfileUseFile) { @@ -412,9 +434,8 @@ FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies. FPM.addPass(SimplifyCFGPass()); // Merge & remove basic blocks. FPM.addPass(InstCombinePass()); // Combine silly sequences. + HM.injectExtensions(FPM); - // FIXME: Here the old pass manager inserts peephole extensions. - // Add them when they're supported. CGPipeline.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPipeline))); @@ -446,10 +467,12 @@ // Do basic inference of function attributes from known properties of system // libraries and other oracles. MPM.addPass(InferFunctionAttrsPass()); + HM.injectExtensions(MPM); // Create an early function pass manager to cleanup the output of the // frontend. FunctionPassManager EarlyFPM(DebugLogging); + HM.injectExtensions(EarlyFPM); EarlyFPM.addPass(SimplifyCFGPass()); EarlyFPM.addPass(SROA()); EarlyFPM.addPass(EarlyCSEPass()); @@ -481,6 +504,7 @@ // optimizations. FunctionPassManager GlobalCleanupPM(DebugLogging); GlobalCleanupPM.addPass(InstCombinePass()); + HM.injectExtensions(GlobalCleanupPM); GlobalCleanupPM.addPass(SimplifyCFGPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(GlobalCleanupPM))); @@ -488,7 +512,7 @@ if (PGOOpt) { assert(PGOOpt->RunProfileGen || PGOOpt->SamplePGO || !PGOOpt->ProfileUseFile.empty()); - addPGOInstrPasses(MPM, DebugLogging, Level, PGOOpt->RunProfileGen, + addPGOInstrPasses(HM, MPM, DebugLogging, Level, PGOOpt->RunProfileGen, PGOOpt->ProfileGenFile, PGOOpt->ProfileUseFile); } @@ -528,6 +552,7 @@ // CGSCC walk. MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor( buildFunctionSimplificationPipeline(Level, DebugLogging))); + HM.injectExtensions(MainCGPipeline); // We wrap the CGSCC pipeline in a devirtualization repeater. This will try // to detect when we devirtualize indirect calls and iterate the SCC passes @@ -569,6 +594,8 @@ // rather than on each loop in an inside-out manner, and so they are actually // function passes. + HM.injectExtensions(OptimizePM); + // First rotate loops that may have been un-rotated by prior passes. OptimizePM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); @@ -633,6 +660,7 @@ // ordering here. MPM.addPass(GlobalDCEPass()); MPM.addPass(ConstantMergePass()); + HM.injectExtensions(MPM); return MPM; } @@ -712,8 +740,10 @@ // simplification opportunities, and both can propagate functions through // function pointers. When this happens, we often have to resolve varargs // calls, etc, so let instcombine do this. - // FIXME: add peephole extensions here as the legacy PM does. - MPM.addPass(createModuleToFunctionPassAdaptor(InstCombinePass())); + FunctionPassManager SimplifyFPM(DebugLogging); + SimplifyFPM.addPass(InstCombinePass()); + HM.injectExtensions(SimplifyFPM); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(SimplifyFPM))); // Note: historically, the PruneEH pass was run first to deduce nounwind and // generally clean up exception handling overhead. It isn't clear this is @@ -730,10 +760,10 @@ MPM.addPass(GlobalDCEPass()); FunctionPassManager FPM(DebugLogging); - // The IPO Passes may leave cruft around. Clean up after them. - // FIXME: add peephole extensions here as the legacy PM does. FPM.addPass(InstCombinePass()); + HM.injectExtensions(FPM); + FPM.addPass(JumpThreadingPass()); // Break up allocas @@ -780,8 +810,8 @@ // FIXME: Conditionally run LoadCombine here, after it's ported // (in case we still have this pass, given its questionable usefulness). - // FIXME: add peephole extensions to the PM here. MainFPM.addPass(InstCombinePass()); + HM.injectExtensions(MainFPM); MainFPM.addPass(JumpThreadingPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(MainFPM))); @@ -857,7 +887,7 @@ return Count; } -static bool isModulePassName(StringRef Name) { +static bool isModulePassName(StringRef Name, const HookManager &HM) { // Manually handle aliases for pre-configured pipeline fragments. if (Name.startswith("default") || Name.startswith("lto")) return DefaultAliasRegex.match(Name); @@ -870,6 +900,9 @@ if (Name == "function") return true; + if (HM.hasPassName(Name)) + return true; + // Explicitly handle custom-parsed pass names. if (parseRepeatPassName(Name)) return true; @@ -885,13 +918,16 @@ return false; } -static bool isCGSCCPassName(StringRef Name) { +static bool isCGSCCPassName(StringRef Name, const HookManager &HM) { // Explicitly handle pass manager names. if (Name == "cgscc") return true; if (Name == "function") return true; + if (HM.hasPassName(Name)) + return true; + // Explicitly handle custom-parsed pass names. if (parseRepeatPassName(Name)) return true; @@ -909,13 +945,16 @@ return false; } -static bool isFunctionPassName(StringRef Name) { +static bool isFunctionPassName(StringRef Name, const HookManager &HM) { // Explicitly handle pass manager names. if (Name == "function") return true; if (Name == "loop") return true; + if (HM.hasPassName(Name)) + return true; + // Explicitly handle custom-parsed pass names. if (parseRepeatPassName(Name)) return true; @@ -931,11 +970,14 @@ return false; } -static bool isLoopPassName(StringRef Name) { +static bool isLoopPassName(StringRef Name, const HookManager &HM) { // Explicitly handle pass manager names. if (Name == "loop") return true; + if (HM.hasPassName(Name)) + return true; + // Explicitly handle custom-parsed pass names. if (parseRepeatPassName(Name)) return true; @@ -1067,9 +1109,11 @@ .Case("O3", O3) .Case("Os", Os) .Case("Oz", Oz); - if (L == O0) + if (L == O0) { + HM.injectExtensions(MPM); // At O0 we do nothing at all! return true; + } if (Matches[1] == "default") { MPM.addPass(buildPerModuleDefaultPipeline(L, DebugLogging)); @@ -1082,6 +1126,9 @@ return true; } + if (HM.parsePassName(Name, MPM)) + return true; + // Finally expand the basic registered passes from the .inc file. #define MODULE_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ @@ -1153,6 +1200,9 @@ return false; } + if (HM.parsePassName(Name, CGPM)) + return true; + // Now expand the basic registered passes from the .inc file. #define CGSCC_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ @@ -1215,6 +1265,9 @@ return false; } + if (HM.parsePassName(Name, FPM)) + return true; + // Now expand the basic registered passes from the .inc file. #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ @@ -1266,6 +1319,9 @@ return false; } + if (HM.parsePassName(Name, LPM)) + return true; + // Now expand the basic registered passes from the .inc file. #define LOOP_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ @@ -1291,12 +1347,16 @@ } bool PassBuilder::parseAAPassName(AAManager &AA, StringRef Name) { + if (HM.parseAAPassName(Name, AA)) + return true; + #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ if (Name == NAME) { \ AA.registerModuleAnalysis< \ std::remove_reference::type>(); \ return true; \ } + #define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ if (Name == NAME) { \ AA.registerFunctionAnalysis< \ @@ -1385,12 +1445,12 @@ // automatically. StringRef FirstName = Pipeline->front().Name; - if (!isModulePassName(FirstName)) { - if (isCGSCCPassName(FirstName)) + if (!isModulePassName(FirstName, HM)) { + if (isCGSCCPassName(FirstName, HM)) Pipeline = {{"cgscc", std::move(*Pipeline)}}; - else if (isFunctionPassName(FirstName)) + else if (isFunctionPassName(FirstName, HM)) Pipeline = {{"function", std::move(*Pipeline)}}; - else if (isLoopPassName(FirstName)) + else if (isLoopPassName(FirstName, HM)) Pipeline = {{"function", {{"loop", std::move(*Pipeline)}}}}; else // Unknown pass name! Index: test/Other/new-pm-lto-defaults.ll =================================================================== --- test/Other/new-pm-lto-defaults.ll +++ test/Other/new-pm-lto-defaults.ll @@ -45,7 +45,10 @@ ; CHECK-O2-NEXT: Running analysis: AssumptionAnalysis ; CHECK-O2-NEXT: Running pass: ConstantMergePass ; CHECK-O2-NEXT: Running pass: DeadArgumentEliminationPass -; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}InstCombinePass> +; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}> +; CHECK-O2-NEXT: Starting llvm::Function pass manager run. +; CHECK-O2-NEXT: Running pass: InstCombinePass +; CHECK-O2-NEXT: Finished llvm::Function pass manager run. ; CHECK-O2-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}InlinerPass> ; CHECK-O2-NEXT: Running pass: GlobalOptPass ; CHECK-O2-NEXT: Running pass: GlobalDCEPass Index: unittests/IR/CMakeLists.txt =================================================================== --- unittests/IR/CMakeLists.txt +++ unittests/IR/CMakeLists.txt @@ -3,6 +3,7 @@ AsmParser Core Support + Passes ) set(IRSources @@ -14,6 +15,7 @@ DebugTypeODRUniquingTest.cpp DominatorTreeTest.cpp FunctionTest.cpp + HookManagerTest.cpp IRBuilderTest.cpp InstructionsTest.cpp IntrinsicsTest.cpp Index: unittests/IR/HookManagerTest.cpp =================================================================== --- /dev/null +++ unittests/IR/HookManagerTest.cpp @@ -0,0 +1,98 @@ +//===- llvm/unittest/IR/HookManagerTest.cpp - HookManager unit tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +using namespace llvm; + +namespace { +template +struct TestAnalysisPass : public AnalysisInfoMixin> { + struct Result {}; + template + Result run(IRUnitT &M, AnalysisManagerT &, ExtraTs &&... ExtraArgs) { + return Result(); + } + static AnalysisKey Key; +}; + +template +struct TestTransformPass : public PassInfoMixin> { + template + PreservedAnalyses run(IRUnitT &M, AnalysisManagerT &AM, ResultT &&R, + ExtraTs &&... ExtraArgs) { + AM.template getResult>(M, R); + PreservedAnalyses P; + P.preserve>(); + return P; + } + template + PreservedAnalyses run(IRUnitT &M, AnalysisManagerT &AM) { + AM.template getResult>(M); + PreservedAnalyses P; + P.preserve>(); + return P; + } +}; + +template AnalysisKey TestAnalysisPass::Key; + +template class HookManagerTest : public testing::Test {}; + +typedef testing::Types PMTypes; + +TYPED_TEST_CASE(HookManagerTest, PMTypes); + +template bool TransformPassTest() { + LLVMContext Ctx; + Module M("TestModule", Ctx); + PassBuilder PB; + ModulePassManager PM; + ModuleAnalysisManager AM; + + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerAnalysisPassHook>( + "test-analysis", + typename RegisterAnalysisPass< + TypeParam, TestAnalysisPass>::DefaultHook()); + HM.registerTransformPassHook( + "test-transform", + typename RegisterTransformPass< + TypeParam, TestTransformPass>::DefaultHook()); + PB.registerModuleAnalyses(AM); + return PB.parsePassPipeline(PM, "test-transform", true); +} + +TYPED_TEST(HookManagerTest, TransformPass) { + ASSERT_TRUE(TransformPassTest()); +} + +template bool AnalysisPassTest() { + LLVMContext Ctx; + Module M("TestModule", Ctx); + PassBuilder PB; + ModulePassManager PM; + ModuleAnalysisManager AM; + + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerAnalysisPassHook>( + "test-analysis", + typename RegisterAnalysisPass< + TypeParam, TestAnalysisPass>::DefaultHook()); + PB.registerModuleAnalyses(AM); + return PB.parsePassPipeline( + PM, "require,invalidate", true); +} +TYPED_TEST(HookManagerTest, AnalysisPass) { + ASSERT_TRUE(AnalysisPassTest()); +} +} // end anonymous namespace