37 #include "llvm/ADT/StringRef.h"
38 #include "llvm/Remarks/RemarkFormat.h"
39 #include "llvm/Support/CommandLine.h"
40 #include "llvm/Support/InitLLVM.h"
41 #include "llvm/Support/LogicalResult.h"
42 #include "llvm/Support/ManagedStatic.h"
43 #include "llvm/Support/Process.h"
44 #include "llvm/Support/Regex.h"
45 #include "llvm/Support/SourceMgr.h"
46 #include "llvm/Support/ThreadPool.h"
47 #include "llvm/Support/ToolOutputFile.h"
53 class BytecodeVersionParser :
public cl::parser<std::optional<int64_t>> {
55 BytecodeVersionParser(cl::Option &o)
56 : cl::parser<std::optional<int64_t>>(o) {}
58 bool parse(cl::Option &o, StringRef , StringRef arg,
59 std::optional<int64_t> &v) {
61 if (getAsSignedInteger(arg, 10, w))
62 return o.error(
"Invalid argument '" + arg +
63 "', only integer is supported.");
72 MlirOptMainConfigCLOptions() {
78 static cl::opt<bool,
true> allowUnregisteredDialects(
79 "allow-unregistered-dialect",
80 cl::desc(
"Allow operation with no registered dialects"),
81 cl::location(allowUnregisteredDialectsFlag), cl::init(
false));
83 static cl::opt<bool,
true> dumpPassPipeline(
84 "dump-pass-pipeline", cl::desc(
"Print the pipeline that will be run"),
85 cl::location(dumpPassPipelineFlag), cl::init(
false));
87 static cl::opt<bool,
true> emitBytecode(
88 "emit-bytecode", cl::desc(
"Emit bytecode when generating output"),
89 cl::location(emitBytecodeFlag), cl::init(
false));
91 static cl::opt<bool,
true> elideResourcesFromBytecode(
92 "elide-resource-data-from-bytecode",
93 cl::desc(
"Elide resources when generating bytecode"),
94 cl::location(elideResourceDataFromBytecodeFlag), cl::init(
false));
96 static cl::opt<std::optional<int64_t>,
true,
97 BytecodeVersionParser>
99 "emit-bytecode-version",
100 cl::desc(
"Use specified bytecode when generating output"),
101 cl::location(emitBytecodeVersion), cl::init(std::nullopt));
103 static cl::opt<std::string,
true> irdlFile(
105 cl::desc(
"IRDL file to register before processing the input"),
106 cl::location(irdlFileFlag), cl::init(
""), cl::value_desc(
"filename"));
109 diagnosticVerbosityLevel(
110 "mlir-diagnostic-verbosity-level",
111 cl::desc(
"Choose level of diagnostic information"),
112 cl::location(diagnosticVerbosityLevelFlag),
117 "Errors and warnings"),
119 "Errors, warnings and remarks")));
121 static cl::opt<bool,
true> disableDiagnosticNotes(
122 "mlir-disable-diagnostic-notes", cl::desc(
"Disable diagnostic notes."),
123 cl::location(disableDiagnosticNotesFlag), cl::init(
false));
125 static cl::opt<bool,
true> explicitModule(
126 "no-implicit-module",
127 cl::desc(
"Disable implicit addition of a top-level module op during "
129 cl::location(useExplicitModuleFlag), cl::init(
false));
131 static cl::opt<bool,
true> listPasses(
132 "list-passes", cl::desc(
"Print the list of registered passes and exit"),
133 cl::location(listPassesFlag), cl::init(
false));
135 static cl::opt<bool,
true> runReproducer(
136 "run-reproducer", cl::desc(
"Run the pipeline stored in the reproducer"),
137 cl::location(runReproducerFlag), cl::init(
false));
139 static cl::opt<bool,
true> showDialects(
141 cl::desc(
"Print the list of registered dialects and exit"),
142 cl::location(showDialectsFlag), cl::init(
false));
144 static cl::opt<std::string,
true> splitInputFile{
146 llvm::cl::ValueOptional,
147 cl::callback([&](
const std::string &str) {
152 cl::desc(
"Split the input file into chunks using the given or "
153 "default marker and process each chunk independently"),
154 cl::location(splitInputFileFlag),
157 static cl::opt<std::string,
true> outputSplitMarker(
158 "output-split-marker",
159 cl::desc(
"Split marker to use for merging the ouput"),
165 "verify-diagnostics", llvm::cl::ValueOptional,
166 cl::desc(
"Check that emitted diagnostics match expected-* lines on "
167 "the corresponding line"),
168 cl::location(verifyDiagnosticsFlag),
172 "Check all diagnostics (expected, unexpected, "
177 "Check all diagnostics (expected, unexpected, "
181 "only-expected",
"Check only expected diagnostics"))};
183 static cl::opt<bool,
true> verifyPasses(
185 cl::desc(
"Run the verifier after each transformation pass"),
186 cl::location(verifyPassesFlag), cl::init(
true));
188 static cl::opt<bool,
true> disableVerifyOnParsing(
189 "mlir-very-unsafe-disable-verifier-on-parsing",
190 cl::desc(
"Disable the verifier on parsing (very unsafe)"),
191 cl::location(disableVerifierOnParsingFlag), cl::init(
false));
193 static cl::opt<bool,
true> verifyRoundtrip(
195 cl::desc(
"Round-trip the IR after parsing and ensure it succeeds"),
196 cl::location(verifyRoundtripFlag), cl::init(
false));
198 static cl::list<std::string> passPlugins(
199 "load-pass-plugin", cl::desc(
"Load passes from plugin library"));
201 static cl::opt<std::string,
true>
202 generateReproducerFile(
203 "mlir-generate-reproducer",
205 "Generate an mlir reproducer at the provided filename"
206 " (no crash required)"),
207 cl::location(generateReproducerFileFlag), cl::init(
""),
208 cl::value_desc(
"filename"));
210 static cl::OptionCategory remarkCategory(
212 "Filter remarks by regular expression (llvm::Regex syntax).");
216 llvm::cl::desc(
"Specify the format for remark output."),
217 cl::location(remarkFormatFlag),
218 llvm::cl::value_desc(
"format"),
222 "Print as emitRemark to command-line"),
226 "bitstream",
"Print bitstream file")),
227 llvm::cl::cat(remarkCategory)};
229 static cl::opt<std::string,
true> remarksAll(
231 cl::desc(
"Show all remarks: passed, missed, failed, analysis"),
232 cl::location(remarksAllFilterFlag), cl::init(
""),
233 cl::cat(remarkCategory));
235 static cl::opt<std::string,
true> remarksFile(
236 "remarks-output-file",
238 "Output file for yaml and bitstream remark formats. Default is "
239 "mlir-remarks.yaml or mlir-remarks.bitstream"),
240 cl::location(remarksOutputFileFlag), cl::init(
""),
241 cl::cat(remarkCategory));
243 static cl::opt<std::string,
true> remarksPassed(
244 "remarks-filter-passed", cl::desc(
"Show passed remarks"),
245 cl::location(remarksPassedFilterFlag), cl::init(
""),
246 cl::cat(remarkCategory));
248 static cl::opt<std::string,
true> remarksFailed(
249 "remarks-filter-failed", cl::desc(
"Show failed remarks"),
250 cl::location(remarksFailedFilterFlag), cl::init(
""),
251 cl::cat(remarkCategory));
253 static cl::opt<std::string,
true> remarksMissed(
254 "remarks-filter-missed", cl::desc(
"Show missed remarks"),
255 cl::location(remarksMissedFilterFlag), cl::init(
""),
256 cl::cat(remarkCategory));
258 static cl::opt<std::string,
true> remarksAnalyse(
259 "remarks-filter-analyse", cl::desc(
"Show analysis remarks"),
260 cl::location(remarksAnalyseFilterFlag), cl::init(
""),
261 cl::cat(remarkCategory));
264 passPlugins.setCallback([&](
const std::string &pluginPath) {
267 errs() <<
"Failed to load passes from '" << pluginPath
268 <<
"'. Request ignored.\n";
271 plugin.get().registerPassRegistryCallbacks();
274 static cl::list<std::string> dialectPlugins(
275 "load-dialect-plugin", cl::desc(
"Load dialects from plugin library"));
276 this->dialectPlugins = std::addressof(dialectPlugins);
279 setPassPipelineParser(passPipeline);
287 cl::list<std::string> *dialectPlugins =
nullptr;
295 bool showNotes =
true)
298 auto severity =
diag.getSeverity();
322 llvm_unreachable(
"Unknown diagnostic severity");
343 auto errorHandler = [&](
const Twine &msg) {
349 if (this->shouldDumpPassPipeline()) {
352 llvm::errs() <<
"\n";
359 void MlirOptMainConfigCLOptions::setDialectPluginsCallback(
361 dialectPlugins->setCallback([&](
const std::string &pluginPath) {
364 errs() <<
"Failed to load dialect plugin from '" << pluginPath
365 <<
"'. Request ignored.\n";
368 plugin.get().registerDialectRegistryCallbacks(registry);
374 registry.
insert<irdl::IRDLDialect>();
378 std::string errorMessage;
379 std::unique_ptr<MemoryBuffer> file =
openInputFile(irdlFile, &errorMessage);
388 sourceMgr.AddNewSourceBuffer(std::move(file), SMLoc());
413 StringRef irdlFile =
config.getIrdlFile();
417 std::string testType = (useBytecode) ?
"bytecode" :
"textual";
422 llvm::raw_string_ostream ostream(buffer);
426 <<
"failed to write bytecode, cannot verify round-trip.\n";
435 &fallbackResourceMap);
436 roundtripModule = parseSourceString<Operation *>(buffer, parseConfig);
437 if (!roundtripModule) {
438 op->
emitOpError() <<
"failed to parse " << testType
439 <<
" content back, cannot verify round-trip.\n";
446 std::string reference, roundtrip;
448 llvm::raw_string_ostream ostreamref(reference);
449 op->
print(ostreamref,
451 llvm::raw_string_ostream ostreamrndtrip(roundtrip);
452 roundtripModule.
get()->print(
456 if (reference != roundtrip) {
460 <<
" roundTrip testing roundtripped module differs "
461 "from reference:\n<<<<<<Reference\n"
462 << reference <<
"\n=====\n"
463 << roundtrip <<
"\n>>>>>roundtripped\n";
473 return success(succeeded(txtStatus) && succeeded(bcStatus));
484 const std::shared_ptr<llvm::SourceMgr> &sourceMgr,
502 &fallbackResourceMap);
503 if (
config.shouldRunReproducer())
509 sourceMgr, parseConfig, !
config.shouldUseExplicitModule());
515 if (
config.shouldVerifyRoundtrip() &&
522 config.getRemarksAllFilter(),
config.getRemarksPassedFilter(),
523 config.getRemarksMissedFilter(),
config.getRemarksAnalyseFilter(),
524 config.getRemarksFailedFilter()};
528 switch (
config.getRemarkFormat()) {
531 ctx,
nullptr, cats,
true )))
536 std::string file =
config.getRemarksOutputFile().empty()
537 ?
"mlir-remarks.yaml"
538 :
config.getRemarksOutputFile();
540 ctx, file, llvm::remarks::Format::YAML, cats)))
546 std::string file =
config.getRemarksOutputFile().empty()
547 ?
"mlir-remarks.bitstream"
548 :
config.getRemarksOutputFile();
550 ctx, file, llvm::remarks::Format::Bitstream, cats)))
572 if (!
config.getReproducerFilename().empty()) {
576 config.getReproducerFilename());
581 if (
config.shouldEmitBytecode()) {
583 if (
auto v =
config.bytecodeVersionToEmit())
585 if (
config.shouldElideResourceDataFromBytecode())
590 if (
config.bytecodeVersionToEmit().has_value())
592 <<
"bytecode version while not emitting bytecode";
594 &fallbackResourceMap);
603 llvm::MemoryBufferRef sourceBuffer,
606 llvm::ThreadPoolInterface *threadPool) {
608 auto sourceMgr = std::make_shared<SourceMgr>();
611 sourceMgr->AddNewSourceBuffer(
612 llvm::MemoryBuffer::getMemBuffer(sourceBuffer,
615 sourceMgr->AddNewSourceBuffer(std::move(ownedBuffer), SMLoc());
625 StringRef irdlFile =
config.getIrdlFile();
631 if (
config.shouldVerifyDiagnostics())
639 if (!
config.shouldVerifyDiagnostics()) {
641 DiagnosticFilter diagnosticFilter(&context,
642 config.getDiagnosticVerbosityLevel(),
643 config.shouldShowNotes());
655 std::pair<std::string, std::string>
657 llvm::StringRef toolName,
659 static cl::opt<std::string> inputFilename(
660 cl::Positional, cl::desc(
"<input file>"), cl::init(
"-"));
662 static cl::opt<std::string> outputFilename(
"o", cl::desc(
"Output filename"),
663 cl::value_desc(
"filename"),
674 std::string helpHeader = (toolName +
"\nAvailable Dialects: ").str();
676 llvm::raw_string_ostream os(helpHeader);
678 [&](
auto name) { os << name; });
681 cl::ParseCommandLineOptions(argc, argv, helpHeader);
682 return std::make_pair(inputFilename.getValue(), outputFilename.getValue());
686 llvm::outs() <<
"Available Dialects: ";
688 llvm::outs() <<
"\n";
698 std::unique_ptr<llvm::MemoryBuffer> buffer,
701 if (
config.shouldShowDialects())
704 if (
config.shouldListPasses())
711 ThreadPoolInterface *threadPool =
nullptr;
722 sourceMgr.AddNewSourceBuffer(
723 llvm::MemoryBuffer::getMemBuffer(buffer->getMemBufferRef(),
730 sourceMgr, &threadPoolCtx,
config.verifyDiagnosticsLevel());
731 auto chunkFn = [&](std::unique_ptr<MemoryBuffer> chunkBuffer,
732 llvm::MemoryBufferRef sourceBuffer, raw_ostream &os) {
734 os, std::move(chunkBuffer), sourceBuffer,
config, registry,
735 config.shouldVerifyDiagnostics() ? &sourceMgrHandler :
nullptr,
739 llvm::MemoryBuffer::getMemBuffer(buffer->getMemBufferRef(),
741 chunkFn, outputStream,
config.inputSplitMarker(),
742 config.outputSplitMarker());
749 llvm::StringRef inputFilename,
750 llvm::StringRef outputFilename,
753 InitLLVM y(argc, argv);
757 if (
config.shouldShowDialects())
760 if (
config.shouldListPasses())
766 if (inputFilename ==
"-" &&
767 sys::Process::FileDescriptorIsDisplayed(fileno(stdin)))
768 llvm::errs() <<
"(processing input from stdin now, hit ctrl-c/ctrl-d to "
772 std::string errorMessage;
775 llvm::errs() << errorMessage <<
"\n";
781 llvm::errs() << errorMessage <<
"\n";
796 std::string inputFilename, outputFilename;
797 std::tie(inputFilename, outputFilename) =
800 return MlirOptMain(argc, argv, inputFilename, outputFilename, registry);
static LogicalResult printRegisteredDialects(DialectRegistry ®istry)
LogicalResult loadIRDLDialects(StringRef irdlFile, MLIRContext &ctx)
static LogicalResult doVerifyRoundTrip(Operation *op, const MlirOptMainConfig &config, bool useBytecode)
static LogicalResult processBuffer(raw_ostream &os, std::unique_ptr< MemoryBuffer > ownedBuffer, llvm::MemoryBufferRef sourceBuffer, const MlirOptMainConfig &config, DialectRegistry ®istry, SourceMgrDiagnosticVerifierHandler *verifyHandler, llvm::ThreadPoolInterface *threadPool)
Parses the memory buffer.
static LogicalResult printRegisteredPassesAndReturn()
ManagedStatic< MlirOptMainConfigCLOptions > clOptionsConfig
static LogicalResult performActions(raw_ostream &os, const std::shared_ptr< llvm::SourceMgr > &sourceMgr, MLIRContext *context, const MlirOptMainConfig &config)
Perform the actions on the input file indicated by the command line flags within the specified contex...
static std::string diag(const llvm::Value &value)
This class provides management for the lifetime of the state used when printing the IR.
This class contains the configuration used for the bytecode writer.
void setElideResourceDataFlag(bool shouldElideResourceData=true)
Set a boolean flag to skip emission of resources into the bytecode file.
void setDesiredBytecodeVersion(int64_t bytecodeVersion)
Set the desired bytecode version to emit.
Facilities for time measurement and report printing to an output stream.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
static llvm::Expected< DialectPlugin > load(const std::string &filename)
Attempts to load a dialect plugin from a given file.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
auto getDialectNames() const
Return the names of dialects known to this registry.
A fallback map containing external resources not explicitly handled by another parser/printer.
MLIRContext is the top-level object for a collection of MLIR operations.
void appendDialectRegistry(const DialectRegistry ®istry)
Append the contents of the given dialect registry to the registry associated with this context.
void disableMultithreading(bool disable=true)
Set the flag specifying if multi-threading is disabled by the context.
void setThreadPool(llvm::ThreadPoolInterface &pool)
Set a new thread pool to be used in this context.
void enableMultithreading(bool enable=true)
void printOpOnDiagnostic(bool enable)
Set the flag specifying if we should attach the operation to diagnostics emitted via Operation::emit.
const DialectRegistry & getDialectRegistry()
Return the dialect registry associated with this context.
llvm::ThreadPoolInterface & getThreadPool()
Return the thread pool used by this context.
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
Configuration options for the mlir-opt tool.
static MlirOptMainConfig createFromCLOptions()
Create a new config with the default set from the CL options.
static void registerCLOptions(DialectRegistry &dialectRegistry)
Register the options as global LLVM command line options.
MlirOptMainConfig & setPassPipelineParser(const PassPipelineCLParser &parser)
Set the parser to use to populate the pass manager.
@ Implicit
Implicit nesting behavior.
iterator_range< pass_iterator > getPasses()
static StringRef getAnyOpAnchorName()
Return the string name used to anchor op-agnostic pass managers that operate generically on any viabl...
Set of flags used to control the behavior of the various IR print methods (e.g.
A wrapper class that allows for printing an operation with a custom AsmState, useful to act as a "str...
Operation is the basic unit of execution within MLIR.
MLIRContext * getContext()
Return the context this operation is associated with.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
OpTy get() const
Allow accessing the internal op.
This class represents a configuration for the MLIR assembly parser.
The main pass manager and pipeline builder.
MLIRContext * getContext() const
Return an instance of the context.
LogicalResult run(Operation *op)
Run the passes within this manager on the provided operation.
void enableVerifier(bool enabled=true)
Runs the verifier after each individual pass.
void enableTiming(TimingScope &timingScope)
Add an instrumentation to time the execution of passes and the computation of analyses.
This class implements a command-line parser for MLIR passes.
LogicalResult addToPipeline(OpPassManager &pm, function_ref< LogicalResult(const Twine &)> errorHandler) const
Adds the passes defined by this parser entry to the given pass manager.
static llvm::Expected< PassPlugin > load(const std::string &filename)
Attempts to load a pass plugin from a given file.
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
This class is a utility diagnostic handler for use with llvm::SourceMgr.
This class is a utility diagnostic handler for use with llvm::SourceMgr that verifies that emitted di...
void registerInContext(MLIRContext *ctx)
Register this handler with the given context.
LogicalResult verify()
Returns the status of the handler and verifies that all expected diagnostics were emitted.
TimingScope getRootScope()
Get the root timer of this timing manager wrapped in a TimingScope for convenience.
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
TimingScope nest(Args... args)
Create a nested timing scope.
void stop()
Manually stop the timer early.
static DebugConfig createFromCLOptions()
Create a new config with the default set from the CL options.
static void registerCLOptions()
Register the options as global LLVM command line options.
static void registerCLOptions()
Register the command line options for debug counters.
This is a RAII class that installs the debug handlers on the context based on the provided configurat...
The OpAsmOpInterface, see OpAsmInterface.td for more details.
llvm::LogicalResult loadDialects(ModuleOp op)
Load all the dialects defined in the module.
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
std::unique_ptr< llvm::MemoryBuffer > openInputFile(llvm::StringRef inputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for reading.
LogicalResult applyPassManagerCLOptions(PassManager &pm)
Apply any values provided to the pass manager options that were registered with 'registerPassManagerO...
const char *const kDefaultSplitMarker
void registerDefaultTimingManagerCLOptions()
Register a set of useful command-line options that can be used to configure a DefaultTimingManager.
const FrozenRewritePatternSet GreedyRewriteConfig config
void printRegisteredPasses()
Prints the passes that were previously registered and stored in passRegistry.
LogicalResult MlirOptMain(llvm::raw_ostream &outputStream, std::unique_ptr< llvm::MemoryBuffer > buffer, DialectRegistry ®istry, const MlirOptMainConfig &config)
Perform the core processing behind mlir-opt.
std::unique_ptr< llvm::ToolOutputFile > openOutputFile(llvm::StringRef outputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for writing.
std::string makeReproducer(StringRef anchorName, const llvm::iterator_range< OpPassManager::pass_iterator > &passes, Operation *op, StringRef outputFile, bool disableThreads=false, bool verifyPasses=false)
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void registerMLIRContextCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
LogicalResult splitAndProcessBuffer(std::unique_ptr< llvm::MemoryBuffer > originalBuffer, ChunkBufferHandler processChunkBuffer, raw_ostream &os, llvm::StringRef inputSplitMarker=kDefaultSplitMarker, llvm::StringRef outputSplitMarker="")
Splits the specified buffer on a marker (// ----- by default), processes each chunk independently acc...
OwningOpRef< Operation * > parseSourceFileForTool(const std::shared_ptr< llvm::SourceMgr > &sourceMgr, const ParserConfig &config, bool insertImplicitModule)
This parses the file specified by the indicated SourceMgr.
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
void registerPassManagerCLOptions()
Register a set of useful command-line options that can be used to configure a pass manager.
void applyDefaultTimingManagerCLOptions(DefaultTimingManager &tm)
Apply any values that were registered with 'registerDefaultTimingManagerOptions' to a DefaultTimingMa...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
@ REMARK_FORMAT_BITSTREAM
std::pair< std::string, std::string > registerAndParseCLIOptions(int argc, char **argv, llvm::StringRef toolName, DialectRegistry ®istry)
Register and parse command line options.
VerbosityLevel
enum class to indicate the verbosity level of the diagnostic filter.
@ ErrorsWarningsAndRemarks
LogicalResult writeBytecodeToFile(Operation *op, raw_ostream &os, const BytecodeWriterConfig &config={})
Write the bytecode for the given operation to the provided output stream.
void attachResourceParser(ParserConfig &config)
Attach an assembly resource parser to 'config' that collects the MLIR reproducer configuration into t...
LogicalResult apply(PassManager &pm) const
Apply the reproducer options to 'pm' and its context.