xref: /llvm-project/mlir/lib/Tools/mlir-translate/MlirTranslateMain.cpp (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
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