diff --git a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h --- a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h +++ b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h @@ -34,8 +34,21 @@ /// This is intended to help building tools like mlir-opt by collecting the /// supported options. /// The API is fluent, and the options are sorted in alphabetical order below. +/// The options can be exposed to the LLVM command line by registering them +/// with `MlirOptMainConfig::registerCLOptions();` and creating a config using +/// `auto config = MlirOptMainConfig::createFromCLOptions();`. class MlirOptMainConfig { public: + /// Register the options as global LLVM command line options. + static void registerCLOptions(); + + /// Create a new config with the default set from the CL options. + static MlirOptMainConfig createFromCLOptions(); + + /// + /// Options. + /// + /// Allow operation with no registered dialects. /// This option is for convenience during testing only and discouraged in /// general. @@ -124,7 +137,7 @@ } bool shouldVerifyPasses() const { return verifyPassesFlag; } -private: +protected: /// Allow operation with no registered dialects. /// This option is for convenience during testing only and discouraged in /// general. diff --git a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp --- a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp +++ b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp @@ -31,6 +31,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/StringSaver.h" @@ -40,6 +41,71 @@ using namespace mlir; using namespace llvm; +namespace { +/// This class is intended to manage the handling of command line options for +/// creating a *-opt config. This is a singleton. +struct MlirOptMainConfigCLOptions : public MlirOptMainConfig { + MlirOptMainConfigCLOptions() { + // These options are static but all uses ExternalStorage to initialize the + // members of the parent class. This is unusual but since this class is a + // singleton it basically attaches command line option to the singleton + // members. + + static cl::opt allowUnregisteredDialects( + "allow-unregistered-dialect", + cl::desc("Allow operation with no registered dialects"), + cl::location(allowUnregisteredDialectsFlag), cl::init(false)); + + static cl::opt dumpPassPipeline( + "dump-pass-pipeline", cl::desc("Print the pipeline that will be run"), + cl::location(dumpPassPipelineFlag), cl::init(false)); + + static cl::opt emitBytecode( + "emit-bytecode", cl::desc("Emit bytecode when generating output"), + cl::location(emitBytecodeFlag), cl::init(false)); + + static cl::opt explicitModule( + "no-implicit-module", + cl::desc("Disable implicit addition of a top-level module op during " + "parsing"), + cl::location(useExplicitModuleFlag), cl::init(false)); + + static cl::opt showDialects( + "show-dialects", + cl::desc("Print the list of registered dialects and exit"), + cl::location(showDialectsFlag), cl::init(false)); + + static cl::opt splitInputFile( + "split-input-file", + cl::desc("Split the input file into pieces and process each " + "chunk independently"), + cl::location(splitInputFileFlag), cl::init(false)); + + static cl::opt verifyDiagnostics( + "verify-diagnostics", + cl::desc("Check that emitted diagnostics match " + "expected-* lines on the corresponding line"), + cl::location(verifyDiagnosticsFlag), cl::init(false)); + + static cl::opt verifyPasses( + "verify-each", + cl::desc("Run the verifier after each transformation pass"), + cl::location(verifyPassesFlag), cl::init(true)); + + static PassPipelineCLParser passPipeline("", "Compiler passes to run", "p"); + setPassPipelineParser(passPipeline); + } +}; +} // namespace + +ManagedStatic clOptionsConfig; + +void MlirOptMainConfig::registerCLOptions() { *clOptionsConfig; } + +MlirOptMainConfig MlirOptMainConfig::createFromCLOptions() { + return *clOptionsConfig; +} + MlirOptMainConfig &MlirOptMainConfig::setPassPipelineParser( const PassPipelineCLParser &passPipeline) { passPipelineCallback = [&](PassManager &pm) { @@ -171,6 +237,12 @@ std::unique_ptr buffer, DialectRegistry ®istry, const MlirOptMainConfig &config) { + if (config.shouldShowDialects()) { + llvm::outs() << "Available Dialects:\n"; + interleave(registry.getDialectNames(), llvm::outs(), "\n"); + llvm::outs() << "\n"; + } + // 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 @@ -244,54 +316,15 @@ cl::value_desc("filename"), cl::init("-")); - static cl::opt splitInputFile( - "split-input-file", - cl::desc("Split the input file into pieces and process each " - "chunk independently"), - cl::init(false)); - - static cl::opt verifyDiagnostics( - "verify-diagnostics", - cl::desc("Check that emitted diagnostics match " - "expected-* lines on the corresponding line"), - cl::init(false)); - - static cl::opt verifyPasses( - "verify-each", - cl::desc("Run the verifier after each transformation pass"), - cl::init(true)); - - static cl::opt allowUnregisteredDialects( - "allow-unregistered-dialect", - cl::desc("Allow operation with no registered dialects (discouraged: testing only!)"), cl::init(false)); - - static cl::opt showDialects( - "show-dialects", cl::desc("Print the list of registered dialects"), - cl::init(false)); - - static cl::opt emitBytecode( - "emit-bytecode", cl::desc("Emit bytecode when generating output"), - cl::init(false)); - - static cl::opt explicitModule{ - "no-implicit-module", - cl::desc( - "Disable implicit addition of a top-level module op during parsing"), - cl::init(false)}; - - static cl::opt dumpPassPipeline{ - "dump-pass-pipeline", cl::desc("Print the pipeline that will be run"), - cl::init(false)}; - InitLLVM y(argc, argv); // Register any command line options. + MlirOptMainConfig::registerCLOptions(); registerAsmPrinterCLOptions(); registerMLIRContextCLOptions(); registerPassManagerCLOptions(); registerDefaultTimingManagerCLOptions(); DebugCounter::registerCLOptions(); - PassPipelineCLParser passPipeline("", "Compiler passes to run", "p"); // Build the list of dialects as a header for the --help message. std::string helpHeader = (toolName + "\nAvailable Dialects: ").str(); @@ -302,14 +335,7 @@ } // Parse pass names in main to ensure static initialization completed. cl::ParseCommandLineOptions(argc, argv, helpHeader); - - if (showDialects) { - llvm::outs() << "Available Dialects:\n"; - interleave( - registry.getDialectNames(), llvm::outs(), - [](auto name) { llvm::outs() << name; }, "\n"); - return success(); - } + MlirOptMainConfig config = MlirOptMainConfig::createFromCLOptions(); // Set up the input file. std::string errorMessage; @@ -324,18 +350,6 @@ llvm::errs() << errorMessage << "\n"; return failure(); } - // Setup the configuration for the main function. - MlirOptMainConfig config; - config.setPassPipelineParser(passPipeline) - .splitInputFile(splitInputFile) - .verifyDiagnostics(verifyDiagnostics) - .verifyPasses(verifyPasses) - .allowUnregisteredDialects(allowUnregisteredDialects) - .preloadDialectsInContext(preloadDialectsInContext) - .emitBytecode(emitBytecode) - .useExplicitModule(explicitModule) - .dumpPassPipeline(dumpPassPipeline); - if (failed(MlirOptMain(output->os(), std::move(file), registry, config))) return failure();