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
9#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
10#include "mlir/IR/AsmState.h"
11#include "mlir/IR/BuiltinOps.h"
12#include "mlir/IR/Dialect.h"
13#include "mlir/IR/Verifier.h"
14#include "mlir/Parser/Parser.h"
15#include "mlir/Support/FileUtilities.h"
16#include "mlir/Support/LogicalResult.h"
17#include "mlir/Support/Timing.h"
18#include "mlir/Support/ToolUtilities.h"
19#include "mlir/Tools/mlir-translate/Translation.h"
20#include "llvm/Support/InitLLVM.h"
21#include "llvm/Support/SourceMgr.h"
22#include "llvm/Support/ToolOutputFile.h"
23
24using namespace mlir;
25
26//===----------------------------------------------------------------------===//
27// Diagnostic Filter
28//===----------------------------------------------------------------------===//
29
30namespace {
31/// A scoped diagnostic handler that marks non-error diagnostics as handled. As
32/// a result, the main diagnostic handler does not print non-error diagnostics.
33class ErrorDiagnosticFilter : public ScopedDiagnosticHandler {
34public:
35 ErrorDiagnosticFilter(MLIRContext *ctx) : ScopedDiagnosticHandler(ctx) {
36 setHandler([](Diagnostic &diag) {
37 if (diag.getSeverity() != DiagnosticSeverity::Error)
38 return success();
39 return failure();
40 });
41 }
42};
43} // namespace
44
45//===----------------------------------------------------------------------===//
46// Translate Entry Point
47//===----------------------------------------------------------------------===//
48
49LogicalResult mlir::mlirTranslateMain(int argc, char **argv,
50 llvm::StringRef toolName) {
51
52 static llvm::cl::opt<std::string> inputFilename(
53 llvm::cl::Positional, llvm::cl::desc("<input file>"),
54 llvm::cl::init(Val: "-"));
55
56 static llvm::cl::opt<std::string> outputFilename(
57 "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
58 llvm::cl::init(Val: "-"));
59
60 static llvm::cl::opt<bool> allowUnregisteredDialects(
61 "allow-unregistered-dialect",
62 llvm::cl::desc("Allow operation with no registered dialects (discouraged: testing only!)"),
63 llvm::cl::init(Val: false));
64
65 static llvm::cl::opt<std::string> inputSplitMarker{
66 "split-input-file", llvm::cl::ValueOptional,
67 llvm::cl::callback(CB: [&](const std::string &str) {
68 // Implicit value: use default marker if flag was used without value.
69 if (str.empty())
70 inputSplitMarker.setValue(V: kDefaultSplitMarker);
71 }),
72 llvm::cl::desc("Split the input file into chunks using the given or "
73 "default marker and process each chunk independently"),
74 llvm::cl::init(Val: "")};
75
76 static llvm::cl::opt<bool> verifyDiagnostics(
77 "verify-diagnostics",
78 llvm::cl::desc("Check that emitted diagnostics match "
79 "expected-* lines on the corresponding line"),
80 llvm::cl::init(Val: false));
81
82 static llvm::cl::opt<bool> errorDiagnosticsOnly(
83 "error-diagnostics-only",
84 llvm::cl::desc("Filter all non-error diagnostics "
85 "(discouraged: testing only!)"),
86 llvm::cl::init(Val: false));
87
88 static llvm::cl::opt<std::string> outputSplitMarker(
89 "output-split-marker",
90 llvm::cl::desc("Split marker to use for merging the ouput"),
91 llvm::cl::init(Val: ""));
92
93 llvm::InitLLVM y(argc, argv);
94
95 // Add flags for all the registered translations.
96 llvm::cl::list<const Translation *, bool, TranslationParser>
97 translationsRequested("", llvm::cl::desc("Translations to perform"),
98 llvm::cl::Required);
99 registerAsmPrinterCLOptions();
100 registerMLIRContextCLOptions();
101 registerTranslationCLOptions();
102 registerDefaultTimingManagerCLOptions();
103 llvm::cl::ParseCommandLineOptions(argc, argv, Overview: toolName);
104
105 // Initialize the timing manager.
106 DefaultTimingManager tm;
107 applyDefaultTimingManagerCLOptions(tm);
108 TimingScope timing = tm.getRootScope();
109
110 std::string errorMessage;
111 std::unique_ptr<llvm::MemoryBuffer> input;
112 if (auto inputAlignment = translationsRequested[0]->getInputAlignment())
113 input = openInputFile(inputFilename, alignment: *inputAlignment, errorMessage: &errorMessage);
114 else
115 input = openInputFile(inputFilename, errorMessage: &errorMessage);
116 if (!input) {
117 llvm::errs() << errorMessage << "\n";
118 return failure();
119 }
120
121 auto output = openOutputFile(outputFilename, errorMessage: &errorMessage);
122 if (!output) {
123 llvm::errs() << errorMessage << "\n";
124 return failure();
125 }
126
127 // Processes the memory buffer with a new MLIRContext.
128 auto processBuffer = [&](std::unique_ptr<llvm::MemoryBuffer> ownedBuffer,
129 raw_ostream &os) {
130 // Temporary buffers for chained translation processing.
131 std::string dataIn;
132 std::string dataOut;
133 LogicalResult result = LogicalResult::success();
134
135 for (size_t i = 0, e = translationsRequested.size(); i < e; ++i) {
136 llvm::raw_ostream *stream;
137 llvm::raw_string_ostream dataStream(dataOut);
138
139 if (i == e - 1) {
140 // Output last translation to output.
141 stream = &os;
142 } else {
143 // Output translation to temporary data buffer.
144 stream = &dataStream;
145 }
146
147 const Translation *translationRequested = translationsRequested[i];
148 TimingScope translationTiming =
149 timing.nest(args: translationRequested->getDescription());
150
151 MLIRContext context;
152 context.allowUnregisteredDialects(allow: allowUnregisteredDialects);
153 context.printOpOnDiagnostic(enable: !verifyDiagnostics);
154 auto sourceMgr = std::make_shared<llvm::SourceMgr>();
155 sourceMgr->AddNewSourceBuffer(F: std::move(ownedBuffer), IncludeLoc: SMLoc());
156
157 if (verifyDiagnostics) {
158 // In the diagnostic verification flow, we ignore whether the
159 // translation failed (in most cases, it is expected to fail) and we do
160 // not filter non-error diagnostics even if `errorDiagnosticsOnly` is
161 // set. Instead, we check if the diagnostics were produced as expected.
162 SourceMgrDiagnosticVerifierHandler sourceMgrHandler(*sourceMgr,
163 &context);
164 (void)(*translationRequested)(sourceMgr, os, &context);
165 result = sourceMgrHandler.verify();
166 } else if (errorDiagnosticsOnly) {
167 SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context);
168 ErrorDiagnosticFilter diagnosticFilter(&context);
169 result = (*translationRequested)(sourceMgr, *stream, &context);
170 } else {
171 SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context);
172 result = (*translationRequested)(sourceMgr, *stream, &context);
173 }
174 if (failed(result))
175 return result;
176
177 if (i < e - 1) {
178 // If there are further translations, create a new buffer with the
179 // output data.
180 dataIn = dataOut;
181 dataOut.clear();
182 ownedBuffer = llvm::MemoryBuffer::getMemBuffer(InputData: dataIn);
183 }
184 }
185 return result;
186 };
187
188 if (failed(result: splitAndProcessBuffer(originalBuffer: std::move(input), processChunkBuffer: processBuffer,
189 os&: output->os(), inputSplitMarker,
190 outputSplitMarker)))
191 return failure();
192
193 output->keep();
194 return success();
195}
196

source code of mlir/lib/Tools/mlir-translate/MlirTranslateMain.cpp