1ee1d447eSRiver Riddle //===- MlirTranslateMain.cpp - MLIR Translation entry point ---------------===//
2ee1d447eSRiver Riddle //
3ee1d447eSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ee1d447eSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5ee1d447eSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ee1d447eSRiver Riddle //
7ee1d447eSRiver Riddle //===----------------------------------------------------------------------===//
8ee1d447eSRiver Riddle
9ee1d447eSRiver Riddle #include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
10ee1d447eSRiver Riddle #include "mlir/IR/AsmState.h"
11ee1d447eSRiver Riddle #include "mlir/IR/BuiltinOps.h"
12ee1d447eSRiver Riddle #include "mlir/IR/Dialect.h"
13ee1d447eSRiver Riddle #include "mlir/IR/Verifier.h"
14ee1d447eSRiver Riddle #include "mlir/Parser/Parser.h"
15ee1d447eSRiver Riddle #include "mlir/Support/FileUtilities.h"
16c3b4e279STobias Gysi #include "mlir/Support/Timing.h"
17ee1d447eSRiver Riddle #include "mlir/Support/ToolUtilities.h"
18ee1d447eSRiver Riddle #include "mlir/Tools/mlir-translate/Translation.h"
19ee1d447eSRiver Riddle #include "llvm/Support/InitLLVM.h"
20ee1d447eSRiver Riddle #include "llvm/Support/SourceMgr.h"
21ee1d447eSRiver Riddle #include "llvm/Support/ToolOutputFile.h"
22ee1d447eSRiver Riddle
23ee1d447eSRiver Riddle using namespace mlir;
24ee1d447eSRiver Riddle
25ee1d447eSRiver Riddle //===----------------------------------------------------------------------===//
261ade6f36STobias Gysi // Diagnostic Filter
271ade6f36STobias Gysi //===----------------------------------------------------------------------===//
281ade6f36STobias Gysi
291ade6f36STobias Gysi namespace {
301ade6f36STobias Gysi /// A scoped diagnostic handler that marks non-error diagnostics as handled. As
311ade6f36STobias Gysi /// a result, the main diagnostic handler does not print non-error diagnostics.
321ade6f36STobias Gysi class ErrorDiagnosticFilter : public ScopedDiagnosticHandler {
331ade6f36STobias Gysi public:
ErrorDiagnosticFilter(MLIRContext * ctx)341ade6f36STobias Gysi ErrorDiagnosticFilter(MLIRContext *ctx) : ScopedDiagnosticHandler(ctx) {
351ade6f36STobias Gysi setHandler([](Diagnostic &diag) {
361ade6f36STobias Gysi if (diag.getSeverity() != DiagnosticSeverity::Error)
371ade6f36STobias Gysi return success();
381ade6f36STobias Gysi return failure();
391ade6f36STobias Gysi });
401ade6f36STobias Gysi }
411ade6f36STobias Gysi };
421ade6f36STobias Gysi } // namespace
431ade6f36STobias Gysi
441ade6f36STobias Gysi //===----------------------------------------------------------------------===//
451ade6f36STobias Gysi // Translate Entry Point
46ee1d447eSRiver Riddle //===----------------------------------------------------------------------===//
47ee1d447eSRiver Riddle
mlirTranslateMain(int argc,char ** argv,llvm::StringRef toolName)482ef95efbSChris Lattner LogicalResult mlir::mlirTranslateMain(int argc, char **argv,
492ef95efbSChris Lattner llvm::StringRef toolName) {
50ee1d447eSRiver Riddle
51ee1d447eSRiver Riddle static llvm::cl::opt<std::string> inputFilename(
52ee1d447eSRiver Riddle llvm::cl::Positional, llvm::cl::desc("<input file>"),
53ee1d447eSRiver Riddle llvm::cl::init("-"));
54ee1d447eSRiver Riddle
55ee1d447eSRiver Riddle static llvm::cl::opt<std::string> outputFilename(
56ee1d447eSRiver Riddle "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
57ee1d447eSRiver Riddle llvm::cl::init("-"));
58ee1d447eSRiver Riddle
59ee1d447eSRiver Riddle static llvm::cl::opt<bool> allowUnregisteredDialects(
60ee1d447eSRiver Riddle "allow-unregistered-dialect",
615cf549e6SMehdi Amini llvm::cl::desc("Allow operation with no registered dialects (discouraged: testing only!)"),
62ee1d447eSRiver Riddle llvm::cl::init(false));
63ee1d447eSRiver Riddle
64*daa350c1SBenjamin Kramer static llvm::cl::opt<std::string> inputSplitMarker{
65516ccce7SIngo Müller "split-input-file", llvm::cl::ValueOptional,
66516ccce7SIngo Müller llvm::cl::callback([&](const std::string &str) {
67516ccce7SIngo Müller // Implicit value: use default marker if flag was used without value.
68516ccce7SIngo Müller if (str.empty())
69516ccce7SIngo Müller inputSplitMarker.setValue(kDefaultSplitMarker);
70516ccce7SIngo Müller }),
71516ccce7SIngo Müller llvm::cl::desc("Split the input file into chunks using the given or "
72516ccce7SIngo Müller "default marker and process each chunk independently"),
73*daa350c1SBenjamin Kramer llvm::cl::init("")};
74ee1d447eSRiver Riddle
75ee1d447eSRiver Riddle static llvm::cl::opt<bool> verifyDiagnostics(
76ee1d447eSRiver Riddle "verify-diagnostics",
77ee1d447eSRiver Riddle llvm::cl::desc("Check that emitted diagnostics match "
78ee1d447eSRiver Riddle "expected-* lines on the corresponding line"),
79ee1d447eSRiver Riddle llvm::cl::init(false));
80ee1d447eSRiver Riddle
811ade6f36STobias Gysi static llvm::cl::opt<bool> errorDiagnosticsOnly(
821ade6f36STobias Gysi "error-diagnostics-only",
831ade6f36STobias Gysi llvm::cl::desc("Filter all non-error diagnostics "
841ade6f36STobias Gysi "(discouraged: testing only!)"),
851ade6f36STobias Gysi llvm::cl::init(false));
861ade6f36STobias Gysi
87516ccce7SIngo Müller static llvm::cl::opt<std::string> outputSplitMarker(
88516ccce7SIngo Müller "output-split-marker",
89516ccce7SIngo Müller llvm::cl::desc("Split marker to use for merging the ouput"),
90516ccce7SIngo Müller llvm::cl::init(""));
91516ccce7SIngo Müller
92ee1d447eSRiver Riddle llvm::InitLLVM y(argc, argv);
93ee1d447eSRiver Riddle
94ee1d447eSRiver Riddle // Add flags for all the registered translations.
9509fd9ef4SFabian llvm::cl::list<const Translation *, bool, TranslationParser>
9609fd9ef4SFabian translationsRequested("", llvm::cl::desc("Translations to perform"),
97ee1d447eSRiver Riddle llvm::cl::Required);
98ee1d447eSRiver Riddle registerAsmPrinterCLOptions();
99ee1d447eSRiver Riddle registerMLIRContextCLOptions();
100d30727fbSrkayaith registerTranslationCLOptions();
101c3b4e279STobias Gysi registerDefaultTimingManagerCLOptions();
102ee1d447eSRiver Riddle llvm::cl::ParseCommandLineOptions(argc, argv, toolName);
103ee1d447eSRiver Riddle
104c3b4e279STobias Gysi // Initialize the timing manager.
105c3b4e279STobias Gysi DefaultTimingManager tm;
106c3b4e279STobias Gysi applyDefaultTimingManagerCLOptions(tm);
107c3b4e279STobias Gysi TimingScope timing = tm.getRootScope();
108c3b4e279STobias Gysi
109ee1d447eSRiver Riddle std::string errorMessage;
1104155be33SRiver Riddle std::unique_ptr<llvm::MemoryBuffer> input;
11109fd9ef4SFabian if (auto inputAlignment = translationsRequested[0]->getInputAlignment())
1124155be33SRiver Riddle input = openInputFile(inputFilename, *inputAlignment, &errorMessage);
1134155be33SRiver Riddle else
1144155be33SRiver Riddle input = openInputFile(inputFilename, &errorMessage);
115ee1d447eSRiver Riddle if (!input) {
116ee1d447eSRiver Riddle llvm::errs() << errorMessage << "\n";
117ee1d447eSRiver Riddle return failure();
118ee1d447eSRiver Riddle }
119ee1d447eSRiver Riddle
120ee1d447eSRiver Riddle auto output = openOutputFile(outputFilename, &errorMessage);
121ee1d447eSRiver Riddle if (!output) {
122ee1d447eSRiver Riddle llvm::errs() << errorMessage << "\n";
123ee1d447eSRiver Riddle return failure();
124ee1d447eSRiver Riddle }
125ee1d447eSRiver Riddle
126ee1d447eSRiver Riddle // Processes the memory buffer with a new MLIRContext.
127ee1d447eSRiver Riddle auto processBuffer = [&](std::unique_ptr<llvm::MemoryBuffer> ownedBuffer,
128ee1d447eSRiver Riddle raw_ostream &os) {
12909fd9ef4SFabian // Temporary buffers for chained translation processing.
13009fd9ef4SFabian std::string dataIn;
13109fd9ef4SFabian std::string dataOut;
13209fd9ef4SFabian LogicalResult result = LogicalResult::success();
13309fd9ef4SFabian
13409fd9ef4SFabian for (size_t i = 0, e = translationsRequested.size(); i < e; ++i) {
13509fd9ef4SFabian llvm::raw_ostream *stream;
13609fd9ef4SFabian llvm::raw_string_ostream dataStream(dataOut);
13709fd9ef4SFabian
13809fd9ef4SFabian if (i == e - 1) {
13909fd9ef4SFabian // Output last translation to output.
14009fd9ef4SFabian stream = &os;
14109fd9ef4SFabian } else {
14209fd9ef4SFabian // Output translation to temporary data buffer.
14309fd9ef4SFabian stream = &dataStream;
14409fd9ef4SFabian }
14509fd9ef4SFabian
14609fd9ef4SFabian const Translation *translationRequested = translationsRequested[i];
147c3b4e279STobias Gysi TimingScope translationTiming =
148c3b4e279STobias Gysi timing.nest(translationRequested->getDescription());
149c3b4e279STobias Gysi
150ee1d447eSRiver Riddle MLIRContext context;
151ee1d447eSRiver Riddle context.allowUnregisteredDialects(allowUnregisteredDialects);
152ee1d447eSRiver Riddle context.printOpOnDiagnostic(!verifyDiagnostics);
15318546ff8SRiver Riddle auto sourceMgr = std::make_shared<llvm::SourceMgr>();
15418546ff8SRiver Riddle sourceMgr->AddNewSourceBuffer(std::move(ownedBuffer), SMLoc());
155ee1d447eSRiver Riddle
15609fd9ef4SFabian if (verifyDiagnostics) {
15709fd9ef4SFabian // In the diagnostic verification flow, we ignore whether the
1581ade6f36STobias Gysi // translation failed (in most cases, it is expected to fail) and we do
1591ade6f36STobias Gysi // not filter non-error diagnostics even if `errorDiagnosticsOnly` is
1601ade6f36STobias Gysi // set. Instead, we check if the diagnostics were produced as expected.
16109fd9ef4SFabian SourceMgrDiagnosticVerifierHandler sourceMgrHandler(*sourceMgr,
16209fd9ef4SFabian &context);
163ee1d447eSRiver Riddle (void)(*translationRequested)(sourceMgr, os, &context);
16409fd9ef4SFabian result = sourceMgrHandler.verify();
1651ade6f36STobias Gysi } else if (errorDiagnosticsOnly) {
1661ade6f36STobias Gysi SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context);
1671ade6f36STobias Gysi ErrorDiagnosticFilter diagnosticFilter(&context);
1681ade6f36STobias Gysi result = (*translationRequested)(sourceMgr, *stream, &context);
16909fd9ef4SFabian } else {
17009fd9ef4SFabian SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context);
17109fd9ef4SFabian result = (*translationRequested)(sourceMgr, *stream, &context);
17209fd9ef4SFabian }
17309fd9ef4SFabian if (failed(result))
17409fd9ef4SFabian return result;
17509fd9ef4SFabian
17609fd9ef4SFabian if (i < e - 1) {
17709fd9ef4SFabian // If there are further translations, create a new buffer with the
17809fd9ef4SFabian // output data.
17909fd9ef4SFabian dataIn = dataOut;
18009fd9ef4SFabian dataOut.clear();
18109fd9ef4SFabian ownedBuffer = llvm::MemoryBuffer::getMemBuffer(dataIn);
18209fd9ef4SFabian }
18309fd9ef4SFabian }
18409fd9ef4SFabian return result;
185ee1d447eSRiver Riddle };
186ee1d447eSRiver Riddle
187ee1d447eSRiver Riddle if (failed(splitAndProcessBuffer(std::move(input), processBuffer,
188516ccce7SIngo Müller output->os(), inputSplitMarker,
189516ccce7SIngo Müller outputSplitMarker)))
190ee1d447eSRiver Riddle return failure();
191ee1d447eSRiver Riddle
192ee1d447eSRiver Riddle output->keep();
193ee1d447eSRiver Riddle return success();
194ee1d447eSRiver Riddle }
195