Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ include/llvm/Passes/PassBuilder.h @@ -46,6 +46,19 @@ Optional PGOOpt; public: + /// \brief A struct to capture parsed pass pipeline names. + /// + /// A pipeline is defined as a series of names, each of which may in itself + /// recursively contain a nested pipeline. A name is either the name of a pass + /// (e.g. "instcombine") or the name of a pipeline type (e.g. "cgscc"). If the + /// name is the name of a pass, the InnerPipeline is empty, since passes + /// cannot contain inner pipelines. See parsePassPipeline() for a more + /// detailed description of the textual pipeline format. + struct PipelineElement { + StringRef Name; + std::vector InnerPipeline; + }; + /// \brief LLVM-provided high-level optimization levels. /// /// This enumerates the LLVM-provided high-level optimization levels. Each @@ -333,6 +346,22 @@ bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, bool VerifyEachPass = true, bool DebugLogging = false); + /// {{@ + /// \brief Parse a tokenized Pipeline description into a given PassManager + bool parseLoopPassPipeline(LoopPassManager &LPM, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); + bool parseFunctionPassPipeline(FunctionPassManager &FPM, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); + bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); + bool parseModulePassPipeline(ModulePassManager &MPM, + ArrayRef Pipeline, + bool VerifyEachPass, bool DebugLogging); + /// @}} + /// Parse a textual alias analysis pipeline into the provided AA manager. /// /// The format of the textual AA pipeline is a comma separated list of AA @@ -350,13 +379,168 @@ /// 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 std::function &) { + ModuleOptimizerEarlyEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + EarlyAsPossibleEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + PeepholeEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + LateLoopOptimizationsEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + LoopOptimizerEndEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + ScalarOptimizerLateEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + CGSCCOptimizerLateEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + VectorizerStartEPCallbacks.push_back(C); + } + + /// \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 std::function &) { + OptimizerLastEPCallbacks.push_back(C); + } + + /// \brief Register a callback for an AA Name + void registerParseAACallback( + const std::function &C) { + ParseAACallbacks.push_back(C); + } + + /// \brief Register a callback for a top-level pipeline entry. + /// + /// If the PassManager type is not given at the top level of the pipeline + /// text, this Callback should be used to determine the appropriate stack of + /// PassManagers and populate the passed ModulePassManager. + void registerParseTopLevelPipelineCallback( + const std::function, bool VerifyEachPass, + bool DebugLogging)> &C) { + ParseTopLevelPipelineCallbacks.push_back(C); + } + + /// {{@ Register callbacks for analysis registration with this PassBuilder + /// instance + void registerRegisterAnalysisCallback( + const std::function &C) { + RegisterCGSCCAnalysisCallbacks.push_back(C); + } + void registerRegisterAnalysisCallback( + const std::function &C) { + RegisterFunctionAnalysisCallbacks.push_back(C); + } + void registerRegisterAnalysisCallback( + const std::function &C) { + RegisterLoopAnalysisCallbacks.push_back(C); + } + void registerRegisterAnalysisCallback( + const std::function &C) { + RegisterModuleAnalysisCallbacks.push_back(C); + } + /// @}} + + /// {{@ Register pipeline parsing callbacks with this pass builder instance. + void registerParsePipelineCallback( + const std::function)> &C) { + ParseCGSCCPipelineCallbacks.push_back(C); + } + void registerParsePipelineCallback( + const std::function)> &C) { + ParseFunctionPipelineCallbacks.push_back(C); + } + void registerParsePipelineCallback( + const std::function)> &C) { + ParseLoopPipelineCallbacks.push_back(C); + } + void registerParsePipelineCallback( + const std::function)> &C) { + ParseModulePipelineCallbacks.push_back(C); + } + /// @}} +private: static Optional> parsePipelineText(StringRef Text); @@ -370,19 +554,112 @@ bool VerifyEachPass, bool DebugLogging); bool parseAAPassName(AAManager &AA, StringRef Name); - bool parseLoopPassPipeline(LoopPassManager &LPM, - ArrayRef Pipeline, - bool VerifyEachPass, bool DebugLogging); - bool parseFunctionPassPipeline(FunctionPassManager &FPM, - ArrayRef Pipeline, - bool VerifyEachPass, bool DebugLogging); - bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, - ArrayRef Pipeline, - bool VerifyEachPass, bool DebugLogging); - 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); + + void invokePeepholeEPCallbacks(FunctionPassManager &, OptimizationLevel); + + // EP callbacks + SmallVector, 2> + ModuleOptimizerEarlyEPCallbacks; + SmallVector, 2> + EarlyAsPossibleEPCallbacks; + SmallVector, 2> + PeepholeEPCallbacks; + SmallVector, 2> + LateLoopOptimizationsEPCallbacks; + SmallVector, 2> + LoopOptimizerEndEPCallbacks; + SmallVector, 2> + ScalarOptimizerLateEPCallbacks; + SmallVector, 2> + CGSCCOptimizerLateEPCallbacks; + SmallVector, 2> + VectorizerStartEPCallbacks; + SmallVector, 2> + OptimizerLastEPCallbacks; + // Module callbacks + SmallVector, 2> + RegisterModuleAnalysisCallbacks; + SmallVector)>, + 2> + ParseModulePipelineCallbacks; + SmallVector, bool VerifyEachPass, + bool DebugLogging)>, + 2> + ParseTopLevelPipelineCallbacks; + // CGSCC callbacks + SmallVector, 2> + RegisterCGSCCAnalysisCallbacks; + SmallVector)>, + 2> + ParseCGSCCPipelineCallbacks; + // Function callbacks + SmallVector, 2> + RegisterFunctionAnalysisCallbacks; + SmallVector)>, + 2> + ParseFunctionPipelineCallbacks; + // Loop callbacks + SmallVector, 2> + RegisterLoopAnalysisCallbacks; + SmallVector)>, + 2> + ParseLoopPipelineCallbacks; + // AA callbacks + SmallVector, 2> + 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 @@ -273,28 +273,46 @@ } // End anonymous namespace. +void PassBuilder::invokePeepholeEPCallbacks( + FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { + for (auto &C : PeepholeEPCallbacks) + C(FPM, Level); +} + 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 @@ -326,6 +344,8 @@ if (!isOptimizingForSize(Level)) FPM.addPass(LibCallsShrinkWrapPass()); + invokePeepholeEPCallbacks(FPM, Level); + FPM.addPass(TailCallElimPass()); FPM.addPass(SimplifyCFGPass()); @@ -349,12 +369,19 @@ LPM1.addPass(SimpleLoopUnswitchPass()); LPM2.addPass(IndVarSimplifyPass()); LPM2.addPass(LoopIdiomRecognizePass()); + + for (auto &C : LateLoopOptimizationsEPCallbacks) + C(LPM2, Level); + LPM2.addPass(LoopDeletionPass()); // FIXME: The old pass manager has a hack to disable loop unrolling during // ThinLTO when using sample PGO. Need to either fix it or port some // workaround. 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()); @@ -390,6 +417,8 @@ // opportunities opened up by them. FPM.addPass(InstCombinePass()); + invokePeepholeEPCallbacks(FPM, Level); + // Re-consider control flow based optimizations after redundancy elimination, // redo DCE, etc. FPM.addPass(JumpThreadingPass()); @@ -397,19 +426,25 @@ 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()); + invokePeepholeEPCallbacks(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 @@ -435,8 +470,8 @@ 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. + invokePeepholeEPCallbacks(FPM, Level); + CGPipeline.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPipeline))); @@ -470,9 +505,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()); @@ -503,6 +545,9 @@ // optimizations. FunctionPassManager GlobalCleanupPM(DebugLogging); GlobalCleanupPM.addPass(InstCombinePass()); + + invokePeepholeEPCallbacks(GlobalCleanupPM, Level); + GlobalCleanupPM.addPass(SimplifyCFGPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(GlobalCleanupPM))); @@ -555,6 +600,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 @@ -613,6 +661,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())); @@ -682,6 +733,9 @@ MPM.addPass(GlobalDCEPass()); MPM.addPass(ConstantMergePass()); + for (auto &C : OptimizerLastEPCallbacks) + C(MPM, Level); + return MPM; } @@ -841,8 +895,12 @@ // 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 PeepholeFPM(DebugLogging); + PeepholeFPM.addPass(InstCombinePass()); + + invokePeepholeEPCallbacks(PeepholeFPM, Level); + + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(PeepholeFPM))); // Note: historically, the PruneEH pass was run first to deduce nounwind and // generally clean up exception handling overhead. It isn't clear this is @@ -859,10 +917,11 @@ 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()); + + invokePeepholeEPCallbacks(FPM, Level); + FPM.addPass(JumpThreadingPass()); // Break up allocas @@ -912,8 +971,9 @@ // 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()); + + invokePeepholeEPCallbacks(MainFPM, Level); MainFPM.addPass(JumpThreadingPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(MainFPM))); @@ -1188,9 +1248,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 (startsWithDefaultPipelineAliasPrefix(Name)) { @@ -1200,15 +1266,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)); @@ -1292,11 +1363,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); \ @@ -1354,11 +1431,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); \ @@ -1405,11 +1488,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); \ @@ -1434,6 +1523,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< \ @@ -1535,9 +1628,15 @@ Pipeline = {{"function", std::move(*Pipeline)}}; else if (isLoopPassName(FirstName)) Pipeline = {{"function", {{"loop", std::move(*Pipeline)}}}}; - else + else { + + for (auto &C : ParseTopLevelPipelineCallbacks) + if (C(*this, MPM, *Pipeline, VerifyEachPass, DebugLogging)) + 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