//===- MlirOptMain.h - MLIR Optimizer Driver main ---------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Main entry function for mlir-opt for when built as standalone binary. // //===----------------------------------------------------------------------===// #ifndef MLIR_TOOLS_MLIROPT_MLIROPTMAIN_H #define MLIR_TOOLS_MLIROPT_MLIROPTMAIN_H #include "mlir/Debug/CLOptionsSetup.h" #include "mlir/Support/ToolUtilities.h" #include "llvm/ADT/StringRef.h" #include #include #include namespace llvm { class raw_ostream; class MemoryBuffer; } // namespace llvm namespace mlir { class DialectRegistry; class PassPipelineCLParser; class PassManager; /// enum class to indicate the verbosity level of the diagnostic filter. enum class VerbosityLevel { ErrorsOnly = 0, ErrorsAndWarnings, ErrorsWarningsAndRemarks }; enum class RemarkFormat { REMARK_FORMAT_STDOUT, REMARK_FORMAT_YAML, REMARK_FORMAT_BITSTREAM, }; enum class RemarkPolicy { REMARK_POLICY_ALL, REMARK_POLICY_FINAL, }; /// Configuration options for the mlir-opt tool. /// 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(DialectRegistry &);` and creating /// a config using `auto config = MlirOptMainConfig::createFromCLOptions();`. class MlirOptMainConfig { public: /// Register the options as global LLVM command line options. static void registerCLOptions(DialectRegistry &dialectRegistry); /// 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. MlirOptMainConfig &allowUnregisteredDialects(bool allow) { allowUnregisteredDialectsFlag = allow; return *this; } bool shouldAllowUnregisteredDialects() const { return allowUnregisteredDialectsFlag; } /// Set the debug configuration to use. MlirOptMainConfig &setDebugConfig(tracing::DebugConfig config) { debugConfig = std::move(config); return *this; } tracing::DebugConfig &getDebugConfig() { return debugConfig; } const tracing::DebugConfig &getDebugConfig() const { return debugConfig; } /// Print the pass-pipeline as text before executing. MlirOptMainConfig &dumpPassPipeline(bool dump) { dumpPassPipelineFlag = dump; return *this; } VerbosityLevel getDiagnosticVerbosityLevel() const { return diagnosticVerbosityLevelFlag; } bool shouldDumpPassPipeline() const { return dumpPassPipelineFlag; } /// Set the output format to bytecode instead of textual IR. MlirOptMainConfig &emitBytecode(bool emit) { emitBytecodeFlag = emit; return *this; } bool shouldEmitBytecode() const { return emitBytecodeFlag; } bool shouldElideResourceDataFromBytecode() const { return elideResourceDataFromBytecodeFlag; } bool shouldShowNotes() const { return !disableDiagnosticNotesFlag; } /// Set the IRDL file to load before processing the input. MlirOptMainConfig &setIrdlFile(StringRef file) { irdlFileFlag = file; return *this; } StringRef getIrdlFile() const { return irdlFileFlag; } /// Set the bytecode version to emit. MlirOptMainConfig &setEmitBytecodeVersion(int64_t version) { emitBytecodeVersion = version; return *this; } std::optional bytecodeVersionToEmit() const { return emitBytecodeVersion; } /// Set the bytecode producer to use. MlirOptMainConfig &emitBytecodeProducer(StringRef producer) { emitBytecodeProducerFlag = producer.str(); return *this; } std::optional bytecodeProducerToEmit() const { if (emitBytecodeProducerFlag.empty()) return std::nullopt; return emitBytecodeProducerFlag; } /// Set the callback to populate the pass manager. MlirOptMainConfig & setPassPipelineSetupFn(std::function callback) { passPipelineCallback = std::move(callback); return *this; } /// Set the parser to use to populate the pass manager. MlirOptMainConfig &setPassPipelineParser(const PassPipelineCLParser &parser); /// Populate the passmanager, if any callback was set. LogicalResult setupPassPipeline(PassManager &pm) const { if (passPipelineCallback) return passPipelineCallback(pm); 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) { runReproducerFlag = enableReproducer; return *this; }; /// Return true if the reproducer should be run. bool shouldRunReproducer() const { return runReproducerFlag; } /// Show the registered dialects before trying to load the input file. MlirOptMainConfig &showDialects(bool show) { showDialectsFlag = show; return *this; } bool shouldShowDialects() const { return showDialectsFlag; } /// Set the marker on which to split the input into chunks and process each /// chunk independently. Input is not split if empty. MlirOptMainConfig & splitInputFile(std::string splitMarker = kDefaultSplitMarker) { splitInputFileFlag = std::move(splitMarker); return *this; } StringRef inputSplitMarker() const { return splitInputFileFlag; } /// Set whether to merge the output chunks into one file using the given /// marker. MlirOptMainConfig & outputSplitMarker(std::string splitMarker = kDefaultSplitMarker) { outputSplitMarkerFlag = std::move(splitMarker); return *this; } StringRef outputSplitMarker() const { return outputSplitMarkerFlag; } /// Disable implicit addition of a top-level module op during parsing. MlirOptMainConfig &useExplicitModule(bool useExplicitModule) { useExplicitModuleFlag = useExplicitModule; return *this; } bool shouldUseExplicitModule() const { return useExplicitModuleFlag; } /// Set whether to check that emitted diagnostics match `expected-*` lines on /// the corresponding line. This is meant for implementing diagnostic tests. MlirOptMainConfig & verifyDiagnostics(SourceMgrDiagnosticVerifierHandler::Level verify) { verifyDiagnosticsFlag = verify; return *this; } bool shouldVerifyDiagnostics() const { return verifyDiagnosticsFlag != SourceMgrDiagnosticVerifierHandler::Level::None; } SourceMgrDiagnosticVerifierHandler::Level verifyDiagnosticsLevel() const { return verifyDiagnosticsFlag; } /// Set whether to run the verifier after each transformation pass. MlirOptMainConfig &verifyPasses(bool verify) { verifyPassesFlag = verify; return *this; } bool shouldVerifyPasses() const { return verifyPassesFlag; } /// Set whether to run the verifier on parsing. MlirOptMainConfig &verifyOnParsing(bool verify) { disableVerifierOnParsingFlag = !verify; return *this; } bool shouldVerifyOnParsing() const { return !disableVerifierOnParsingFlag; } /// Set whether to run the verifier after each transformation pass. MlirOptMainConfig &verifyRoundtrip(bool verify) { verifyRoundtripFlag = verify; return *this; } bool shouldVerifyRoundtrip() const { return verifyRoundtripFlag; } /// Checks if any remark filters are set. bool shouldEmitRemarks() const { // Emit all remarks only when no filters are specified. const bool hasFilters = !getRemarksAllFilter().empty() || !getRemarksPassedFilter().empty() || !getRemarksFailedFilter().empty() || !getRemarksMissedFilter().empty() || !getRemarksAnalyseFilter().empty(); return hasFilters; } /// Reproducer file generation (no crash required). StringRef getReproducerFilename() const { return generateReproducerFileFlag; } /// Set the reproducer output filename RemarkFormat getRemarkFormat() const { return remarkFormatFlag; } /// Set the remark policy to use. RemarkPolicy getRemarkPolicy() const { return remarkPolicyFlag; } /// Set the remark format to use. std::string getRemarksAllFilter() const { return remarksAllFilterFlag; } /// Set the remark output file. std::string getRemarksOutputFile() const { return remarksOutputFileFlag; } /// Set the remark passed filters. std::string getRemarksPassedFilter() const { return remarksPassedFilterFlag; } /// Set the remark failed filters. std::string getRemarksFailedFilter() const { return remarksFailedFilterFlag; } /// Set the remark missed filters. std::string getRemarksMissedFilter() const { return remarksMissedFilterFlag; } /// Set the remark analyse filters. std::string getRemarksAnalyseFilter() const { return remarksAnalyseFilterFlag; } protected: /// Allow operation with no registered dialects. /// This option is for convenience during testing only and discouraged in /// general. bool allowUnregisteredDialectsFlag = false; /// Remark format RemarkFormat remarkFormatFlag = RemarkFormat::REMARK_FORMAT_STDOUT; /// Remark policy RemarkPolicy remarkPolicyFlag = RemarkPolicy::REMARK_POLICY_ALL; /// Remark file to output to std::string remarksOutputFileFlag = ""; /// Remark filters std::string remarksAllFilterFlag = ""; std::string remarksPassedFilterFlag = ""; std::string remarksFailedFilterFlag = ""; std::string remarksMissedFilterFlag = ""; std::string remarksAnalyseFilterFlag = ""; /// Configuration for the debugging hooks. tracing::DebugConfig debugConfig; /// Verbosity level of diagnostic information. 0: Errors only, /// 1: Errors and warnings, 2: Errors, warnings and remarks. VerbosityLevel diagnosticVerbosityLevelFlag = VerbosityLevel::ErrorsWarningsAndRemarks; /// Print the pipeline that will be run. bool dumpPassPipelineFlag = false; /// Emit bytecode instead of textual assembly when generating output. bool emitBytecodeFlag = false; /// Elide resources when generating bytecode. bool elideResourceDataFromBytecodeFlag = false; /// IRDL file to register before processing the input. std::string irdlFileFlag = ""; /// Location Breakpoints to filter the action logging. std::vector logActionLocationFilter; /// Emit bytecode at given version. std::optional emitBytecodeVersion = std::nullopt; /// Emit bytecode with given producer. std::string emitBytecodeProducerFlag = ""; /// 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; /// Show the registered dialects before trying to load the input file. bool showDialectsFlag = false; /// Show the notes in diagnostic information. Notes can be included in /// any diagnostic information, so it is not specified in the verbosity /// level. bool disableDiagnosticNotesFlag = true; /// Split the input file based on the given marker into chunks and process /// each chunk independently. Input is not split if empty. std::string splitInputFileFlag = ""; /// Merge output chunks into one file using the given marker. std::string outputSplitMarkerFlag = ""; /// Use an explicit top-level module op during parsing. bool useExplicitModuleFlag = false; /// Set whether to check that emitted diagnostics match `expected-*` lines on /// the corresponding line. This is meant for implementing diagnostic tests. SourceMgrDiagnosticVerifierHandler::Level verifyDiagnosticsFlag = SourceMgrDiagnosticVerifierHandler::Level::None; /// Run the verifier after each transformation pass. bool verifyPassesFlag = true; /// Disable the verifier on parsing. bool disableVerifierOnParsingFlag = false; /// Verify that the input IR round-trips perfectly. bool verifyRoundtripFlag = false; /// The reproducer output filename (no crash required). std::string generateReproducerFileFlag = ""; }; /// This defines the function type used to setup the pass manager. This can be /// used to pass in a callback to setup a default pass pipeline to be applied on /// the loaded IR. using PassPipelineFn = llvm::function_ref; /// Register basic command line options. /// - toolName is used for the header displayed by `--help`. /// - registry should contain all the dialects that can be parsed in the source. /// - return std::string for help header. std::string registerCLIOptions(llvm::StringRef toolName, DialectRegistry ®istry); /// Parse command line options. /// - helpHeader is used for the header displayed by `--help`. /// - return std::pair for /// inputFilename and outputFilename command line option values. std::pair parseCLIOptions(int argc, char **argv, llvm::StringRef helpHeader); /// Register and parse command line options. /// - toolName is used for the header displayed by `--help`. /// - registry should contain all the dialects that can be parsed in the source. /// - return std::pair for /// inputFilename and outputFilename command line option values. std::pair registerAndParseCLIOptions(int argc, char **argv, llvm::StringRef toolName, DialectRegistry ®istry); /// Perform the core processing behind `mlir-opt`. /// - outputStream is the stream where the resulting IR is printed. /// - buffer is the in-memory file to parser and process. /// - registry should contain all the dialects that can be parsed in the source. /// - config contains the configuration options for the tool. LogicalResult MlirOptMain(llvm::raw_ostream &outputStream, std::unique_ptr buffer, DialectRegistry ®istry, const MlirOptMainConfig &config); /// Implementation for tools like `mlir-opt`. /// - toolName is used for the header displayed by `--help`. /// - registry should contain all the dialects that can be parsed in the source. LogicalResult MlirOptMain(int argc, char **argv, llvm::StringRef toolName, DialectRegistry ®istry); /// Implementation for tools like `mlir-opt`. /// This function can be used with registerAndParseCLIOptions so that /// CLI options can be accessed before running MlirOptMain. /// - inputFilename is the name of the input mlir file. /// - outputFilename is the name of the output file. /// - registry should contain all the dialects that can be parsed in the source. LogicalResult MlirOptMain(int argc, char **argv, llvm::StringRef inputFilename, llvm::StringRef outputFilename, DialectRegistry ®istry); /// Helper wrapper to return the result of MlirOptMain directly from main. /// /// Example: /// /// int main(int argc, char **argv) { /// // ... /// return mlir::asMainReturnCode(mlir::MlirOptMain( /// argc, argv, /* ... */); /// } /// inline int asMainReturnCode(LogicalResult r) { return r.succeeded() ? EXIT_SUCCESS : EXIT_FAILURE; } } // namespace mlir #endif // MLIR_TOOLS_MLIROPT_MLIROPTMAIN_H