diff --git a/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h b/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h --- a/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h +++ b/llvm/include/llvm/Transforms/Coroutines/CoroConditionalWrapper.h @@ -21,6 +21,8 @@ CoroConditionalWrapper(ModulePassManager &&); PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); static bool isRequired() { return true; } + void printPipeline(raw_ostream &OS, + function_ref MapClassName2PassName); private: ModulePassManager PM; diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -86,6 +86,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h" #include "llvm/Transforms/Coroutines/CoroCleanup.h" +#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h" #include "llvm/Transforms/Coroutines/CoroEarly.h" #include "llvm/Transforms/Coroutines/CoroElide.h" #include "llvm/Transforms/Coroutines/CoroSplit.h" @@ -897,6 +898,8 @@ return true; if (Name == "function" || Name == "function") return true; + if (Name == "coro-cond") + return true; // Explicitly handle custom-parsed pass names. if (parseRepeatPassName(Name)) @@ -1091,6 +1094,13 @@ MPM.addPass(std::move(NestedMPM)); return Error::success(); } + if (Name == "coro-cond") { + ModulePassManager NestedMPM; + if (auto Err = parseModulePassPipeline(NestedMPM, InnerPipeline)) + return Err; + MPM.addPass(CoroConditionalWrapper(std::move(NestedMPM))); + return Error::success(); + } if (Name == "cgscc") { CGSCCPassManager CGPM; if (auto Err = parseCGSCCPassPipeline(CGPM, InnerPipeline)) diff --git a/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp b/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp --- a/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp @@ -22,3 +22,11 @@ return PM.run(M, AM); } + +void CoroConditionalWrapper::printPipeline( + raw_ostream &OS, function_ref MapClassName2PassName) { + OS << "coro-cond"; + OS << "("; + PM.printPipeline(OS, MapClassName2PassName); + OS << ")"; +} diff --git a/llvm/test/Other/new-pm-print-pipeline.ll b/llvm/test/Other/new-pm-print-pipeline.ll --- a/llvm/test/Other/new-pm-print-pipeline.ll +++ b/llvm/test/Other/new-pm-print-pipeline.ll @@ -10,7 +10,7 @@ ; CHECK-2: repeat<5>(function(mem2reg)),invalidate ;; Test that we get ClassName printed when there is no ClassName to pass-name mapping (as is the case for the BitcodeWriterPass). -; RUN: opt -o /dev/null -disable-verify -print-pipeline-passes -passes='function(mem2reg)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-3 +; RUN: opt -o /dev/null -disable-verify -print-pipeline-passes -passes='function(mem2reg)' < %s -disable-pipeline-verification | FileCheck %s --match-full-lines --check-prefixes=CHECK-3 ; CHECK-3: function(mem2reg),BitcodeWriterPass ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(loop-mssa(indvars))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-4 @@ -79,3 +79,13 @@ ;; Test that LICM & LNICM with options. ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(loop-mssa(licm,licm,lnicm,lnicm))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-25 ; CHECK-25: function(loop-mssa(licm,licm,lnicm,lnicm)) + +;; Test coro-cond. +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='coro-cond(no-op-module)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-26 +; CHECK-26: coro-cond(no-op-module) + +;; Test that -print-pipeline-passes is parsable (implicitly done with -print-pipeline-passes) for various default pipelines. +; RUN: opt -disable-output -passes='default' < %s +; RUN: opt -disable-output -passes='default' < %s +; RUN: opt -disable-output -passes='default' < %s +; RUN: opt -disable-output -passes='default' < %s diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -31,6 +31,7 @@ #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" @@ -153,6 +154,13 @@ "pipelines"), cl::Hidden); +static cl::opt DisablePipelineVerification( + "disable-pipeline-verification", + cl::desc("Only has an effect when specified with -print-pipeline-passes. " + "Disables verifying that the textual pipeline generated by " + "-print-pipeline-passes can be used to create a pipeline."), + cl::Hidden); + // Individual pipeline tuning options. extern cl::opt DisableLoopUnrolling; @@ -462,11 +470,26 @@ // Print a textual, '-passes=' compatible, representation of pipeline if // requested. if (PrintPipelinePasses) { - MPM.printPipeline(outs(), [&PIC](StringRef ClassName) { + std::string Pipeline; + raw_string_ostream SOS(Pipeline); + MPM.printPipeline(SOS, [&PIC](StringRef ClassName) { auto PassName = PIC.getPassNameForClassName(ClassName); return PassName.empty() ? ClassName : PassName; }); + outs() << Pipeline; outs() << "\n"; + + if (!DisablePipelineVerification) { + // Check that we can parse the returned pipeline string as an actual + // pipeline. + ModulePassManager TempPM; + if (auto Err = PB.parsePassPipeline(TempPM, Pipeline)) { + errs() << "Could not parse dumped pass pipeline: " + << toString(std::move(Err)) << "\n"; + return false; + } + } + return true; }