xref: /llvm-project/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h (revision d0b7633d7ad566579bfb794f95cce9aef294c92b)
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 &registry);
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 &registry,
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 &registry);
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 &registry);
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