1 | //===- mlir-irdl-to-cpp.cpp - IRDL to C++ conversion tool -----------------===// |
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 | // |
9 | // This is a command line utility that translates an IRDL dialect definition |
10 | // into a C++ implementation to be included in MLIR. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "mlir/Dialect/IRDL/IR/IRDL.h" |
15 | #include "mlir/IR/AsmState.h" |
16 | #include "mlir/IR/DialectRegistry.h" |
17 | #include "mlir/IR/MLIRContext.h" |
18 | #include "mlir/Support/FileUtilities.h" |
19 | #include "mlir/Support/ToolUtilities.h" |
20 | #include "mlir/Target/IRDLToCpp/IRDLToCpp.h" |
21 | #include "mlir/Tools/ParseUtilities.h" |
22 | #include "llvm/Support/Casting.h" |
23 | #include "llvm/Support/CommandLine.h" |
24 | #include "llvm/Support/InitLLVM.h" |
25 | #include "llvm/Support/MemoryBuffer.h" |
26 | #include "llvm/Support/SourceMgr.h" |
27 | #include "llvm/Support/ToolOutputFile.h" |
28 | |
29 | using namespace mlir; |
30 | |
31 | static LogicalResult |
32 | processBuffer(llvm::raw_ostream &os, |
33 | std::unique_ptr<llvm::MemoryBuffer> ownedBuffer, |
34 | bool verifyDiagnostics, llvm::ThreadPoolInterface *threadPool) { |
35 | // Tell sourceMgr about this buffer, which is what the parser will pick up. |
36 | auto sourceMgr = std::make_shared<llvm::SourceMgr>(); |
37 | sourceMgr->AddNewSourceBuffer(F: std::move(ownedBuffer), IncludeLoc: SMLoc()); |
38 | |
39 | DialectRegistry registry; |
40 | registry.insert<irdl::IRDLDialect>(); |
41 | MLIRContext ctx(registry); |
42 | |
43 | ctx.printOpOnDiagnostic(enable: !verifyDiagnostics); |
44 | |
45 | auto runTranslation = [&]() { |
46 | ParserConfig parseConfig(&ctx); |
47 | OwningOpRef<Operation *> op = |
48 | parseSourceFileForTool(sourceMgr, config: parseConfig, insertImplicitModule: true); |
49 | if (!op) |
50 | return failure(); |
51 | |
52 | auto moduleOp = llvm::cast<ModuleOp>(*op); |
53 | llvm::SmallVector<irdl::DialectOp> dialects{ |
54 | moduleOp.getOps<irdl::DialectOp>(), |
55 | }; |
56 | |
57 | return irdl::translateIRDLDialectToCpp(dialects, os); |
58 | }; |
59 | |
60 | if (!verifyDiagnostics) { |
61 | // If no errors are expected, return translation result. |
62 | SourceMgrDiagnosticHandler srcManagerHandler(*sourceMgr, &ctx); |
63 | return runTranslation(); |
64 | } |
65 | |
66 | // If errors are expected, ignore translation result and check for |
67 | // diagnostics. |
68 | SourceMgrDiagnosticVerifierHandler srcManagerHandler(*sourceMgr, &ctx); |
69 | (void)runTranslation(); |
70 | return srcManagerHandler.verify(); |
71 | } |
72 | |
73 | static LogicalResult translateIRDLToCpp(int argc, char **argv) { |
74 | static llvm::cl::opt<std::string> inputFilename( |
75 | llvm::cl::Positional, llvm::cl::desc("<input file>" ), |
76 | llvm::cl::init(Val: "-" )); |
77 | |
78 | static llvm::cl::opt<std::string> outputFilename( |
79 | "o" , llvm::cl::desc("Output filename" ), llvm::cl::value_desc("filename" ), |
80 | llvm::cl::init(Val: "-" )); |
81 | |
82 | static llvm::cl::opt<bool> verifyDiagnostics( |
83 | "verify-diagnostics" , |
84 | llvm::cl::desc("Check that emitted diagnostics match " |
85 | "expected-* lines on the corresponding line" ), |
86 | llvm::cl::init(Val: false)); |
87 | |
88 | static llvm::cl::opt<std::string> splitInputFile( |
89 | "split-input-file" , llvm::cl::ValueOptional, |
90 | llvm::cl::callback(CB: [&](const std::string &str) { |
91 | // Implicit value: use default marker if flag was used without |
92 | // value. |
93 | if (str.empty()) |
94 | splitInputFile.setValue(V: kDefaultSplitMarker); |
95 | }), |
96 | llvm::cl::desc("Split the input file into chunks using the given or " |
97 | "default marker and process each chunk independently" ), |
98 | llvm::cl::init(Val: "" )); |
99 | |
100 | llvm::InitLLVM y(argc, argv); |
101 | |
102 | llvm::cl::ParseCommandLineOptions(argc, argv, Overview: "mlir-irdl-to-cpp" ); |
103 | |
104 | std::string errorMessage; |
105 | std::unique_ptr<llvm::MemoryBuffer> input = |
106 | openInputFile(inputFilename, errorMessage: &errorMessage); |
107 | if (!input) { |
108 | llvm::errs() << errorMessage << "\n" ; |
109 | return failure(); |
110 | } |
111 | |
112 | std::unique_ptr<llvm::ToolOutputFile> output = |
113 | openOutputFile(outputFilename, errorMessage: &errorMessage); |
114 | |
115 | if (!output) { |
116 | llvm::errs() << errorMessage << "\n" ; |
117 | return failure(); |
118 | } |
119 | |
120 | auto chunkFn = [&](std::unique_ptr<llvm::MemoryBuffer> chunkBuffer, |
121 | raw_ostream &os) { |
122 | return processBuffer(os&: output->os(), ownedBuffer: std::move(chunkBuffer), |
123 | verifyDiagnostics, threadPool: nullptr); |
124 | }; |
125 | |
126 | auto &splitInputFileDelimiter = splitInputFile.getValue(); |
127 | if (splitInputFileDelimiter.size()) |
128 | return splitAndProcessBuffer(originalBuffer: std::move(input), processChunkBuffer: chunkFn, os&: output->os(), |
129 | inputSplitMarker: splitInputFileDelimiter, |
130 | outputSplitMarker: splitInputFileDelimiter); |
131 | |
132 | if (failed(Result: chunkFn(std::move(input), output->os()))) |
133 | return failure(); |
134 | |
135 | if (!verifyDiagnostics) |
136 | output->keep(); |
137 | |
138 | return success(); |
139 | } |
140 | |
141 | int main(int argc, char **argv) { |
142 | return failed(Result: translateIRDLToCpp(argc, argv)); |
143 | } |
144 | |