Index: include/llvm/IR/PassManager.h =================================================================== --- include/llvm/IR/PassManager.h +++ include/llvm/IR/PassManager.h @@ -987,6 +987,34 @@ } }; +/// A utility pass template that simply runs another pass multiple times. +/// +/// This can be useful when debugging or testing passes. It also serves as an +/// example of how to extend the pass manager in ways beyond composition. +template +class RepeatingPassWrapper : public PassInfoMixin> { +public: + RepeatingPassWrapper(int Count, PassT P) : Count(Count), P(std::move(P)) {} + + template + PreservedAnalyses run(IRUnitT &Arg, AnalysisManager &AM, + Ts... Args) { + auto PA = PreservedAnalyses::all(); + for (int i = 0; i < Count; ++i) + PA.intersect(P.run(Arg, AM, Args...)); + return PA; + } + +private: + const int Count; + PassT P; +}; + +template +RepeatingPassWrapper createRepeatingPassWrapper(int Count, PassT P) { + return RepeatingPassWrapper(Count, std::move(P)); +} + } #endif Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -450,6 +450,34 @@ return false; } +template +static bool parseRepeatedPipeline(PassManagerT &PM, StringRef &PipelineText, + bool DebugLogging, + ParseCallbackT &&ParseCallback) { + assert(PipelineText.startswith("repeat(") && + "Must be parsing a repeated pipeline!"); + PipelineText = PipelineText.substr(strlen("repeat(")); + // Otherwise try to parse a pass name. + size_t End = PipelineText.find_first_of(","); + int Count; + if (PipelineText.substr(0, End).getAsInteger(0, Count)) + return false; + if (Count <= 0) + return false; + PipelineText = PipelineText.substr(End + 1); + + // Now build up the repeated pipeline in an implicit pass manager. + PassManagerT RepeatedPM(DebugLogging); + if (!ParseCallback(RepeatedPM, PipelineText) || PipelineText.empty()) + return false; + assert(PipelineText[0] == ')'); + PipelineText = PipelineText.substr(1); + + // Finally, embed this repeated pass manager in the repeated pass wrapper. + PM.addPass(createRepeatingPassWrapper(Count, std::move(RepeatedPM))); + return true; +} + bool PassBuilder::parseLoopPassPipeline(LoopPassManager &LPM, StringRef &PipelineText, bool VerifyEachPass, @@ -470,6 +498,14 @@ // Add the nested pass manager with the appropriate adaptor. LPM.addPass(std::move(NestedLPM)); + } else if (PipelineText.startswith("repeat(")) { + if (!parseRepeatedPipeline( + LPM, PipelineText, DebugLogging, + [&](LoopPassManager &RepeatedLPM, StringRef &PipelineText) { + return parseLoopPassPipeline(RepeatedLPM, PipelineText, + VerifyEachPass, DebugLogging); + })) + return false; } else { // Otherwise try to parse a pass name. size_t End = PipelineText.find_first_of(",)"); @@ -523,6 +559,14 @@ // Add the nested pass manager with the appropriate adaptor. FPM.addPass(createFunctionToLoopPassAdaptor(std::move(NestedLPM))); + } else if (PipelineText.startswith("repeat(")) { + if (!parseRepeatedPipeline( + FPM, PipelineText, DebugLogging, + [&](FunctionPassManager &RepeatedFPM, StringRef &PipelineText) { + return parseFunctionPassPipeline(RepeatedFPM, PipelineText, + VerifyEachPass, DebugLogging); + })) + return false; } else { // Otherwise try to parse a pass name. size_t End = PipelineText.find_first_of(",)"); @@ -577,6 +621,14 @@ // Add the nested pass manager with the appropriate adaptor. CGPM.addPass( createCGSCCToFunctionPassAdaptor(std::move(NestedFPM), DebugLogging)); + } else if (PipelineText.startswith("repeat(")) { + if (!parseRepeatedPipeline( + CGPM, PipelineText, DebugLogging, + [&](CGSCCPassManager &RepeatedCGPM, StringRef &PipelineText) { + return parseCGSCCPassPipeline(RepeatedCGPM, PipelineText, + VerifyEachPass, DebugLogging); + })) + return false; } else { // Otherwise try to parse a pass name. size_t End = PipelineText.find_first_of(",)"); @@ -658,6 +710,14 @@ // Add the nested pass manager with the appropriate adaptor. MPM.addPass(createModuleToFunctionPassAdaptor(std::move(NestedFPM))); + } else if (PipelineText.startswith("repeat(")) { + if (!parseRepeatedPipeline( + MPM, PipelineText, DebugLogging, + [&](ModulePassManager &RepeatedMPM, StringRef &PipelineText) { + return parseModulePassPipeline(RepeatedMPM, PipelineText, + VerifyEachPass, DebugLogging); + })) + return false; } else { // Otherwise try to parse a pass name. size_t End = PipelineText.find_first_of(",)"); Index: test/Other/new-pass-manager.ll =================================================================== --- test/Other/new-pass-manager.ll +++ test/Other/new-pass-manager.ll @@ -48,7 +48,7 @@ ; CHECK-MODULE-PRINT: Running pass: VerifierPass ; CHECK-MODULE-PRINT: Running pass: PrintModulePass ; CHECK-MODULE-PRINT: ModuleID -; CHECK-MODULE-PRINT: define void @foo() +; CHECK-MODULE-PRINT: define void @foo(i1 %x) ; CHECK-MODULE-PRINT: Running pass: VerifierPass ; CHECK-MODULE-PRINT: Finished llvm::Module pass manager run @@ -57,7 +57,7 @@ ; CHECK-MODULE-VERIFY: Starting llvm::Module pass manager run ; CHECK-MODULE-VERIFY: Running pass: PrintModulePass ; CHECK-MODULE-VERIFY: ModuleID -; CHECK-MODULE-VERIFY: define void @foo() +; CHECK-MODULE-VERIFY: define void @foo(i1 %x) ; CHECK-MODULE-VERIFY: Running pass: VerifierPass ; CHECK-MODULE-VERIFY: Finished llvm::Module pass manager run @@ -70,7 +70,7 @@ ; CHECK-FUNCTION-PRINT: Starting llvm::Function pass manager run ; CHECK-FUNCTION-PRINT: Running pass: PrintFunctionPass ; CHECK-FUNCTION-PRINT-NOT: ModuleID -; CHECK-FUNCTION-PRINT: define void @foo() +; CHECK-FUNCTION-PRINT: define void @foo(i1 %x) ; CHECK-FUNCTION-PRINT: Finished llvm::Function pass manager run ; CHECK-FUNCTION-PRINT: Running pass: VerifierPass ; CHECK-FUNCTION-PRINT: Finished llvm::Module pass manager run @@ -81,14 +81,19 @@ ; CHECK-FUNCTION-VERIFY: Starting llvm::Function pass manager run ; CHECK-FUNCTION-VERIFY: Running pass: PrintFunctionPass ; CHECK-FUNCTION-VERIFY-NOT: ModuleID -; CHECK-FUNCTION-VERIFY: define void @foo() +; CHECK-FUNCTION-VERIFY: define void @foo(i1 %x) ; CHECK-FUNCTION-VERIFY: Running pass: VerifierPass ; CHECK-FUNCTION-VERIFY: Finished llvm::Function pass manager run ; CHECK-FUNCTION-VERIFY: Finished llvm::Module pass manager run ; RUN: opt -S -o - -passes='no-op-module,no-op-module' %s \ ; RUN: | FileCheck %s --check-prefix=CHECK-NOOP -; CHECK-NOOP: define void @foo() { +; CHECK-NOOP: define void @foo(i1 %x) { +; CHECK-NOOP: entry: +; CHECK-NOOP: br i1 %x, label %loop, label %exit +; CHECK-NOOP: loop: +; CHECK-NOOP: br label %loop +; CHECK-NOOP: exit: ; CHECK-NOOP: ret void ; CHECK-NOOP: } @@ -363,7 +368,101 @@ ; CHECK-LTO-O2: Running pass: InstCombinePass ; CHECK-LTO-O2: Running pass: SimplifyCFGPass -define void @foo() { +; RUN: opt -disable-output -disable-verify -debug-pass-manager \ +; RUN: -passes='repeat(3,no-op-module)' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-REPEAT-MODULE-PASS +; CHECK-REPEAT-MODULE-PASS: Starting llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Running pass: RepeatingPassWrapper +; CHECK-REPEAT-MODULE-PASS-NEXT: Starting llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Running pass: NoOpModulePass +; CHECK-REPEAT-MODULE-PASS-NEXT: Finished llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Starting llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Running pass: NoOpModulePass +; CHECK-REPEAT-MODULE-PASS-NEXT: Finished llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Starting llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Running pass: NoOpModulePass +; CHECK-REPEAT-MODULE-PASS-NEXT: Finished llvm::Module pass manager run +; CHECK-REPEAT-MODULE-PASS-NEXT: Finished llvm::Module pass manager run + +; RUN: opt -disable-output -disable-verify -debug-pass-manager \ +; RUN: -passes='cgscc(repeat(3,no-op-cgscc))' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-REPEAT-CGSCC-PASS +; CHECK-REPEAT-CGSCC-PASS: Starting llvm::Module pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)] +; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: RepeatingPassWrapper +; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass +; CHECK-REPEAT-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass +; CHECK-REPEAT-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass +; CHECK-REPEAT-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run +; CHECK-REPEAT-CGSCC-PASS-NEXT: Finished llvm::Module pass manager run + +; RUN: opt -disable-output -disable-verify -debug-pass-manager \ +; RUN: -passes='function(repeat(3,no-op-function))' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-REPEAT-FUNCTION-PASS +; CHECK-REPEAT-FUNCTION-PASS: Starting llvm::Module pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: ModuleToFunctionPassAdaptor +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: RepeatingPassWrapper +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: NoOpFunctionPass +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Finished llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: NoOpFunctionPass +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Finished llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Starting llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Running pass: NoOpFunctionPass +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Finished llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Finished llvm::Function pass manager run +; CHECK-REPEAT-FUNCTION-PASS-NEXT: Finished llvm::Module pass manager run + +; RUN: opt -disable-output -disable-verify -debug-pass-manager \ +; RUN: -passes='loop(repeat(3,no-op-loop))' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-REPEAT-LOOP-PASS +; CHECK-REPEAT-LOOP-PASS: Starting llvm::Module pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: ModuleToFunctionPassAdaptor +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Function pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: FunctionToLoopPassAdaptor +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: LoopAnalysis +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: DominatorTreeAnalysis +; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: PassManager<{{.*}}> on loop +; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: RepeatingPassWrapper +; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: NoOpLoopPass +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: NoOpLoopPass +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: NoOpLoopPass +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Loop pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Function pass manager run +; CHECK-REPEAT-LOOP-PASS-NEXT: Finished llvm::Module pass manager run + +define void @foo(i1 %x) { +entry: + br i1 %x, label %loop, label %exit + +loop: + br label %loop + +exit: ret void }