Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -46,6 +46,12 @@ Optional PGOOpt; public: + /// A struct to capture parsed pass pipeline names. + struct PipelineElement { + StringRef Name; + std::vector InnerPipeline; + }; + /// \brief LLVM-provided high-level optimization levels. /// /// This enumerates the LLVM-provided high-level optimization levels. Each @@ -132,6 +138,37 @@ Oz }; + template + using EPCallbackT = std::function; + template + using ParsePipelineCallbackT = + std::function Pipeline)>; + template + using RegisterAnalysisCallbackT = std::function; + + using ParseAACallbackT = std::function; + using RegisterCGSCCAnalysisCallbackT = + RegisterAnalysisCallbackT; + using CGSCCEPCallbackT = EPCallbackT; + using ParseCGSCCPipelineCallbackT = ParsePipelineCallbackT; + using RegisterFunctionAnalysisCallbackT = + RegisterAnalysisCallbackT; + using FunctionEPCallbackT = EPCallbackT; + using ParseFunctionPipelineCallbackT = + ParsePipelineCallbackT; + using RegisterLoopAnalysisCallbackT = + RegisterAnalysisCallbackT; + using LoopEPCallbackT = EPCallbackT; + using ParseLoopPipelineCallbackT = ParsePipelineCallbackT; + using RegisterModuleAnalysisCallbackT = + RegisterAnalysisCallbackT; + using ModuleEPCallbackT = EPCallbackT; + using ParseModulePipelineCallbackT = + ParsePipelineCallbackT; + using ParseTopLevelPipelineCallbackT = + std::function)>; + explicit PassBuilder(TargetMachine *TM = nullptr, Optional PGOOpt = None) : TM(TM), PGOOpt(PGOOpt) {} @@ -287,13 +324,97 @@ /// returns false. bool parseAAPipeline(AAManager &AA, StringRef PipelineText); -private: - /// A struct to capture parsed pass pipeline names. - struct PipelineElement { - StringRef Name; - std::vector InnerPipeline; - }; + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// ModuleOptimizerEarly - This extension point allows adding passes + /// just before the main module-level optimization passes. + void registerModuleOptimizerEarlyEPCallback(const ModuleEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// 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. + void registerEarlyAsPossibleEPCallback(const FunctionEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// 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. + void registerPeepholeEPCallback(const FunctionEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// 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. + void registerLateLoopOptimizationsEPCallback(const LoopEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// LoopOptimizerEnd - This extension point allows adding loop passes to + /// the end of the loop optimizer. + void registerLoopOptimizerEndEPCallback(const LoopEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// ScalarOptimizerLate - This extension point allows adding optimization + /// passes after most of the main optimizations, but before the last + /// cleanup-ish optimizations. + void registerScalarOptimizerLateEPCallback(const FunctionEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// 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. + void registerCGSCCOptimizerLateEPCallback(const CGSCCEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// VectorizerStart - This extension point allows adding optimization + /// passes before the vectorizer and other highly target specific + /// optimization passes are executed. + void registerVectorizerStartEPCallback(const FunctionEPCallbackT &); + + /// \brief Register a callback for a default optimizer pipeline extension + /// point + /// + /// OptimizerLast -- This extension point allows adding passes that + /// run after everything else. + void registerOptimizerLastEPCallback(const ModuleEPCallbackT &); + + /// {{@ Register generic callbacks with this pass builder instance. + void registerParseAACallback(const ParseAACallbackT &C); + void + registerRegisterAnalysisCallback(const RegisterCGSCCAnalysisCallbackT &C); + void + registerRegisterAnalysisCallback(const RegisterFunctionAnalysisCallbackT &C); + void registerRegisterAnalysisCallback(const RegisterLoopAnalysisCallbackT &C); + void + registerRegisterAnalysisCallback(const RegisterModuleAnalysisCallbackT &C); + void registerParsePipelineCallback(const ParseCGSCCPipelineCallbackT &C); + void registerParsePipelineCallback(const ParseFunctionPipelineCallbackT &C); + void registerParsePipelineCallback(const ParseLoopPipelineCallbackT &C); + void registerParsePipelineCallback(const ParseModulePipelineCallbackT &C); + void registerParseTopLevelPipelineCallback( + const ParseTopLevelPipelineCallbackT &C); + /// @}} +private: static Optional> parsePipelineText(StringRef Text); @@ -319,7 +440,83 @@ bool parseModulePassPipeline(ModulePassManager &MPM, ArrayRef Pipeline, bool VerifyEachPass, bool DebugLogging); + + void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, + OptimizationLevel Level, bool RunProfileGen, + std::string ProfileGenFile, + std::string ProfileUseFile); + + // EP callbacks + SmallVector ModuleOptimizerEarlyEPCallbacks; + SmallVector EarlyAsPossibleEPCallbacks; + SmallVector PeepholeEPCallbacks; + SmallVector LateLoopOptimizationsEPCallbacks; + SmallVector LoopOptimizerEndEPCallbacks; + SmallVector ScalarOptimizerLateEPCallbacks; + SmallVector CGSCCOptimizerLateEPCallbacks; + SmallVector VectorizerStartEPCallbacks; + SmallVector OptimizerLastEPCallbacks; + // Module callbacks + SmallVector + RegisterModuleAnalysisCallbacks; + SmallVector ParseModulePipelineCallbacks; + SmallVector ParseTopLevelPipelineCallbacks; + // CGSCC callbacks + SmallVector RegisterCGSCCAnalysisCallbacks; + SmallVector ParseCGSCCPipelineCallbacks; + // Function callbacks + SmallVector + RegisterFunctionAnalysisCallbacks; + SmallVector ParseFunctionPipelineCallbacks; + // Loop callbacks + SmallVector RegisterLoopAnalysisCallbacks; + SmallVector ParseLoopPipelineCallbacks; + // AA callbacks + SmallVector ParseAACallbacks; }; + +/// 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 PipelineName. +/// When registering a new function analysis FancyAnalysis with the pass +/// pipeline name "fancy-analysis", a matching ParsePipelineCallback could look +/// like this: +/// +/// static bool parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM, +/// ArrayRef P) { +/// if (parseAnalysisUtilityPasses("fancy-analysis", Name, +/// FPM)) +/// return true; +/// return false; +/// } +template +bool parseAnalysisUtilityPasses( + StringRef AnalysisName, StringRef PipelineName, + PassManager &PM) { + if (!PipelineName.endswith(">")) + return false; + // See if this is an invalidate<> pass name + if (PipelineName.startswith("invalidate<")) { + PipelineName = PipelineName.substr(11, PipelineName.size() - 12); + if (PipelineName != AnalysisName) + return false; + PM.addPass(InvalidateAnalysisPass()); + return true; + } + + // See if this is a require<> pass name + if (PipelineName.startswith("require<")) { + PipelineName = PipelineName.substr(8, PipelineName.size() - 9); + if (PipelineName != AnalysisName) + 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,114 @@ } // End anonymous namespace. +void PassBuilder::registerEarlyAsPossibleEPCallback( + const FunctionEPCallbackT &C) { + EarlyAsPossibleEPCallbacks.push_back(C); +} +void PassBuilder::registerModuleOptimizerEarlyEPCallback( + const ModuleEPCallbackT &C) { + ModuleOptimizerEarlyEPCallbacks.push_back(C); +} +void PassBuilder::registerLoopOptimizerEndEPCallback(const LoopEPCallbackT &C) { + LoopOptimizerEndEPCallbacks.push_back(C); +} +void PassBuilder::registerScalarOptimizerLateEPCallback( + const FunctionEPCallbackT &C) { + ScalarOptimizerLateEPCallbacks.push_back(C); +} +void PassBuilder::registerOptimizerLastEPCallback(const ModuleEPCallbackT &C) { + OptimizerLastEPCallbacks.push_back(C); +} +void PassBuilder::registerVectorizerStartEPCallback( + const FunctionEPCallbackT &C) { + VectorizerStartEPCallbacks.push_back(C); +} +void PassBuilder::registerPeepholeEPCallback(const FunctionEPCallbackT &C) { + PeepholeEPCallbacks.push_back(C); +} +void PassBuilder::registerLateLoopOptimizationsEPCallback( + const LoopEPCallbackT &C) { + LateLoopOptimizationsEPCallbacks.push_back(C); +} +void PassBuilder::registerCGSCCOptimizerLateEPCallback( + const CGSCCEPCallbackT &C) { + CGSCCOptimizerLateEPCallbacks.push_back(C); +} + +void PassBuilder::registerRegisterAnalysisCallback( + const RegisterModuleAnalysisCallbackT &C) { + RegisterModuleAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerParsePipelineCallback( + const ParseModulePipelineCallbackT &C) { + ParseModulePipelineCallbacks.push_back(C); +} +void PassBuilder::registerRegisterAnalysisCallback( + const RegisterCGSCCAnalysisCallbackT &C) { + RegisterCGSCCAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerParsePipelineCallback( + const ParseCGSCCPipelineCallbackT &C) { + ParseCGSCCPipelineCallbacks.push_back(C); +} +void PassBuilder::registerRegisterAnalysisCallback( + const RegisterFunctionAnalysisCallbackT &C) { + RegisterFunctionAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerParsePipelineCallback( + const ParseFunctionPipelineCallbackT &C) { + ParseFunctionPipelineCallbacks.push_back(C); +} +void PassBuilder::registerRegisterAnalysisCallback( + const RegisterLoopAnalysisCallbackT &C) { + RegisterLoopAnalysisCallbacks.push_back(C); +} +void PassBuilder::registerParsePipelineCallback( + const ParseLoopPipelineCallbackT &C) { + ParseLoopPipelineCallbacks.push_back(C); +} +void PassBuilder::registerParseTopLevelPipelineCallback( + const ParseTopLevelPipelineCallbackT &C) { + ParseTopLevelPipelineCallbacks.push_back(C); +} +void PassBuilder::registerParseAACallback(const ParseAACallbackT &C) { + ParseAACallbacks.push_back(C); +} + void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) { #define MODULE_ANALYSIS(NAME, CREATE_PASS) \ MAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + for (auto &C : RegisterModuleAnalysisCallbacks) + C(MAM); } void PassBuilder::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) { #define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ CGAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + for (auto &C : RegisterCGSCCAnalysisCallbacks) + C(CGAM); } void PassBuilder::registerFunctionAnalyses(FunctionAnalysisManager &FAM) { #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ FAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + for (auto &C : RegisterFunctionAnalysisCallbacks) + C(FAM); } void PassBuilder::registerLoopAnalyses(LoopAnalysisManager &LAM) { #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ LAM.registerPass([&] { return CREATE_PASS; }); #include "PassRegistry.def" + + for (auto &C : RegisterLoopAnalysisCallbacks) + C(LAM); } FunctionPassManager @@ -321,6 +407,9 @@ if (!isOptimizingForSize(Level)) FPM.addPass(LibCallsShrinkWrapPass()); + for (auto &C : PeepholeEPCallbacks) + C(FPM, Level); + FPM.addPass(TailCallElimPass()); FPM.addPass(SimplifyCFGPass()); @@ -344,9 +433,16 @@ LPM1.addPass(SimpleLoopUnswitchPass()); LPM2.addPass(IndVarSimplifyPass()); LPM2.addPass(LoopIdiomRecognizePass()); + + for (auto &C : LateLoopOptimizationsEPCallbacks) + C(LPM2, Level); + LPM2.addPass(LoopDeletionPass()); LPM2.addPass(LoopUnrollPass::createFull(Level)); + for (auto &C : LoopOptimizerEndEPCallbacks) + C(LPM2, Level); + // We provide the opt remark emitter pass for LICM to use. We only need to do // this once as it is immutable. FPM.addPass(RequireAnalysisPass()); @@ -382,6 +478,9 @@ // opportunities opened up by them. FPM.addPass(InstCombinePass()); + for (auto &C : PeepholeEPCallbacks) + C(FPM, Level); + // Re-consider control flow based optimizations after redundancy elimination, // redo DCE, etc. FPM.addPass(JumpThreadingPass()); @@ -389,19 +488,26 @@ FPM.addPass(DSEPass()); FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass())); + for (auto &C : ScalarOptimizerLateEPCallbacks) + C(FPM, Level); + // 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()); + for (auto &C : PeepholeEPCallbacks) + C(FPM, Level); + return FPM; } -static void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, - PassBuilder::OptimizationLevel Level, - bool RunProfileGen, std::string ProfileGenFile, - std::string ProfileUseFile) { +void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, + PassBuilder::OptimizationLevel Level, + bool RunProfileGen, + std::string ProfileGenFile, + std::string ProfileUseFile) { // Generally running simplification passes and the inliner with an high // threshold results in smaller executables, but there may be cases where // the size grows, so let's be conservative here and skip this simplification @@ -427,8 +533,9 @@ FPM.addPass(SimplifyCFGPass()); // Merge & remove basic blocks. FPM.addPass(InstCombinePass()); // Combine silly sequences. - // FIXME: Here the old pass manager inserts peephole extensions. - // Add them when they're supported. + for (auto &C : PeepholeEPCallbacks) + C(FPM, Level); + CGPipeline.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPipeline))); @@ -466,9 +573,16 @@ // libraries and other oracles. MPM.addPass(InferFunctionAttrsPass()); + for (auto &C : ModuleOptimizerEarlyEPCallbacks) + C(MPM, Level); + // Create an early function pass manager to cleanup the output of the // frontend. FunctionPassManager EarlyFPM(DebugLogging); + + for (auto &C : EarlyAsPossibleEPCallbacks) + C(EarlyFPM, Level); + EarlyFPM.addPass(SimplifyCFGPass()); EarlyFPM.addPass(SROA()); EarlyFPM.addPass(EarlyCSEPass()); @@ -501,6 +615,10 @@ // optimizations. FunctionPassManager GlobalCleanupPM(DebugLogging); GlobalCleanupPM.addPass(InstCombinePass()); + + for (auto &C : PeepholeEPCallbacks) + C(GlobalCleanupPM, Level); + GlobalCleanupPM.addPass(SimplifyCFGPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(GlobalCleanupPM))); @@ -553,6 +671,9 @@ MainCGPipeline.addPass(createCGSCCToFunctionPassAdaptor( buildFunctionSimplificationPipeline(Level, DebugLogging))); + for (auto &C : CGSCCOptimizerLateEPCallbacks) + C(MainCGPipeline, Level); + // We wrap the CGSCC pipeline in a devirtualization repeater. This will try // to detect when we devirtualize indirect calls and iterate the SCC passes // in that case to try and catch knock-on inlining or function attrs @@ -598,6 +719,9 @@ // rather than on each loop in an inside-out manner, and so they are actually // function passes. + for (auto &C : VectorizerStartEPCallbacks) + C(OptimizePM, Level); + // First rotate loops that may have been un-rotated by prior passes. OptimizePM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); @@ -667,6 +791,9 @@ MPM.addPass(GlobalDCEPass()); MPM.addPass(ConstantMergePass()); + for (auto &C : OptimizerLastEPCallbacks) + C(MPM, Level); + return MPM; } @@ -745,8 +872,13 @@ // 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()); + + for (auto &C : PeepholeEPCallbacks) + C(SimplifyFPM, Level); + + 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 @@ -763,10 +895,12 @@ 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()); + + for (auto &C : PeepholeEPCallbacks) + C(FPM, Level); + FPM.addPass(JumpThreadingPass()); // Break up allocas @@ -816,8 +950,10 @@ // 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()); + + for (auto &C : PeepholeEPCallbacks) + C(MainFPM, Level); MainFPM.addPass(JumpThreadingPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(MainFPM))); @@ -1085,9 +1221,15 @@ MPM.addPass(createRepeatedPass(*Count, std::move(NestedMPM))); return true; } + } + + for (auto &C : ParseModulePipelineCallbacks) + if (C(Name, MPM, InnerPipeline)) + return true; + + if (!InnerPipeline.empty()) // Normal passes can't have pipelines. return false; - } // Manually handle aliases for pre-configured pipeline fragments. if (Name.startswith("default") || Name.startswith("lto")) { @@ -1097,15 +1239,20 @@ 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) { + + for (auto &C : OptimizerLastEPCallbacks) + C(MPM, L); + // At O0 we do nothing at all! return true; + } if (Matches[1] == "default") { MPM.addPass(buildPerModuleDefaultPipeline(L, DebugLogging)); @@ -1185,11 +1332,17 @@ *MaxRepetitions, DebugLogging)); return true; } - // Normal passes can't have pipelines. - return false; } - // Now expand the basic registered passes from the .inc file. + for (auto &C : ParseCGSCCPipelineCallbacks) + if (C(Name, CGPM, InnerPipeline)) + return true; + + // Normal passes can't have pipelines. + if (InnerPipeline.empty()) + return false; + +// Now expand the basic registered passes from the .inc file. #define CGSCC_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ CGPM.addPass(CREATE_PASS); \ @@ -1247,11 +1400,17 @@ FPM.addPass(createRepeatedPass(*Count, std::move(NestedFPM))); return true; } + } + + for (auto &C : ParseFunctionPipelineCallbacks) + if (C(Name, FPM, InnerPipeline)) + return true; + + if (!InnerPipeline.empty()) // Normal passes can't have pipelines. return false; - } - // Now expand the basic registered passes from the .inc file. +// Now expand the basic registered passes from the .inc file. #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ FPM.addPass(CREATE_PASS); \ @@ -1298,11 +1457,17 @@ LPM.addPass(createRepeatedPass(*Count, std::move(NestedLPM))); return true; } + } + + for (auto &C : ParseLoopPipelineCallbacks) + if (C(Name, LPM, InnerPipeline)) + return true; + + if (!InnerPipeline.empty()) // Normal passes can't have pipelines. return false; - } - // Now expand the basic registered passes from the .inc file. +// Now expand the basic registered passes from the .inc file. #define LOOP_PASS(NAME, CREATE_PASS) \ if (Name == NAME) { \ LPM.addPass(CREATE_PASS); \ @@ -1327,6 +1492,10 @@ } bool PassBuilder::parseAAPassName(AAManager &AA, StringRef Name) { + for (auto &C : ParseAACallbacks) + if (C(Name, AA)) + return true; + #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ if (Name == NAME) { \ AA.registerModuleAnalysis< \ @@ -1428,9 +1597,15 @@ Pipeline = {{"function", std::move(*Pipeline)}}; else if (isLoopPassName(FirstName)) Pipeline = {{"function", {{"loop", std::move(*Pipeline)}}}}; - else + else { + + for (auto &C : ParseTopLevelPipelineCallbacks) + if (C(MPM, *Pipeline)) + return true; + // Unknown pass name! return false; + } } return parseModulePassPipeline(MPM, *Pipeline, VerifyEachPass, DebugLogging); 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/opt/NewPMDriver.cpp =================================================================== --- tools/opt/NewPMDriver.cpp +++ tools/opt/NewPMDriver.cpp @@ -48,6 +48,12 @@ "pipeline for handling managed aliasing queries"), cl::Hidden); +#ifdef LINK_POLLY_INTO_TOOLS +namespace polly { +void RegisterPollyPasses(PassBuilder &); +} +#endif + bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, tool_output_file *Out, tool_output_file *ThinLTOLinkOut, @@ -57,6 +63,9 @@ bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash) { PassBuilder PB(TM); +#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 @@ -15,6 +16,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,128 @@ +//===- 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, + ArrayRef InnerPipeline) const { + if (parseAnalysisUtilityPasses>("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.registerRegisterAnalysisCallback( + Callback()); + PB.registerParsePipelineCallback( + 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.registerRegisterAnalysisCallback( + Callback()); + PB.registerParsePipelineCallback( + 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