From 3c35208ad1c3f21a8e639c42fd3e416341296eea Mon Sep 17 00:00:00 2001 From: Natan-GabrielTiutiuIntel <101411449+Natan-GabrielTiutiuIntel@users.noreply.github.com> Date: Tue, 6 Aug 2024 21:00:51 +0300 Subject: [PATCH] [mlir] Add --list-passes option to mlir-opt (#100420) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the only way to see the passes that were registered is by calling “mlir-opt --help”. However, for compilers with 500+ passes, the help message becomes too long and sometimes hard to understand. In this PR I add a new "--list-passes" option to mlir-opt, which can be used for printing only the registered passes, a feature that would be extremely useful. --- mlir/include/mlir/Pass/PassRegistry.h | 3 +++ .../include/mlir/Tools/mlir-opt/MlirOptMain.h | 10 +++++++ mlir/lib/Pass/PassRegistry.cpp | 26 +++++++++++++++++++ mlir/lib/Tools/mlir-opt/MlirOptMain.cpp | 16 ++++++++++++ 4 files changed, 55 insertions(+) diff --git a/mlir/include/mlir/Pass/PassRegistry.h b/mlir/include/mlir/Pass/PassRegistry.h index 08874f012199..f9cdee683d3f 100644 --- a/mlir/include/mlir/Pass/PassRegistry.h +++ b/mlir/include/mlir/Pass/PassRegistry.h @@ -44,6 +44,9 @@ using PassAllocatorFunction = std::function()>; // PassRegistry //===----------------------------------------------------------------------===// +/// Prints the passes that were previously registered and stored in passRegistry +void printRegisteredPasses(); + /// Structure to group information about a passes and pass pipelines (argument /// to invoke via mlir-opt, description, pass pipeline builder). class PassRegistryEntry { diff --git a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h index fd1b7e447b31..f578a2608ad6 100644 --- a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h +++ b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h @@ -119,6 +119,13 @@ class MlirOptMainConfig { return success(); } + /// List the registered passes and return. + MlirOptMainConfig &listPasses(bool list) { + listPassesFlag = list; + return *this; + } + bool shouldListPasses() const { return listPassesFlag; } + /// Enable running the reproducer information stored in resources (if /// present). MlirOptMainConfig &runReproducer(bool enableReproducer) { @@ -209,6 +216,9 @@ class MlirOptMainConfig { /// The callback to populate the pass manager. std::function passPipelineCallback; + /// List the registered passes and return. + bool listPassesFlag = false; + /// Enable running the reproducer. bool runReproducerFlag = false; diff --git a/mlir/lib/Pass/PassRegistry.cpp b/mlir/lib/Pass/PassRegistry.cpp index b304183b5a8b..059a85d76250 100644 --- a/mlir/lib/Pass/PassRegistry.cpp +++ b/mlir/lib/Pass/PassRegistry.cpp @@ -68,6 +68,32 @@ static void printOptionHelp(StringRef arg, StringRef desc, size_t indent, // PassRegistry //===----------------------------------------------------------------------===// +/// Prints the passes that were previously registered and stored in passRegistry +void mlir::printRegisteredPasses() { + size_t maxWidth = 0; + for (auto &entry : *passRegistry) + maxWidth = std::max(maxWidth, entry.second.getOptionWidth() + 4); + + // Functor used to print the ordered entries of a registration map. + auto printOrderedEntries = [&](StringRef header, auto &map) { + llvm::SmallVector orderedEntries; + for (auto &kv : map) + orderedEntries.push_back(&kv.second); + llvm::array_pod_sort( + orderedEntries.begin(), orderedEntries.end(), + [](PassRegistryEntry *const *lhs, PassRegistryEntry *const *rhs) { + return (*lhs)->getPassArgument().compare((*rhs)->getPassArgument()); + }); + + llvm::outs().indent(0) << header << ":\n"; + for (PassRegistryEntry *entry : orderedEntries) + entry->printHelpStr(/*indent=*/2, maxWidth); + }; + + // Print the available passes. + printOrderedEntries("Passes", *passRegistry); +} + /// Print the help information for this pass. This includes the argument, /// description, and any pass options. `descIndent` is the indent that the /// descriptions should be aligned. diff --git a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp index ea79ee619061..73320851aadf 100644 --- a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp +++ b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp @@ -30,6 +30,7 @@ #include "mlir/Parser/Parser.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassManager.h" +#include "mlir/Pass/PassRegistry.h" #include "mlir/Support/FileUtilities.h" #include "mlir/Support/Timing.h" #include "mlir/Support/ToolUtilities.h" @@ -118,6 +119,10 @@ struct MlirOptMainConfigCLOptions : public MlirOptMainConfig { "parsing"), cl::location(useExplicitModuleFlag), cl::init(false)); + static cl::opt listPasses( + "list-passes", cl::desc("Print the list of registered passes and exit"), + cl::location(listPassesFlag), cl::init(false)); + static cl::opt runReproducer( "run-reproducer", cl::desc("Run the pipeline stored in the reproducer"), cl::location(runReproducerFlag), cl::init(false)); @@ -501,6 +506,11 @@ mlir::registerAndParseCLIOptions(int argc, char **argv, return std::make_pair(inputFilename.getValue(), outputFilename.getValue()); } +static LogicalResult printRegisteredPassesAndReturn() { + mlir::printRegisteredPasses(); + return success(); +} + LogicalResult mlir::MlirOptMain(llvm::raw_ostream &outputStream, std::unique_ptr buffer, DialectRegistry ®istry, @@ -511,6 +521,9 @@ LogicalResult mlir::MlirOptMain(llvm::raw_ostream &outputStream, llvm::outs() << "\n"; } + if (config.shouldListPasses()) + return printRegisteredPassesAndReturn(); + // The split-input-file mode is a very specific mode that slices the file // up into small pieces and checks each independently. // We use an explicit threadpool to avoid creating and joining/destroying @@ -572,6 +585,9 @@ LogicalResult mlir::MlirOptMain(int argc, char **argv, llvm::StringRef toolName, cl::ParseCommandLineOptions(argc, argv, helpHeader); MlirOptMainConfig config = MlirOptMainConfig::createFromCLOptions(); + if (config.shouldListPasses()) + return printRegisteredPassesAndReturn(); + // When reading from stdin and the input is a tty, it is often a user mistake // and the process "appears to be stuck". Print a message to let the user know // about it!