MLIR  22.0.0git
MlirTranslateMain.cpp
Go to the documentation of this file.
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 
10 #include "mlir/IR/AsmState.h"
11 #include "mlir/Parser/Parser.h"
13 #include "mlir/Support/Timing.h"
16 #include "llvm/Support/InitLLVM.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "llvm/Support/ToolOutputFile.h"
19 
20 using namespace mlir;
21 
22 //===----------------------------------------------------------------------===//
23 // Diagnostic Filter
24 //===----------------------------------------------------------------------===//
25 
26 namespace {
27 /// A scoped diagnostic handler that marks non-error diagnostics as handled. As
28 /// a result, the main diagnostic handler does not print non-error diagnostics.
29 class ErrorDiagnosticFilter : public ScopedDiagnosticHandler {
30 public:
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 } // namespace
40 
41 //===----------------------------------------------------------------------===//
42 // Translate Entry Point
43 //===----------------------------------------------------------------------===//
44 
45 LogicalResult 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(
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(
85  "Check all diagnostics (expected, unexpected, near-misses)"),
86  clEnumValN(
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);
111  llvm::cl::ParseCommandLineOptions(argc, argv, toolName);
112 
113  // Initialize the timing manager.
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  else
123  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 splitting
139  // the buffer does not guarantee null-termination. Make a copy of the buffer
140  // 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 the
174  // translation failed (in most cases, it is expected to fail) and we do
175  // not filter non-error diagnostics even if `errorDiagnosticsOnly` is
176  // 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 the
194  // 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 }
static LogicalResult processBuffer(raw_ostream &os, std::unique_ptr< MemoryBuffer > ownedBuffer, llvm::MemoryBufferRef sourceBuffer, const MlirOptMainConfig &config, DialectRegistry &registry, SourceMgrDiagnosticVerifierHandler *verifyHandler, llvm::ThreadPoolInterface *threadPool)
Parses the memory buffer.
static std::string diag(const llvm::Value &value)
Facilities for time measurement and report printing to an output stream.
Definition: Timing.h:388
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Definition: Diagnostics.h:155
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
void printOpOnDiagnostic(bool enable)
Set the flag specifying if we should attach the operation to diagnostics emitted via Operation::emit.
void allowUnregisteredDialects(bool allow=true)
Enables creating operations in unregistered dialects.
This diagnostic handler is a simple RAII class that registers and erases a diagnostic handler on a gi...
Definition: Diagnostics.h:522
This class is a utility diagnostic handler for use with llvm::SourceMgr.
Definition: Diagnostics.h:559
This class is a utility diagnostic handler for use with llvm::SourceMgr that verifies that emitted di...
Definition: Diagnostics.h:627
TimingScope getRootScope()
Get the root timer of this timing manager wrapped in a TimingScope for convenience.
Definition: Timing.cpp:72
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
Definition: Timing.h:272
TimingScope nest(Args... args)
Create a nested timing scope.
Definition: Timing.h:311
This class contains all of the components necessary for performing a translation.
Definition: Translation.h:61
StringRef getDescription() const
Return the description of this translation.
Definition: Translation.h:70
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
std::unique_ptr< llvm::MemoryBuffer > openInputFile(llvm::StringRef inputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for reading.
const char *const kDefaultSplitMarker
void registerDefaultTimingManagerCLOptions()
Register a set of useful command-line options that can be used to configure a DefaultTimingManager.
Definition: Timing.cpp:612
void registerTranslationCLOptions()
Register command-line options used by the translation registry.
Definition: Translation.cpp:37
std::unique_ptr< llvm::ToolOutputFile > openOutputFile(llvm::StringRef outputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for writing.
void registerMLIRContextCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Definition: MLIRContext.cpp:88
LogicalResult splitAndProcessBuffer(std::unique_ptr< llvm::MemoryBuffer > originalBuffer, ChunkBufferHandler processChunkBuffer, raw_ostream &os, llvm::StringRef inputSplitMarker=kDefaultSplitMarker, llvm::StringRef outputSplitMarker="")
Splits the specified buffer on a marker (// ----- by default), processes each chunk independently acc...
void registerAsmPrinterCLOptions()
Register a set of useful command-line options that can be used to configure various flags within the ...
Definition: AsmPrinter.cpp:211
void applyDefaultTimingManagerCLOptions(DefaultTimingManager &tm)
Apply any values that were registered with 'registerDefaultTimingManagerOptions' to a DefaultTimingMa...
Definition: Timing.cpp:617
LogicalResult mlirTranslateMain(int argc, char **argv, StringRef toolName)
Translate to/from an MLIR module from/to an external representation (e.g.