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