Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -287,13 +287,13 @@ /// returns false. bool parseAAPipeline(AAManager &AA, StringRef PipelineText); -private: /// A struct to capture parsed pass pipeline names. struct PipelineElement { StringRef Name; std::vector InnerPipeline; }; +private: static Optional> parsePipelineText(StringRef Text); @@ -319,7 +319,204 @@ bool parseModulePassPipeline(ModulePassManager &MPM, ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); + +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; + + /// \brief Call all loaded plugins + /// + /// For all plugins regeistered with the PluginLoader, this method will call + /// the plugins' registration entrypoint, if it exists. The entrypoint is a + /// method with the extern "C" signature `void + /// RegisterPluginPasses(PassBuilder &PB)`. + /// Plugin passes can register callbacks with this PassBuilder instance. + void callPassPlugins(); + + /// {{@ Register a Callback with this pass builder instance. + 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); + /// @}} + + /// {{@ Run all registered callbacks for a given pass type + 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; }; + +/// This utility template takes care of adding require<> and invalidate<> +/// passes for an analysis to a given \c PassManager. It is intended to be used +/// during parsing of a pass pipeline when parsing a single PipelineEntry. +template +bool HandleAnalysisUtilities( + StringRef AnalysisName, 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 != AnalysisName) + 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 != AnalysisName) + return false; + PM.addPass(RequireAnalysisPass()); + return true; + } + + return false; +} } #endif Index: include/llvm/Support/PluginLoader.h =================================================================== --- include/llvm/Support/PluginLoader.h +++ include/llvm/Support/PluginLoader.h @@ -18,17 +18,18 @@ #define LLVM_SUPPORT_PLUGINLOADER_H #include "llvm/Support/CommandLine.h" +#include "llvm/Support/DynamicLibrary.h" namespace llvm { - struct PluginLoader { - void operator=(const std::string &Filename); - static unsigned getNumPlugins(); - static std::string& getPlugin(unsigned num); - }; +struct PluginLoader { + void operator=(const std::string &Filename); + static unsigned getNumPlugins(); + static std::pair &getPlugin(unsigned num); +}; #ifndef DONT_GET_PLUGIN_LOADER_OPTION - // This causes operator= above to be invoked for every -load option. - static cl::opt > +// This causes operator= above to be invoked for every -load option. +static cl::opt> LoadOpt("load", cl::ZeroOrMore, cl::value_desc("pluginfilename"), cl::desc("Load the specified plugin")); #endif Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -144,6 +144,9 @@ #include "llvm/Transforms/Vectorize/LoopVectorize.h" #include "llvm/Transforms/Vectorize/SLPVectorizer.h" +#define DONT_GET_PLUGIN_LOADER_OPTION +#include "llvm/Support/PluginLoader.h" + #include using namespace llvm; @@ -272,28 +275,200 @@ } // End anonymous namespace. +void PassBuilder::registerAnalysisCallback(const ModuleAnalysisCallback &C) { + moduleAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerPassCallback(const ModulePassCallback &C) { + modulePassCallbacks.push_back(C); +} +void PassBuilder::registerEPCallback(const ModuleEPCallback &C) { + moduleEPCallbacks.push_back(C); +} +void PassBuilder::registerPipelineCallback(const ModulePipelineCallback &C) { + modulePipelineCallbacks.push_back(C); +} +void PassBuilder::registerAnalysisCallback(const CGSCCAnalysisCallback &C) { + cgsccAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerPassCallback(const CGSCCPassCallback &C) { + cgsccPassCallbacks.push_back(C); +} +void PassBuilder::registerEPCallback(const CGSCCEPCallback &C) { + cgsccEPCallbacks.push_back(C); +} +void PassBuilder::registerPipelineCallback(const CGSCCPipelineCallback &C) { + cgsccPipelineCallbacks.push_back(C); +} +void PassBuilder::registerAnalysisCallback(const FunctionAnalysisCallback &C) { + functionAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerPassCallback(const FunctionPassCallback &C) { + functionPassCallbacks.push_back(C); +} +void PassBuilder::registerEPCallback(const FunctionEPCallback &C) { + functionEPCallbacks.push_back(C); +} +void PassBuilder::registerPipelineCallback(const FunctionPipelineCallback &C) { + functionPipelineCallbacks.push_back(C); +} +void PassBuilder::registerAnalysisCallback(const LoopAnalysisCallback &C) { + loopAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerPassCallback(const LoopPassCallback &C) { + loopPassCallbacks.push_back(C); +} +void PassBuilder::registerEPCallback(const LoopEPCallback &C) { + loopEPCallbacks.push_back(C); +} +void PassBuilder::registerPipelineCallback(const LoopPipelineCallback &C) { + loopPipelineCallbacks.push_back(C); +} +void PassBuilder::registerAACallback(const AACallback &C) { + AACallbacks.push_back(C); +} +bool PassBuilder::invokeAACallbacks(StringRef Name, AAManager &PM) const { + for (auto &C : AACallbacks) + if (C(Name, PM)) + return true; + return false; +} +void PassBuilder::invokeAnalysisCallbacks(CGSCCAnalysisManager &PM) const { + for (auto &C : cgsccAnalysisCallbacks) + C(PM); +} +void PassBuilder::invokeAnalysisCallbacks(FunctionAnalysisManager &PM) const { + for (auto &C : functionAnalysisCallbacks) + C(PM); +} +void PassBuilder::invokeAnalysisCallbacks(LoopAnalysisManager &PM) const { + for (auto &C : loopAnalysisCallbacks) + C(PM); +} +void PassBuilder::invokeAnalysisCallbacks(ModuleAnalysisManager &PM) const { + for (auto &C : moduleAnalysisCallbacks) + C(PM); +} +void PassBuilder::invokeEPCallbacks(ExtensionPoint EP, + CGSCCPassManager &PM) const { + for (auto &C : cgsccEPCallbacks) + C(EP, PM); +} +void PassBuilder::invokeEPCallbacks(ExtensionPoint EP, + FunctionPassManager &PM) const { + for (auto &C : functionEPCallbacks) + C(EP, PM); +} +void PassBuilder::invokeEPCallbacks(ExtensionPoint EP, + LoopPassManager &PM) const { + for (auto &C : loopEPCallbacks) + C(EP, PM); +} +void PassBuilder::invokeEPCallbacks(ExtensionPoint EP, + ModulePassManager &PM) const { + for (auto &C : moduleEPCallbacks) + C(EP, PM); +} +bool PassBuilder::invokePassCallbacks(StringRef Name, + CGSCCPassManager &PM) const { + for (auto &C : cgsccPassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool PassBuilder::invokePassCallbacks(StringRef Name, + FunctionPassManager &PM) const { + for (auto &C : functionPassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool PassBuilder::invokePassCallbacks(StringRef Name, + LoopPassManager &PM) const { + for (auto &C : loopPassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool PassBuilder::invokePassCallbacks(StringRef Name, + ModulePassManager &PM) const { + for (auto &C : modulePassCallbacks) + if (C(Name, PM)) + return true; + return false; +} +bool PassBuilder::invokePipelineCallbacks( + StringRef Name, CGSCCPassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : cgsccPipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} +bool PassBuilder::invokePipelineCallbacks( + StringRef Name, FunctionPassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : functionPipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} +bool PassBuilder::invokePipelineCallbacks( + StringRef Name, LoopPassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : loopPipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} +bool PassBuilder::invokePipelineCallbacks( + StringRef Name, ModulePassManager &PM, + ArrayRef Pipeline) const { + for (auto &C : modulePipelineCallbacks) + if (C(Name, PM, Pipeline)) + return true; + return false; +} + +void PassBuilder::callPassPlugins() { + using EntrypointT = void (*)(PassBuilder &); + for (unsigned i = 0; i < PluginLoader::getNumPlugins(); ++i) { + auto &lib = PluginLoader::getPlugin(i).second; + auto *entrypoint = lib.getAddressOfSymbol("RegisterPluginPasses"); + if (entrypoint) + reinterpret_cast(entrypoint)(*this); + } +} + void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) { #define MODULE_ANALYSIS(NAME, CREATE_PASS) \ MAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + invokeAnalysisCallbacks(MAM); } void PassBuilder::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) { #define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ CGAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + invokeAnalysisCallbacks(CGAM); } void PassBuilder::registerFunctionAnalyses(FunctionAnalysisManager &FAM) { #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ FAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + invokeAnalysisCallbacks(FAM); } void PassBuilder::registerLoopAnalyses(LoopAnalysisManager &LAM) { #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ LAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + invokeAnalysisCallbacks(LAM); } FunctionPassManager @@ -320,6 +495,7 @@ if (!isOptimizingForSize(Level)) FPM.addPass(LibCallsShrinkWrapPass()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::Peephole, FPM); FPM.addPass(TailCallElimPass()); FPM.addPass(SimplifyCFGPass()); @@ -347,8 +523,10 @@ #endif LPM2.addPass(IndVarSimplifyPass()); LPM2.addPass(LoopIdiomRecognizePass()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::LateLoopOptimizations, LPM2); LPM2.addPass(LoopDeletionPass()); LPM2.addPass(LoopUnrollPass::createFull(Level)); + invokeEPCallbacks(PassBuilder::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 +562,7 @@ // Run instcombine after redundancy and dead bit elimination to exploit // opportunities opened up by them. FPM.addPass(InstCombinePass()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::Peephole, FPM); // Re-consider control flow based optimizations after redundancy elimination, // redo DCE, etc. @@ -392,16 +571,20 @@ FPM.addPass(DSEPass()); FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass())); + invokeEPCallbacks(PassBuilder::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()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::Peephole, FPM); return FPM; } -static void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, +static void addPGOInstrPasses(const PassBuilder &PB, ModulePassManager &MPM, + bool DebugLogging, PassBuilder::OptimizationLevel Level, bool RunProfileGen, std::string ProfileGenFile, std::string ProfileUseFile) { @@ -429,9 +612,8 @@ FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies. FPM.addPass(SimplifyCFGPass()); // Merge & remove basic blocks. FPM.addPass(InstCombinePass()); // Combine silly sequences. + PB.invokeEPCallbacks(PassBuilder::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 +645,12 @@ // Do basic inference of function attributes from known properties of system // libraries and other oracles. MPM.addPass(InferFunctionAttrsPass()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::ModuleOptimizerEarly, MPM); // Create an early function pass manager to cleanup the output of the // frontend. FunctionPassManager EarlyFPM(DebugLogging); + invokeEPCallbacks(PassBuilder::ExtensionPoint::EarlyAsPossible, EarlyFPM); EarlyFPM.addPass(SimplifyCFGPass()); EarlyFPM.addPass(SROA()); EarlyFPM.addPass(EarlyCSEPass()); @@ -499,6 +683,7 @@ // optimizations. FunctionPassManager GlobalCleanupPM(DebugLogging); GlobalCleanupPM.addPass(InstCombinePass()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::Peephole, GlobalCleanupPM); GlobalCleanupPM.addPass(SimplifyCFGPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(GlobalCleanupPM))); @@ -506,7 +691,7 @@ if (PGOOpt) { assert(PGOOpt->RunProfileGen || PGOOpt->SamplePGO || !PGOOpt->ProfileUseFile.empty()); - addPGOInstrPasses(MPM, DebugLogging, Level, PGOOpt->RunProfileGen, + addPGOInstrPasses(*this, MPM, DebugLogging, Level, PGOOpt->RunProfileGen, PGOOpt->ProfileGenFile, PGOOpt->ProfileUseFile); } @@ -550,6 +735,8 @@ // CGSCC walk. MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor( buildFunctionSimplificationPipeline(Level, DebugLogging))); + invokeEPCallbacks(PassBuilder::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 +783,8 @@ // rather than on each loop in an inside-out manner, and so they are actually // function passes. + invokeEPCallbacks(PassBuilder::ExtensionPoint::VectorizerStart, OptimizePM); + // First rotate loops that may have been un-rotated by prior passes. OptimizePM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); @@ -664,6 +853,7 @@ // ordering here. MPM.addPass(GlobalDCEPass()); MPM.addPass(ConstantMergePass()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::OptimizerLast, MPM); return MPM; } @@ -743,8 +933,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()); + invokeEPCallbacks(PassBuilder::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 +953,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()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::Peephole, FPM); + FPM.addPass(JumpThreadingPass()); // Break up allocas @@ -814,8 +1006,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()); + invokeEPCallbacks(PassBuilder::ExtensionPoint::Peephole, MainFPM); MainFPM.addPass(JumpThreadingPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(MainFPM))); @@ -1083,10 +1275,17 @@ MPM.addPass(createRepeatedPass(*Count, std::move(NestedMPM))); return true; } + + if (invokePipelineCallbacks(Name, MPM, InnerPipeline)) + return true; + // Normal passes can't have pipelines. return false; } + if (invokePassCallbacks(Name, MPM)) + return true; + // Manually handle aliases for pre-configured pipeline fragments. if (Name.startswith("default") || Name.startswith("lto")) { SmallVector Matches; @@ -1095,15 +1294,17 @@ 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) { + invokeEPCallbacks(PassBuilder::ExtensionPoint::EnabledOnOptLevel0, MPM); // At O0 we do nothing at all! return true; + } if (Matches[1] == "default") { MPM.addPass(buildPerModuleDefaultPipeline(L, DebugLogging)); @@ -1183,11 +1384,18 @@ *MaxRepetitions, DebugLogging)); return true; } + + if (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 (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 +1453,18 @@ FPM.addPass(createRepeatedPass(*Count, std::move(NestedFPM))); return true; } + + if (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 (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 +1511,18 @@ LPM.addPass(createRepeatedPass(*Count, std::move(NestedLPM))); return true; } + + if (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 (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 +1547,9 @@ } bool PassBuilder::parseAAPassName(AAManager &AA, StringRef Name) { + if (invokeAACallbacks(Name, AA)) + return true; + #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ if (Name == NAME) { \ AA.registerModuleAnalysis< \ Index: lib/Support/PluginLoader.cpp =================================================================== --- lib/Support/PluginLoader.cpp +++ lib/Support/PluginLoader.cpp @@ -20,17 +20,19 @@ #include using namespace llvm; -static ManagedStatic > Plugins; -static ManagedStatic > PluginsLock; +static ManagedStatic>> + Plugins; +static ManagedStatic> PluginsLock; void PluginLoader::operator=(const std::string &Filename) { sys::SmartScopedLock Lock(*PluginsLock); std::string Error; - if (sys::DynamicLibrary::LoadLibraryPermanently(Filename.c_str(), &Error)) { + auto lib = sys::DynamicLibrary::getPermanentLibrary(Filename.c_str(), &Error); + if (!lib.isValid()) { errs() << "Error opening '" << Filename << "': " << Error << "\n -load request ignored.\n"; } else { - Plugins->push_back(Filename); + Plugins->push_back({Filename, std::move(lib)}); } } @@ -39,7 +41,8 @@ return Plugins.isConstructed() ? Plugins->size() : 0; } -std::string &PluginLoader::getPlugin(unsigned num) { +std::pair & +PluginLoader::getPlugin(unsigned num) { sys::SmartScopedLock Lock(*PluginsLock); assert(Plugins.isConstructed() && num < Plugins->size() && "Asking for an out of bounds plugin"); 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: tools/bugpoint/OptimizerDriver.cpp =================================================================== --- tools/bugpoint/OptimizerDriver.cpp +++ tools/bugpoint/OptimizerDriver.cpp @@ -106,7 +106,7 @@ outs() << "valgrind "; outs() << "opt " << Filename; for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) { - outs() << " -load " << PluginLoader::getPlugin(i); + outs() << " -load " << PluginLoader::getPlugin(i).first; } outs() << " " << getPassesString(PassesToRun) << "\n"; } @@ -210,7 +210,7 @@ std::vector pass_args; for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) { pass_args.push_back(std::string("-load")); - pass_args.push_back(PluginLoader::getPlugin(i)); + pass_args.push_back(PluginLoader::getPlugin(i).first); } for (std::vector::const_iterator I = Passes.begin(), E = Passes.end(); Index: tools/opt/NewPMDriver.cpp =================================================================== --- tools/opt/NewPMDriver.cpp +++ tools/opt/NewPMDriver.cpp @@ -47,14 +47,23 @@ "pipeline for handling managed aliasing queries"), cl::Hidden); -bool llvm::runPassPipeline(StringRef Arg0, Module &M, - TargetMachine *TM, tool_output_file *Out, - StringRef PassPipeline, OutputKind OK, - VerifierKind VK, +#ifdef LINK_POLLY_INTO_TOOLS +namespace polly { +void RegisterPollyPasses(PassBuilder &); +} +#endif + +bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, + tool_output_file *Out, StringRef PassPipeline, + OutputKind OK, VerifierKind VK, bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash) { PassBuilder PB(TM); + PB.callPassPlugins(); +#ifdef LINK_POLLY_INTO_TOOLS + polly::RegisterPollyPasses(PB); +#endif // Specially handle the alias analysis manager so that we can register // a custom pipeline of AA passes with it. 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,124 @@ +//===- 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; + + PB.registerAnalysisCallback( + Callback()); + PB.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; + + PB.registerAnalysisCallback( + Callback()); + PB.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