Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -26,6 +26,7 @@ class StringRef; class AAManager; class TargetMachine; +class HookManager; /// A struct capturing PGO tunables. struct PGOOptions { @@ -42,9 +43,12 @@ /// of the built-in passes, and those may reference these members during /// construction. class PassBuilder { + friend class HookManager; TargetMachine *TM; Optional PGOOpt; + const HookManager &HM; + public: /// \brief LLVM-provided high-level optimization levels. /// @@ -132,9 +136,13 @@ Oz }; + explicit PassBuilder(const HookManager &HM, TargetMachine *TM = nullptr, + Optional PGOOpt = None) + : TM(TM), PGOOpt(PGOOpt), HM(HM) {} + explicit PassBuilder(TargetMachine *TM = nullptr, Optional PGOOpt = None) - : TM(TM), PGOOpt(PGOOpt) {} + : TM(TM), PGOOpt(PGOOpt), HM(GlobalHookManager()) {} /// \brief Cross register the analysis managers through their proxies. /// @@ -287,6 +295,9 @@ /// returns false. bool parseAAPipeline(AAManager &AA, StringRef PipelineText); + /// Obtain the global HookManager object + static HookManager &GlobalHookManager(); + private: /// A struct to capture parsed pass pipeline names. struct PipelineElement { @@ -320,6 +331,191 @@ ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); }; + +class HookManager { + friend class PassBuilder; + +public: + enum class ExtensionPoint { + /// 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. + EarlyAsPossible, + + /// ModuleOptimizerEarly - This extension point allows adding passes + /// just before the main module-level optimization passes. + ModuleOptimizerEarly, + + /// LoopOptimizerEnd - This extension point allows adding loop passes to + /// the end of the loop optimizer. + LoopOptimizerEnd, + + /// ScalarOptimizerLate - This extension point allows adding optimization + /// passes after most of the main optimizations, but before the last + /// cleanup-ish optimizations. + ScalarOptimizerLate, + + /// OptimizerLast -- This extension point allows adding passes that + /// run after everything else. + OptimizerLast, + + /// VectorizerStart - This extension point allows adding optimization + /// passes before the vectorizer and other highly target specific + /// optimization passes are executed. + 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. + 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. + 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. + 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. + CGSCCOptimizerLate, + }; + +private: + template + using EPCallback = std::function; + template + using PassCallback = std::function; + template + using PipelineCallback = + std::function Pipeline)>; + template + using AnalysisCallback = std::function; + +public: + using AACallback = std::function; + using CGSCCAnalysisCallback = AnalysisCallback; + using CGSCCEPCallback = EPCallback; + using CGSCCPassCallback = PassCallback; + using CGSCCPipelineCallback = PipelineCallback; + using FunctionAnalysisCallback = AnalysisCallback; + using FunctionEPCallback = EPCallback; + using FunctionPassCallback = PassCallback; + using FunctionPipelineCallback = PipelineCallback; + using LoopAnalysisCallback = AnalysisCallback; + using LoopEPCallback = EPCallback; + using LoopPassCallback = PassCallback; + using LoopPipelineCallback = PipelineCallback; + using ModuleAnalysisCallback = AnalysisCallback; + using ModuleEPCallback = EPCallback; + using ModulePassCallback = PassCallback; + using ModulePipelineCallback = PipelineCallback; + + void registerAACallback(const AACallback &C); + void registerAnalysisCallback(const CGSCCAnalysisCallback &C); + void registerAnalysisCallback(const FunctionAnalysisCallback &C); + void registerAnalysisCallback(const LoopAnalysisCallback &C); + void registerAnalysisCallback(const ModuleAnalysisCallback &C); + void registerEPCallback(const CGSCCEPCallback &C); + void registerEPCallback(const FunctionEPCallback &C); + void registerEPCallback(const LoopEPCallback &C); + void registerEPCallback(const ModuleEPCallback &C); + void registerPassCallback(const CGSCCPassCallback &C); + void registerPassCallback(const FunctionPassCallback &C); + void registerPassCallback(const LoopPassCallback &C); + void registerPassCallback(const ModulePassCallback &C); + void registerPipelineCallback(const CGSCCPipelineCallback &C); + void registerPipelineCallback(const FunctionPipelineCallback &C); + void registerPipelineCallback(const LoopPipelineCallback &C); + void registerPipelineCallback(const ModulePipelineCallback &C); + + void invokeAnalysisCallbacks(CGSCCAnalysisManager &PM) const; + void invokeAnalysisCallbacks(FunctionAnalysisManager &PM) const; + void invokeAnalysisCallbacks(LoopAnalysisManager &PM) const; + void invokeAnalysisCallbacks(ModuleAnalysisManager &PM) const; + void invokeEPCallbacks(ExtensionPoint EP, CGSCCPassManager &PM) const; + void invokeEPCallbacks(ExtensionPoint EP, FunctionPassManager &PM) const; + void invokeEPCallbacks(ExtensionPoint EP, LoopPassManager &PM) const; + void invokeEPCallbacks(ExtensionPoint EP, ModulePassManager &PM) const; + bool invokeAACallbacks(StringRef Name, AAManager &PM) const; + bool invokePassCallbacks(StringRef Name, CGSCCPassManager &PM) const; + bool invokePassCallbacks(StringRef Name, FunctionPassManager &PM) const; + bool invokePassCallbacks(StringRef Name, LoopPassManager &PM) const; + bool invokePassCallbacks(StringRef Name, ModulePassManager &PM) const; + bool invokePipelineCallbacks( + StringRef Name, CGSCCPassManager &PM, + ArrayRef Pipeline) const; + bool invokePipelineCallbacks( + StringRef Name, FunctionPassManager &PM, + ArrayRef Pipeline) const; + bool invokePipelineCallbacks( + StringRef Name, LoopPassManager &PM, + ArrayRef Pipeline) const; + bool invokePipelineCallbacks( + StringRef Name, ModulePassManager &PM, + ArrayRef Pipeline) const; + +private: + // Module callbacks + SmallVector moduleAnalysisCallbacks; + SmallVector modulePassCallbacks; + SmallVector moduleEPCallbacks; + SmallVector modulePipelineCallbacks; + // CGSCC callbacks + SmallVector cgsccAnalysisCallbacks; + SmallVector cgsccPassCallbacks; + SmallVector cgsccEPCallbacks; + SmallVector cgsccPipelineCallbacks; + // Function callbacks + SmallVector functionAnalysisCallbacks; + SmallVector functionPassCallbacks; + SmallVector functionEPCallbacks; + SmallVector functionPipelineCallbacks; + // Loop callbacks + SmallVector loopAnalysisCallbacks; + SmallVector loopPassCallbacks; + SmallVector loopEPCallbacks; + SmallVector loopPipelineCallbacks; + // AA callbacks + SmallVector AACallbacks; +}; + +template +bool HandleAnalysisUtilities( + StringRef PassName, StringRef PipelineEntry, + PassManager &PM) { + if (!PipelineEntry.endswith(">")) + return false; + // See if this is an invalidate<> pass name + if (PipelineEntry.startswith("invalidate<")) { + PipelineEntry = PipelineEntry.substr(11, PipelineEntry.size() - 12); + if (PipelineEntry != PassName) + return false; + PM.addPass(InvalidateAnalysisPass()); + return true; + } + + // See if this is a require<> pass name + if (PipelineEntry.startswith("require<")) { + PipelineEntry = PipelineEntry.substr(8, PipelineEntry.size() - 9); + if (PipelineEntry != PassName) + return false; + PM.addPass(RequireAnalysisPass()); + return true; + } + + return false; +} } #endif Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -272,28 +272,194 @@ } // End anonymous namespace. +HookManager &PassBuilder::GlobalHookManager() { + static HookManager instance; + return instance; +} +void HookManager::registerAnalysisCallback(const ModuleAnalysisCallback &C) { + moduleAnalysisCallbacks.push_back(C); +} +void HookManager::registerPassCallback(const ModulePassCallback &C) { + modulePassCallbacks.push_back(C); +} +void HookManager::registerEPCallback(const ModuleEPCallback &C) { + moduleEPCallbacks.push_back(C); +} +void HookManager::registerPipelineCallback(const ModulePipelineCallback &C) { + modulePipelineCallbacks.push_back(C); +} +void HookManager::registerAnalysisCallback(const CGSCCAnalysisCallback &C) { + cgsccAnalysisCallbacks.push_back(C); +} +void HookManager::registerPassCallback(const CGSCCPassCallback &C) { + cgsccPassCallbacks.push_back(C); +} +void HookManager::registerEPCallback(const CGSCCEPCallback &C) { + cgsccEPCallbacks.push_back(C); +} +void HookManager::registerPipelineCallback(const CGSCCPipelineCallback &C) { + cgsccPipelineCallbacks.push_back(C); +} +void HookManager::registerAnalysisCallback(const FunctionAnalysisCallback &C) { + functionAnalysisCallbacks.push_back(C); +} +void HookManager::registerPassCallback(const FunctionPassCallback &C) { + functionPassCallbacks.push_back(C); +} +void HookManager::registerEPCallback(const FunctionEPCallback &C) { + functionEPCallbacks.push_back(C); +} +void HookManager::registerPipelineCallback(const FunctionPipelineCallback &C) { + functionPipelineCallbacks.push_back(C); +} +void HookManager::registerAnalysisCallback(const LoopAnalysisCallback &C) { + loopAnalysisCallbacks.push_back(C); +} +void HookManager::registerPassCallback(const LoopPassCallback &C) { + loopPassCallbacks.push_back(C); +} +void HookManager::registerEPCallback(const LoopEPCallback &C) { + loopEPCallbacks.push_back(C); +} +void HookManager::registerPipelineCallback(const LoopPipelineCallback &C) { + loopPipelineCallbacks.push_back(C); +} +void HookManager::registerAACallback(const AACallback &C) { + AACallbacks.push_back(C); +} +bool HookManager::invokeAACallbacks(StringRef Name, AAManager &PM) const { + for (auto &C : AACallbacks) + if (C(Name, PM)) + return true; + return false; +} +void HookManager::invokeAnalysisCallbacks(CGSCCAnalysisManager &PM) const { + for (auto &C : cgsccAnalysisCallbacks) + C(PM); +} +void HookManager::invokeAnalysisCallbacks(FunctionAnalysisManager &PM) const { + for (auto &C : functionAnalysisCallbacks) + C(PM); +} +void HookManager::invokeAnalysisCallbacks(LoopAnalysisManager &PM) const { + for (auto &C : loopAnalysisCallbacks) + C(PM); +} +void HookManager::invokeAnalysisCallbacks(ModuleAnalysisManager &PM) const { + for (auto &C : moduleAnalysisCallbacks) + C(PM); +} +void HookManager::invokeEPCallbacks(ExtensionPoint EP, + CGSCCPassManager &PM) const { + for (auto &C : cgsccEPCallbacks) + C(EP, PM); +} +void HookManager::invokeEPCallbacks(ExtensionPoint EP, + FunctionPassManager &PM) const { + for (auto &C : functionEPCallbacks) + C(EP, PM); +} +void HookManager::invokeEPCallbacks(ExtensionPoint EP, + LoopPassManager &PM) const { + for (auto &C : loopEPCallbacks) + C(EP, PM); +} +void HookManager::invokeEPCallbacks(ExtensionPoint EP, + ModulePassManager &PM) const { + for (auto &C : moduleEPCallbacks) + C(EP, PM); +} +bool HookManager::invokePassCallbacks(StringRef Name, + CGSCCPassManager &PM) const { + for (auto &C : cgsccPassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool HookManager::invokePassCallbacks(StringRef Name, + FunctionPassManager &PM) const { + for (auto &C : functionPassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool HookManager::invokePassCallbacks(StringRef Name, + LoopPassManager &PM) const { + for (auto &C : loopPassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool HookManager::invokePassCallbacks(StringRef Name, + ModulePassManager &PM) const { + for (auto &C : modulePassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool HookManager::invokePipelineCallbacks( + StringRef Name, CGSCCPassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : cgsccPipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} +bool HookManager::invokePipelineCallbacks( + StringRef Name, FunctionPassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : functionPipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} +bool HookManager::invokePipelineCallbacks( + StringRef Name, LoopPassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : loopPipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} +bool HookManager::invokePipelineCallbacks( + StringRef Name, ModulePassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : modulePipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} + void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) { #define MODULE_ANALYSIS(NAME, CREATE_PASS) \ MAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + HM.invokeAnalysisCallbacks(MAM); } void PassBuilder::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) { #define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ CGAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + HM.invokeAnalysisCallbacks(CGAM); } void PassBuilder::registerFunctionAnalyses(FunctionAnalysisManager &FAM) { #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ FAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + HM.invokeAnalysisCallbacks(FAM); } void PassBuilder::registerLoopAnalyses(LoopAnalysisManager &LAM) { #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ LAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + HM.invokeAnalysisCallbacks(LAM); } FunctionPassManager @@ -320,6 +486,7 @@ if (!isOptimizingForSize(Level)) FPM.addPass(LibCallsShrinkWrapPass()); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, FPM); FPM.addPass(TailCallElimPass()); FPM.addPass(SimplifyCFGPass()); @@ -347,8 +514,11 @@ #endif LPM2.addPass(IndVarSimplifyPass()); LPM2.addPass(LoopIdiomRecognizePass()); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::LateLoopOptimizations, + LPM2); LPM2.addPass(LoopDeletionPass()); LPM2.addPass(LoopUnrollPass::createFull(Level)); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::LoopOptimizerEnd, LPM2); // We provide the opt remark emitter pass for LICM to use. We only need to do // this once as it is immutable. @@ -384,6 +554,7 @@ // Run instcombine after redundancy and dead bit elimination to exploit // opportunities opened up by them. FPM.addPass(InstCombinePass()); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, FPM); // Re-consider control flow based optimizations after redundancy elimination, // redo DCE, etc. @@ -392,16 +563,20 @@ FPM.addPass(DSEPass()); FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass())); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::ScalarOptimizerLate, 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.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, 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) { @@ -429,9 +604,8 @@ FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies. FPM.addPass(SimplifyCFGPass()); // Merge & remove basic blocks. FPM.addPass(InstCombinePass()); // Combine silly sequences. + HM.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, 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))); @@ -463,10 +637,12 @@ // Do basic inference of function attributes from known properties of system // libraries and other oracles. MPM.addPass(InferFunctionAttrsPass()); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::ModuleOptimizerEarly, MPM); // Create an early function pass manager to cleanup the output of the // frontend. FunctionPassManager EarlyFPM(DebugLogging); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::EarlyAsPossible, EarlyFPM); EarlyFPM.addPass(SimplifyCFGPass()); EarlyFPM.addPass(SROA()); EarlyFPM.addPass(EarlyCSEPass()); @@ -499,6 +675,7 @@ // optimizations. FunctionPassManager GlobalCleanupPM(DebugLogging); GlobalCleanupPM.addPass(InstCombinePass()); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, GlobalCleanupPM); GlobalCleanupPM.addPass(SimplifyCFGPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(GlobalCleanupPM))); @@ -506,7 +683,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); } @@ -550,6 +727,8 @@ // CGSCC walk. MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor( buildFunctionSimplificationPipeline(Level, DebugLogging))); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::CGSCCOptimizerLate, + 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 @@ -596,6 +775,9 @@ // rather than on each loop in an inside-out manner, and so they are actually // function passes. + HM.invokeEPCallbacks(HookManager::ExtensionPoint::VectorizerStart, + OptimizePM); + // First rotate loops that may have been un-rotated by prior passes. OptimizePM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); @@ -664,6 +846,7 @@ // ordering here. MPM.addPass(GlobalDCEPass()); MPM.addPass(ConstantMergePass()); + HM.invokeEPCallbacks(HookManager::ExtensionPoint::OptimizerLast, MPM); return MPM; } @@ -743,8 +926,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.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, 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 @@ -761,10 +946,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.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, FPM); + FPM.addPass(JumpThreadingPass()); // Break up allocas @@ -814,8 +999,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.invokeEPCallbacks(HookManager::ExtensionPoint::Peephole, MainFPM); MainFPM.addPass(JumpThreadingPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(MainFPM))); @@ -1083,10 +1268,17 @@ MPM.addPass(createRepeatedPass(*Count, std::move(NestedMPM))); return true; } + + if (HM.invokePipelineCallbacks(Name, MPM, InnerPipeline)) + return true; + // Normal passes can't have pipelines. return false; } + if (HM.invokePassCallbacks(Name, MPM)) + return true; + // Manually handle aliases for pre-configured pipeline fragments. if (Name.startswith("default") || Name.startswith("lto")) { SmallVector Matches; @@ -1095,15 +1287,18 @@ assert(Matches.size() == 3 && "Must capture two matched strings!"); OptimizationLevel L = StringSwitch(Matches[2]) - .Case("O0", O0) - .Case("O1", O1) - .Case("O2", O2) - .Case("O3", O3) - .Case("Os", Os) - .Case("Oz", Oz); - if (L == O0) + .Case("O0", O0) + .Case("O1", O1) + .Case("O2", O2) + .Case("O3", O3) + .Case("Os", Os) + .Case("Oz", Oz); + if (L == O0) { + HM.invokeEPCallbacks(HookManager::ExtensionPoint::EnabledOnOptLevel0, + MPM); // At O0 we do nothing at all! return true; + } if (Matches[1] == "default") { MPM.addPass(buildPerModuleDefaultPipeline(L, DebugLogging)); @@ -1183,11 +1378,18 @@ *MaxRepetitions, DebugLogging)); return true; } + + if (HM.invokePipelineCallbacks(Name, CGPM, InnerPipeline)) + return true; + // Normal passes can't have pipelines. return false; } - // Now expand the basic registered passes from the .inc file. + if (HM.invokePassCallbacks(Name, CGPM)) + return true; + +// Now expand the basic registered passes from the .inc file. #define CGSCC_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ CGPM.addPass(CREATE_PASS); \ @@ -1245,11 +1447,18 @@ FPM.addPass(createRepeatedPass(*Count, std::move(NestedFPM))); return true; } + + if (HM.invokePipelineCallbacks(Name, FPM, InnerPipeline)) + return true; + // Normal passes can't have pipelines. return false; } - // Now expand the basic registered passes from the .inc file. + if (HM.invokePassCallbacks(Name, FPM)) + return true; + +// Now expand the basic registered passes from the .inc file. #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ FPM.addPass(CREATE_PASS); \ @@ -1296,11 +1505,18 @@ LPM.addPass(createRepeatedPass(*Count, std::move(NestedLPM))); return true; } + + if (HM.invokePipelineCallbacks(Name, LPM, InnerPipeline)) + return true; + // Normal passes can't have pipelines. return false; } - // Now expand the basic registered passes from the .inc file. + if (HM.invokePassCallbacks(Name, LPM)) + return true; + +// Now expand the basic registered passes from the .inc file. #define LOOP_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ LPM.addPass(CREATE_PASS); \ @@ -1325,6 +1541,9 @@ } bool PassBuilder::parseAAPassName(AAManager &AA, StringRef Name) { + if (HM.invokeAACallbacks(Name, AA)) + return true; + #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ if (Name == NAME) { \ AA.registerModuleAnalysis< \ 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,126 @@ +//===- 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 +#include +#include +#include + +using namespace llvm; + +namespace { +template +struct TestAnalysis : public AnalysisInfoMixin> { + struct Result {}; + template + Result run(IRUnitT &M, AnalysisManagerT &, ExtraTs &&... ExtraArgs) { + return Result(); + } + static AnalysisKey Key; +}; + +template +struct TestPass : 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 TestAnalysis::Key; + +template class HookManagerTest : public testing::Test {}; + +template +struct Callback { + void operator()(AnalysisManagerT &AM) const { + AM.registerPass([] { return TestAnalysis(); }); + } + bool operator()(StringRef Name, PassManagerT &PM) const { + if (HandleAnalysisUtilities>("test-analysis", Name, PM)) + return true; + + if (Name == "test-transform") { + PM.addPass(TestPass()); + return true; + } + return false; + } +}; + +template , + typename PassManagerT = PassManager> +bool PassTest() { + LLVMContext Ctx; + Module M("TestModule", Ctx); + PassBuilder PB; + ModulePassManager PM; + ModuleAnalysisManager AM; + CGSCCAnalysisManager CGAM; + FunctionAnalysisManager FAM; + LoopAnalysisManager LAM; + + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerAnalysisCallback( + Callback()); + HM.registerPassCallback(Callback()); + PB.registerModuleAnalyses(AM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + return PB.parsePassPipeline(PM, "module(test-transform)", true); +} + +TEST(HookManagerTest, Pass) { + ASSERT_TRUE(PassTest()); // FIXME test different IRUnits as well +} + +template , + typename PassManagerT = PassManager> +bool AnalysisTest() { + LLVMContext Ctx; + Module M("TestModule", Ctx); + PassBuilder PB; + ModulePassManager PM; + ModuleAnalysisManager AM; + CGSCCAnalysisManager CGAM; + FunctionAnalysisManager FAM; + LoopAnalysisManager LAM; + + auto &HM = PassBuilder::GlobalHookManager(); + HM.registerAnalysisCallback( + Callback()); + HM.registerPassCallback(Callback()); + PB.registerModuleAnalyses(AM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + return PB.parsePassPipeline( + PM, "module(require,invalidate)", true); +} +TEST(HookManagerTest, Analysis) { + ASSERT_TRUE(AnalysisTest()); // FIXME test different IRUnits as well +} +} // end anonymous namespace