//===- MlirTranslateMain.cpp - MLIR Translation entry point ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "mlir/Tools/mlir-translate/MlirTranslateMain.h" #include "mlir/IR/AsmState.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/Dialect.h" #include "mlir/IR/Verifier.h" #include "mlir/Parser/Parser.h" #include "mlir/Support/FileUtilities.h" #include "mlir/Support/LogicalResult.h" #include "mlir/Support/Timing.h" #include "mlir/Support/ToolUtilities.h" #include "mlir/Tools/mlir-translate/Translation.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" using namespace mlir; //===----------------------------------------------------------------------===// // Diagnostic Filter //===----------------------------------------------------------------------===// namespace { /// A scoped diagnostic handler that marks non-error diagnostics as handled. As /// a result, the main diagnostic handler does not print non-error diagnostics. class ErrorDiagnosticFilter : public ScopedDiagnosticHandler { public: ErrorDiagnosticFilter(MLIRContext *ctx) : ScopedDiagnosticHandler(ctx) { setHandler([](Diagnostic &diag) { if (diag.getSeverity() != DiagnosticSeverity::Error) return success(); return failure(); }); } }; } // namespace //===----------------------------------------------------------------------===// // Translate Entry Point //===----------------------------------------------------------------------===// LogicalResult mlir::mlirTranslateMain(int argc, char **argv, llvm::StringRef toolName) { static llvm::cl::opt inputFilename( llvm::cl::Positional, llvm::cl::desc(""), llvm::cl::init("-")); static llvm::cl::opt outputFilename( "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"), llvm::cl::init("-")); static llvm::cl::opt allowUnregisteredDialects( "allow-unregistered-dialect", llvm::cl::desc("Allow operation with no registered dialects (discouraged: testing only!)"), llvm::cl::init(false)); static llvm::cl::opt splitInputFile( "split-input-file", llvm::cl::desc("Split the input file into pieces and " "process each chunk independently"), llvm::cl::init(false)); static llvm::cl::opt verifyDiagnostics( "verify-diagnostics", llvm::cl::desc("Check that emitted diagnostics match " "expected-* lines on the corresponding line"), llvm::cl::init(false)); static llvm::cl::opt errorDiagnosticsOnly( "error-diagnostics-only", llvm::cl::desc("Filter all non-error diagnostics " "(discouraged: testing only!)"), llvm::cl::init(false)); llvm::InitLLVM y(argc, argv); // Add flags for all the registered translations. llvm::cl::list translationsRequested("", llvm::cl::desc("Translations to perform"), llvm::cl::Required); registerAsmPrinterCLOptions(); registerMLIRContextCLOptions(); registerTranslationCLOptions(); registerDefaultTimingManagerCLOptions(); llvm::cl::ParseCommandLineOptions(argc, argv, toolName); // Initialize the timing manager. DefaultTimingManager tm; applyDefaultTimingManagerCLOptions(tm); TimingScope timing = tm.getRootScope(); std::string errorMessage; std::unique_ptr input; if (auto inputAlignment = translationsRequested[0]->getInputAlignment()) input = openInputFile(inputFilename, *inputAlignment, &errorMessage); else input = openInputFile(inputFilename, &errorMessage); if (!input) { llvm::errs() << errorMessage << "\n"; return failure(); } auto output = openOutputFile(outputFilename, &errorMessage); if (!output) { llvm::errs() << errorMessage << "\n"; return failure(); } // Processes the memory buffer with a new MLIRContext. auto processBuffer = [&](std::unique_ptr ownedBuffer, raw_ostream &os) { // Temporary buffers for chained translation processing. std::string dataIn; std::string dataOut; LogicalResult result = LogicalResult::success(); for (size_t i = 0, e = translationsRequested.size(); i < e; ++i) { llvm::raw_ostream *stream; llvm::raw_string_ostream dataStream(dataOut); if (i == e - 1) { // Output last translation to output. stream = &os; } else { // Output translation to temporary data buffer. stream = &dataStream; } const Translation *translationRequested = translationsRequested[i]; TimingScope translationTiming = timing.nest(translationRequested->getDescription()); MLIRContext context; context.allowUnregisteredDialects(allowUnregisteredDialects); context.printOpOnDiagnostic(!verifyDiagnostics); auto sourceMgr = std::make_shared(); sourceMgr->AddNewSourceBuffer(std::move(ownedBuffer), SMLoc()); if (verifyDiagnostics) { // In the diagnostic verification flow, we ignore whether the // translation failed (in most cases, it is expected to fail) and we do // not filter non-error diagnostics even if `errorDiagnosticsOnly` is // set. Instead, we check if the diagnostics were produced as expected. SourceMgrDiagnosticVerifierHandler sourceMgrHandler(*sourceMgr, &context); (void)(*translationRequested)(sourceMgr, os, &context); result = sourceMgrHandler.verify(); } else if (errorDiagnosticsOnly) { SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context); ErrorDiagnosticFilter diagnosticFilter(&context); result = (*translationRequested)(sourceMgr, *stream, &context); } else { SourceMgrDiagnosticHandler sourceMgrHandler(*sourceMgr, &context); result = (*translationRequested)(sourceMgr, *stream, &context); } if (failed(result)) return result; if (i < e - 1) { // If there are further translations, create a new buffer with the // output data. dataIn = dataOut; dataOut.clear(); ownedBuffer = llvm::MemoryBuffer::getMemBuffer(dataIn); } } return result; }; if (failed(splitAndProcessBuffer(std::move(input), processBuffer, output->os(), splitInputFile))) return failure(); output->keep(); return success(); }