1 //===- MlirOptMain.h - MLIR Optimizer Driver main ---------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Main entry function for mlir-opt for when built as standalone binary. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef MLIR_TOOLS_MLIROPT_MLIROPTMAIN_H 14 #define MLIR_TOOLS_MLIROPT_MLIROPTMAIN_H 15 16 #include "mlir/Debug/CLOptionsSetup.h" 17 #include "mlir/Support/ToolUtilities.h" 18 #include "llvm/ADT/StringRef.h" 19 20 #include <cstdlib> 21 #include <functional> 22 #include <memory> 23 24 namespace llvm { 25 class raw_ostream; 26 class MemoryBuffer; 27 } // namespace llvm 28 29 namespace mlir { 30 class DialectRegistry; 31 class PassPipelineCLParser; 32 class PassManager; 33 34 /// enum class to indicate the verbosity level of the diagnostic filter. 35 enum class VerbosityLevel { 36 ErrorsOnly = 0, 37 ErrorsAndWarnings, 38 ErrorsWarningsAndRemarks 39 }; 40 41 /// Configuration options for the mlir-opt tool. 42 /// This is intended to help building tools like mlir-opt by collecting the 43 /// supported options. 44 /// The API is fluent, and the options are sorted in alphabetical order below. 45 /// The options can be exposed to the LLVM command line by registering them 46 /// with `MlirOptMainConfig::registerCLOptions(DialectRegistry &);` and creating 47 /// a config using `auto config = MlirOptMainConfig::createFromCLOptions();`. 48 class MlirOptMainConfig { 49 public: 50 /// Register the options as global LLVM command line options. 51 static void registerCLOptions(DialectRegistry &dialectRegistry); 52 53 /// Create a new config with the default set from the CL options. 54 static MlirOptMainConfig createFromCLOptions(); 55 56 /// 57 /// Options. 58 /// 59 60 /// Allow operation with no registered dialects. 61 /// This option is for convenience during testing only and discouraged in 62 /// general. 63 MlirOptMainConfig &allowUnregisteredDialects(bool allow) { 64 allowUnregisteredDialectsFlag = allow; 65 return *this; 66 } 67 bool shouldAllowUnregisteredDialects() const { 68 return allowUnregisteredDialectsFlag; 69 } 70 71 /// Set the debug configuration to use. 72 MlirOptMainConfig &setDebugConfig(tracing::DebugConfig config) { 73 debugConfig = std::move(config); 74 return *this; 75 } 76 tracing::DebugConfig &getDebugConfig() { return debugConfig; } 77 const tracing::DebugConfig &getDebugConfig() const { return debugConfig; } 78 79 /// Print the pass-pipeline as text before executing. 80 MlirOptMainConfig &dumpPassPipeline(bool dump) { 81 dumpPassPipelineFlag = dump; 82 return *this; 83 } 84 85 VerbosityLevel getDiagnosticVerbosityLevel() const { 86 return diagnosticVerbosityLevelFlag; 87 } 88 89 bool shouldDumpPassPipeline() const { return dumpPassPipelineFlag; } 90 91 /// Set the output format to bytecode instead of textual IR. 92 MlirOptMainConfig &emitBytecode(bool emit) { 93 emitBytecodeFlag = emit; 94 return *this; 95 } 96 bool shouldEmitBytecode() const { return emitBytecodeFlag; } 97 98 bool shouldElideResourceDataFromBytecode() const { 99 return elideResourceDataFromBytecodeFlag; 100 } 101 102 bool shouldShowNotes() const { return !disableDiagnosticNotesFlag; } 103 104 /// Set the IRDL file to load before processing the input. 105 MlirOptMainConfig &setIrdlFile(StringRef file) { 106 irdlFileFlag = file; 107 return *this; 108 } 109 StringRef getIrdlFile() const { return irdlFileFlag; } 110 111 /// Set the bytecode version to emit. 112 MlirOptMainConfig &setEmitBytecodeVersion(int64_t version) { 113 emitBytecodeVersion = version; 114 return *this; 115 } 116 std::optional<int64_t> bytecodeVersionToEmit() const { 117 return emitBytecodeVersion; 118 } 119 120 /// Set the callback to populate the pass manager. 121 MlirOptMainConfig & 122 setPassPipelineSetupFn(std::function<LogicalResult(PassManager &)> callback) { 123 passPipelineCallback = std::move(callback); 124 return *this; 125 } 126 127 /// Set the parser to use to populate the pass manager. 128 MlirOptMainConfig &setPassPipelineParser(const PassPipelineCLParser &parser); 129 130 /// Populate the passmanager, if any callback was set. 131 LogicalResult setupPassPipeline(PassManager &pm) const { 132 if (passPipelineCallback) 133 return passPipelineCallback(pm); 134 return success(); 135 } 136 137 /// List the registered passes and return. 138 MlirOptMainConfig &listPasses(bool list) { 139 listPassesFlag = list; 140 return *this; 141 } 142 bool shouldListPasses() const { return listPassesFlag; } 143 144 /// Enable running the reproducer information stored in resources (if 145 /// present). 146 MlirOptMainConfig &runReproducer(bool enableReproducer) { 147 runReproducerFlag = enableReproducer; 148 return *this; 149 }; 150 151 /// Return true if the reproducer should be run. 152 bool shouldRunReproducer() const { return runReproducerFlag; } 153 154 /// Show the registered dialects before trying to load the input file. 155 MlirOptMainConfig &showDialects(bool show) { 156 showDialectsFlag = show; 157 return *this; 158 } 159 bool shouldShowDialects() const { return showDialectsFlag; } 160 161 /// Set the marker on which to split the input into chunks and process each 162 /// chunk independently. Input is not split if empty. 163 MlirOptMainConfig & 164 splitInputFile(std::string splitMarker = kDefaultSplitMarker) { 165 splitInputFileFlag = std::move(splitMarker); 166 return *this; 167 } 168 StringRef inputSplitMarker() const { return splitInputFileFlag; } 169 170 /// Set whether to merge the output chunks into one file using the given 171 /// marker. 172 MlirOptMainConfig & 173 outputSplitMarker(std::string splitMarker = kDefaultSplitMarker) { 174 outputSplitMarkerFlag = std::move(splitMarker); 175 return *this; 176 } 177 StringRef outputSplitMarker() const { return outputSplitMarkerFlag; } 178 179 /// Disable implicit addition of a top-level module op during parsing. 180 MlirOptMainConfig &useExplicitModule(bool useExplicitModule) { 181 useExplicitModuleFlag = useExplicitModule; 182 return *this; 183 } 184 bool shouldUseExplicitModule() const { return useExplicitModuleFlag; } 185 186 /// Set whether to check that emitted diagnostics match `expected-*` lines on 187 /// the corresponding line. This is meant for implementing diagnostic tests. 188 MlirOptMainConfig &verifyDiagnostics(bool verify) { 189 verifyDiagnosticsFlag = verify; 190 return *this; 191 } 192 bool shouldVerifyDiagnostics() const { return verifyDiagnosticsFlag; } 193 194 /// Set whether to run the verifier after each transformation pass. 195 MlirOptMainConfig &verifyPasses(bool verify) { 196 verifyPassesFlag = verify; 197 return *this; 198 } 199 bool shouldVerifyPasses() const { return verifyPassesFlag; } 200 201 /// Set whether to run the verifier on parsing. 202 MlirOptMainConfig &verifyOnParsing(bool verify) { 203 disableVerifierOnParsingFlag = !verify; 204 return *this; 205 } 206 bool shouldVerifyOnParsing() const { return !disableVerifierOnParsingFlag; } 207 208 /// Set whether to run the verifier after each transformation pass. 209 MlirOptMainConfig &verifyRoundtrip(bool verify) { 210 verifyRoundtripFlag = verify; 211 return *this; 212 } 213 bool shouldVerifyRoundtrip() const { return verifyRoundtripFlag; } 214 215 /// Reproducer file generation (no crash required). 216 StringRef getReproducerFilename() const { return generateReproducerFileFlag; } 217 218 protected: 219 /// Allow operation with no registered dialects. 220 /// This option is for convenience during testing only and discouraged in 221 /// general. 222 bool allowUnregisteredDialectsFlag = false; 223 224 /// Configuration for the debugging hooks. 225 tracing::DebugConfig debugConfig; 226 227 /// Verbosity level of diagnostic information. 0: Errors only, 228 /// 1: Errors and warnings, 2: Errors, warnings and remarks. 229 VerbosityLevel diagnosticVerbosityLevelFlag = 230 VerbosityLevel::ErrorsWarningsAndRemarks; 231 232 /// Print the pipeline that will be run. 233 bool dumpPassPipelineFlag = false; 234 235 /// Emit bytecode instead of textual assembly when generating output. 236 bool emitBytecodeFlag = false; 237 238 /// Elide resources when generating bytecode. 239 bool elideResourceDataFromBytecodeFlag = false; 240 241 /// Enable the Debugger action hook: Debugger can intercept MLIR Actions. 242 bool enableDebuggerActionHookFlag = false; 243 244 /// IRDL file to register before processing the input. 245 std::string irdlFileFlag = ""; 246 247 /// Location Breakpoints to filter the action logging. 248 std::vector<tracing::BreakpointManager *> logActionLocationFilter; 249 250 /// Emit bytecode at given version. 251 std::optional<int64_t> emitBytecodeVersion = std::nullopt; 252 253 /// The callback to populate the pass manager. 254 std::function<LogicalResult(PassManager &)> passPipelineCallback; 255 256 /// List the registered passes and return. 257 bool listPassesFlag = false; 258 259 /// Enable running the reproducer. 260 bool runReproducerFlag = false; 261 262 /// Show the registered dialects before trying to load the input file. 263 bool showDialectsFlag = false; 264 265 /// Show the notes in diagnostic information. Notes can be included in 266 /// any diagnostic information, so it is not specified in the verbosity 267 /// level. 268 bool disableDiagnosticNotesFlag = true; 269 270 /// Split the input file based on the given marker into chunks and process 271 /// each chunk independently. Input is not split if empty. 272 std::string splitInputFileFlag = ""; 273 274 /// Merge output chunks into one file using the given marker. 275 std::string outputSplitMarkerFlag = ""; 276 277 /// Use an explicit top-level module op during parsing. 278 bool useExplicitModuleFlag = false; 279 280 /// Set whether to check that emitted diagnostics match `expected-*` lines on 281 /// the corresponding line. This is meant for implementing diagnostic tests. 282 bool verifyDiagnosticsFlag = false; 283 284 /// Run the verifier after each transformation pass. 285 bool verifyPassesFlag = true; 286 287 /// Disable the verifier on parsing. 288 bool disableVerifierOnParsingFlag = false; 289 290 /// Verify that the input IR round-trips perfectly. 291 bool verifyRoundtripFlag = false; 292 293 /// The reproducer output filename (no crash required). 294 std::string generateReproducerFileFlag = ""; 295 }; 296 297 /// This defines the function type used to setup the pass manager. This can be 298 /// used to pass in a callback to setup a default pass pipeline to be applied on 299 /// the loaded IR. 300 using PassPipelineFn = llvm::function_ref<LogicalResult(PassManager &pm)>; 301 302 /// Register and parse command line options. 303 /// - toolName is used for the header displayed by `--help`. 304 /// - registry should contain all the dialects that can be parsed in the source. 305 /// - return std::pair<std::string, std::string> for 306 /// inputFilename and outputFilename command line option values. 307 std::pair<std::string, std::string> 308 registerAndParseCLIOptions(int argc, char **argv, llvm::StringRef toolName, 309 DialectRegistry ®istry); 310 311 /// Perform the core processing behind `mlir-opt`. 312 /// - outputStream is the stream where the resulting IR is printed. 313 /// - buffer is the in-memory file to parser and process. 314 /// - registry should contain all the dialects that can be parsed in the source. 315 /// - config contains the configuration options for the tool. 316 LogicalResult MlirOptMain(llvm::raw_ostream &outputStream, 317 std::unique_ptr<llvm::MemoryBuffer> buffer, 318 DialectRegistry ®istry, 319 const MlirOptMainConfig &config); 320 321 /// Implementation for tools like `mlir-opt`. 322 /// - toolName is used for the header displayed by `--help`. 323 /// - registry should contain all the dialects that can be parsed in the source. 324 LogicalResult MlirOptMain(int argc, char **argv, llvm::StringRef toolName, 325 DialectRegistry ®istry); 326 327 /// Implementation for tools like `mlir-opt`. 328 /// This function can be used with registerAndParseCLIOptions so that 329 /// CLI options can be accessed before running MlirOptMain. 330 /// - inputFilename is the name of the input mlir file. 331 /// - outputFilename is the name of the output file. 332 /// - registry should contain all the dialects that can be parsed in the source. 333 LogicalResult MlirOptMain(int argc, char **argv, llvm::StringRef inputFilename, 334 llvm::StringRef outputFilename, 335 DialectRegistry ®istry); 336 337 /// Helper wrapper to return the result of MlirOptMain directly from main. 338 /// 339 /// Example: 340 /// 341 /// int main(int argc, char **argv) { 342 /// // ... 343 /// return mlir::asMainReturnCode(mlir::MlirOptMain( 344 /// argc, argv, /* ... */); 345 /// } 346 /// 347 inline int asMainReturnCode(LogicalResult r) { 348 return r.succeeded() ? EXIT_SUCCESS : EXIT_FAILURE; 349 } 350 351 } // namespace mlir 352 353 #endif // MLIR_TOOLS_MLIROPT_MLIROPTMAIN_H 354