diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -19,6 +19,7 @@ #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO/Inliner.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" @@ -532,6 +533,9 @@ /// Returns true if the pass name is the name of a (non-alias) analysis pass. bool isAnalysisPassName(StringRef PassName); + /// Print pass names. + void printPassNames(raw_ostream &OS); + /// Register a callback for a default optimizer pipeline extension /// point /// 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 @@ -3060,6 +3060,54 @@ return false; } +static void printPassName(StringRef PassName, raw_ostream &OS) { + OS << " " << PassName << "\n"; +} + +void PassBuilder::printPassNames(raw_ostream &OS) { + // TODO: print pass descriptions when they are available + + OS << "Module passes:\n"; +#define MODULE_PASS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Module analyses:\n"; +#define MODULE_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Module alias analyses:\n"; +#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "CGSCC passes:\n"; +#define CGSCC_PASS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "CGSCC analyses:\n"; +#define CGSCC_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Function passes:\n"; +#define FUNCTION_PASS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Function analyses:\n"; +#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Function alias analyses:\n"; +#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Loop passes:\n"; +#define LOOP_PASS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" + + OS << "Loop analyses:\n"; +#define LOOP_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS); +#include "PassRegistry.def" +} + void PassBuilder::registerParseTopLevelPipelineCallback( const std::function, bool DebugLogging)> &C) { diff --git a/llvm/test/Other/print-passes.ll b/llvm/test/Other/print-passes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/print-passes.ll @@ -0,0 +1,22 @@ +; RUN: opt --print-passes | FileCheck %s + +; CHECK: Module passes: +; CHECK: no-op-module +; CHECK: Module analyses: +; CHECK: no-op-module +; CHECK: Module alias analyses: +; CHECK: globals-aa +; CHECK: CGSCC passes: +; CHECK: no-op-cgscc +; CHECK: CGSCC analyses: +; CHECK: no-op-cgscc +; CHECK: Function passes: +; CHECK: no-op-function +; CHECK: Function analyses: +; CHECK: no-op-function +; CHECK: Function alias analyses: +; CHECK: basic-aa +; CHECK: Loop passes: +; CHECK: no-op-loop +; CHECK: Loop analyses: +; CHECK: no-op-loop diff --git a/llvm/tools/opt/NewPMDriver.h b/llvm/tools/opt/NewPMDriver.h --- a/llvm/tools/opt/NewPMDriver.h +++ b/llvm/tools/opt/NewPMDriver.h @@ -54,6 +54,8 @@ enum CSPGOKind { NoCSPGO, CSInstrGen, CSInstrUse }; } +void printPasses(raw_ostream &OS); + /// Driver function to run the new pass manager over a module. /// /// This function only exists factored away from opt.cpp in order to prevent 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 @@ -463,3 +463,8 @@ return true; } + +void llvm::printPasses(raw_ostream &OS) { + PassBuilder PB; + PB.printPassNames(OS); +} diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -82,8 +82,13 @@ // pass management. static cl::opt PassPipeline( "passes", - cl::desc("A textual description of the pass pipeline for optimizing"), - cl::Hidden); + cl::desc( + "A textual description of the pass pipeline. To have analysis passes " + "available before a certain pass, add 'require'.")); + +static cl::opt PrintPasses("print-passes", + cl::desc("Print available passes that can be " + "specified in -passes=foo and exit")); static cl::opt InputFilename(cl::Positional, cl::desc(""), @@ -589,6 +594,14 @@ return 1; } + // FIXME: once the legacy PM code is deleted, move runPassPipeline() here and + // construct the PassBuilder before parsing IR so we can reuse the same + // PassBuilder for print passes. + if (PrintPasses) { + printPasses(outs()); + return 0; + } + TimeTracerRAII TimeTracer(argv[0]); SMDiagnostic Err;