MLIR 24.0.0git
MlirTranslateMain.cpp
Go to the documentation of this file.
1//===- MlirTranslateMain.cpp - MLIR Translation entry point ---------------===//
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
10#include "mlir/IR/AsmState.h"
11#include "mlir/Parser/Parser.h"
13#include "mlir/Support/Timing.h"
16#include "llvm/Support/SourceMgr.h"
17#include "llvm/Support/ToolOutputFile.h"
18
19using namespace mlir;
20
21//===----------------------------------------------------------------------===//
22// Diagnostic Filter
23//===----------------------------------------------------------------------===//
24
25namespace {
26/// A scoped diagnostic handler that marks non-error diagnostics as handled. As
27/// a result, the main diagnostic handler does not print non-error diagnostics.
28class ErrorDiagnosticFilter : public ScopedDiagnosticHandler {
29public:
30 ErrorDiagnosticFilter(MLIRContext *ctx) : ScopedDiagnosticHandler(ctx) {
31 setHandler([](Diagnostic &diag) {
32 if (diag.getSeverity() != DiagnosticSeverity::Error)
33 return success();
34 return failure();
35 });
36 }
37};
38} // namespace
39
40//===----------------------------------------------------------------------===//
41// Translate Entry Point
42//===----------------------------------------------------------------------===//
43
44static LogicalResult mlirTranslateMainImpl(
45 std::unique_ptr<llvm::MemoryBuffer> input, llvm::raw_ostream &output,
47 const MlirTranslateMainConfig &config, TimingScope timing) {
48 if (translations.empty()) {
49 llvm::errs() << "no translation requested\n";
50 return failure();
51 }
52
53 // Processes the memory buffer with a new MLIRContext.
54 auto processBuffer = [&](std::unique_ptr<llvm::MemoryBuffer> ownedBuffer,
55 raw_ostream &os) {
56 // Many of the translations expect a null-terminated buffer while splitting
57 // the buffer does not guarantee null-termination. Make a copy of the buffer
58 // to ensure null-termination.
59 if (!ownedBuffer->getBuffer().ends_with('\0')) {
60 ownedBuffer = llvm::MemoryBuffer::getMemBufferCopy(
61 ownedBuffer->getBuffer(), ownedBuffer->getBufferIdentifier());
62 }
63 // Temporary buffers for chained translation processing.
64 std::string dataIn;
65 std::string dataOut;
66 LogicalResult result = LogicalResult::success();
67
68 for (const auto [index, translationRequested] :
69 llvm::enumerate(translations)) {
70 llvm::raw_ostream *stream;
71 llvm::raw_string_ostream dataStream(dataOut);
72
73 if (index == translations.size() - 1) {
74 // Output last translation to output.
75 stream = &os;
76 } else {
77 // Output translation to temporary data buffer.
78 stream = &dataStream;
79 }
80
81 TimingScope translationTiming =
82 timing.nest(translationRequested->getDescription());
83
84 MLIRContext context;
87 context.printOpOnDiagnostic(
90 auto sourceMgr = std::make_shared<llvm::SourceMgr>();
91 sourceMgr->AddNewSourceBuffer(std::move(ownedBuffer), SMLoc());
92
93 if (config.getVerifyDiagnosticsLevel() !=
95 // In the diagnostic verification flow, we ignore whether the
96 // translation failed (in most cases, it is expected to fail) and we do
97 // not filter non-error diagnostics even if `errorDiagnosticsOnly` is
98 // set. Instead, we check if the diagnostics were produced as expected.
100 *sourceMgr, &context, config.getVerifyDiagnosticsLevel());
101 (void)(*translationRequested)(sourceMgr, os, &context);
102 result = sourceMgrHandler.verify();
103 } else if (config.shouldEmitErrorDiagnosticsOnly()) {
104 SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context);
105 ErrorDiagnosticFilter diagnosticFilter(&context);
106 result = (*translationRequested)(sourceMgr, *stream, &context);
107 } else {
108 SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context);
109 result = (*translationRequested)(sourceMgr, *stream, &context);
110 }
111 if (failed(result))
112 return result;
113
114 if (index < translations.size() - 1) {
115 // If there are further translations, create a new buffer with the
116 // output data.
117 dataIn = dataOut;
118 dataOut.clear();
119 ownedBuffer = llvm::MemoryBuffer::getMemBuffer(dataIn);
120 }
121 }
122 return result;
123 };
124
125 return splitAndProcessBuffer(std::move(input), processBuffer, output,
126 config.getInputSplitMarker(),
127 config.getOutputSplitMarker());
128}
129
130LogicalResult
131mlir::mlirTranslateMain(std::unique_ptr<llvm::MemoryBuffer> input,
132 llvm::raw_ostream &output,
134 const MlirTranslateMainConfig &config) {
135 return mlirTranslateMainImpl(std::move(input), output, translations, config,
136 TimingScope());
137}
138
139LogicalResult mlir::mlirTranslateMain(int argc, char **argv,
140 llvm::StringRef toolName) {
141
142 static llvm::cl::opt<std::string> inputFilename(
143 llvm::cl::Positional, llvm::cl::desc("<input file>"),
144 llvm::cl::init("-"));
145
146 static llvm::cl::opt<std::string> outputFilename(
147 "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
148 llvm::cl::init("-"));
149
150 static llvm::cl::opt<bool> allowUnregisteredDialects(
151 "allow-unregistered-dialect",
152 llvm::cl::desc("Allow operation with no registered dialects "
153 "(discouraged: testing only!)"),
154 llvm::cl::init(false));
155
156 static llvm::cl::opt<std::string> inputSplitMarker{
157 "split-input-file", llvm::cl::ValueOptional,
158 llvm::cl::callback([&](const std::string &str) {
159 // Implicit value: use default marker if flag was used without value.
160 if (str.empty())
161 inputSplitMarker.setValue(kDefaultSplitMarker);
162 }),
163 llvm::cl::desc("Split the input file into chunks using the given or "
164 "default marker and process each chunk independently"),
165 llvm::cl::init("")};
166
167 static llvm::cl::opt<SourceMgrDiagnosticVerifierHandler::Level>
168 verifyDiagnostics{
169 "verify-diagnostics", llvm::cl::ValueOptional,
170 llvm::cl::desc("Check that emitted diagnostics match expected-* "
171 "lines on the corresponding line"),
172 llvm::cl::values(
173 clEnumValN(
175 "Check all diagnostics (expected, unexpected, near-misses)"),
176 // Implicit value: when passed with no arguments, e.g.
177 // `--verify-diagnostics` or `--verify-diagnostics=`.
178 clEnumValN(
180 "Check all diagnostics (expected, unexpected, near-misses)"),
181 clEnumValN(
183 "only-expected", "Check only expected diagnostics"))};
184
185 static llvm::cl::opt<bool> errorDiagnosticsOnly(
186 "error-diagnostics-only",
187 llvm::cl::desc("Filter all non-error diagnostics "
188 "(discouraged: testing only!)"),
189 llvm::cl::init(false));
190
191 static llvm::cl::opt<std::string> outputSplitMarker(
192 "output-split-marker",
193 llvm::cl::desc("Split marker to use for merging the ouput"),
194 llvm::cl::init(""));
195
196 // Add flags for all the registered translations.
197 llvm::cl::list<const Translation *, bool, TranslationParser>
198 translationsRequested("", llvm::cl::desc("Translations to perform"),
199 llvm::cl::Required);
204 llvm::cl::ParseCommandLineOptions(argc, argv, toolName);
205
206 // Initialize the timing manager.
209 TimingScope timing = tm.getRootScope();
210
211 std::string errorMessage;
212 std::unique_ptr<llvm::MemoryBuffer> input;
213 if (auto inputAlignment = translationsRequested[0]->getInputAlignment())
214 input = openInputFile(inputFilename, *inputAlignment, &errorMessage);
215 else
216 input = openInputFile(inputFilename, &errorMessage);
217 if (!input) {
218 llvm::errs() << errorMessage << "\n";
219 return failure();
220 }
221
222 auto output = openOutputFile(outputFilename, &errorMessage);
223 if (!output) {
224 llvm::errs() << errorMessage << "\n";
225 return failure();
226 }
227
229 config.allowUnregisteredDialects(allowUnregisteredDialects)
230 .errorDiagnosticsOnly(errorDiagnosticsOnly)
231 .outputSplitMarker(outputSplitMarker);
232 if (inputSplitMarker.getNumOccurrences())
233 config.splitInputFile(inputSplitMarker);
234 if (verifyDiagnostics.getNumOccurrences())
235 config.verifyDiagnostics(verifyDiagnostics);
236
237 if (failed(mlirTranslateMainImpl(std::move(input), output->os(),
238 translationsRequested, config,
239 std::move(timing))))
240 return failure();
241
242 output->keep();
243 return success();
244}
return success()
static LogicalResult processBuffer(raw_ostream &os, std::unique_ptr< MemoryBuffer > ownedBuffer, llvm::MemoryBufferRef sourceBuffer, const MlirOptMainConfig &config, DialectRegistry &registry, SourceMgrDiagnosticVerifierHandler *verifyHandler, llvm::ThreadPoolInterface *threadPool)
Parses the memory buffer.
static LogicalResult mlirTranslateMainImpl(std::unique_ptr< llvm::MemoryBuffer > input, llvm::raw_ostream &output, ArrayRef< const Translation * > translations, const MlirTranslateMainConfig &config, TimingScope timing)
static std::string diag(const llvm::Value &value)
Facilities for time measurement and report printing to an output stream.
Definition Timing.h:388
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
void printOpOnDiagnostic(bool enable)
Set the flag specifying if we should attach the operation to diagnostics emitted via Operation::emit.
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
Configuration options for the mlir-translate driver.
MlirTranslateMainConfig & outputSplitMarker(std::string splitMarker)
MlirTranslateMainConfig & splitInputFile(std::string splitMarker=kDefaultSplitMarker)
StringRef getOutputSplitMarker() const
StringRef getInputSplitMarker() const
MlirTranslateMainConfig & verifyDiagnostics(SourceMgrDiagnosticVerifierHandler::Level level)
SourceMgrDiagnosticVerifierHandler::Level getVerifyDiagnosticsLevel() const
MlirTranslateMainConfig & errorDiagnosticsOnly(bool errorOnly)
MlirTranslateMainConfig & allowUnregisteredDialects(bool allow)
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...
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.
Definition Timing.cpp:73
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
Definition Timing.h:272
TimingScope nest(Args... args)
Create a nested timing scope.
Definition Timing.h:311
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:733
Include the generated interface declarations.
LogicalResult mlirTranslateMain(std::unique_ptr< llvm::MemoryBuffer > input, llvm::raw_ostream &output, ArrayRef< const Translation * > translations, const MlirTranslateMainConfig &config={})
Apply the requested translations to an input buffer and write the result to the output stream.
const char *const kDefaultSplitMarker
void registerDefaultTimingManagerCLOptions()
Register a set of useful command-line options that can be used to configure a DefaultTimingManager.
Definition Timing.cpp:612
std::unique_ptr< llvm::ToolOutputFile > openOutputFile(llvm::StringRef outputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for writing.
void registerTranslationCLOptions()
Register command-line options used by the translation registry.
void registerMLIRContextCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
std::unique_ptr< llvm::MemoryBuffer > openInputFile(llvm::StringRef inputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for reading.
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...
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
void applyDefaultTimingManagerCLOptions(DefaultTimingManager &tm)
Apply any values that were registered with 'registerDefaultTimingManagerOptions' to a DefaultTimingMa...
Definition Timing.cpp:617