1 | //===- LLVMIRConversionGen.cpp - MLIR LLVM IR builder generator -----------===// |
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 file uses tablegen definitions of the LLVM IR Dialect operations to |
10 | // generate the code building the LLVM IR from it. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "mlir/TableGen/Argument.h" |
15 | #include "mlir/TableGen/Attribute.h" |
16 | #include "mlir/TableGen/EnumInfo.h" |
17 | #include "mlir/TableGen/GenInfo.h" |
18 | #include "mlir/TableGen/Operator.h" |
19 | |
20 | #include "llvm/ADT/Sequence.h" |
21 | #include "llvm/ADT/StringExtras.h" |
22 | #include "llvm/ADT/Twine.h" |
23 | #include "llvm/Support/FormatVariadic.h" |
24 | #include "llvm/Support/raw_ostream.h" |
25 | #include "llvm/TableGen/Error.h" |
26 | #include "llvm/TableGen/Record.h" |
27 | #include "llvm/TableGen/TableGenBackend.h" |
28 | |
29 | using namespace llvm; |
30 | using namespace mlir; |
31 | |
32 | static LogicalResult emitError(const Record &record, const Twine &message) { |
33 | PrintError(Rec: &record, Msg: message); |
34 | return failure(); |
35 | } |
36 | |
37 | namespace { |
38 | // Helper structure to return a position of the substring in a string. |
39 | struct StringLoc { |
40 | size_t pos; |
41 | size_t length; |
42 | |
43 | // Take a substring identified by this location in the given string. |
44 | StringRef in(StringRef str) const { return str.substr(Start: pos, N: length); } |
45 | |
46 | // A location is invalid if its position is outside the string. |
47 | explicit operator bool() { return pos != std::string::npos; } |
48 | }; |
49 | } // namespace |
50 | |
51 | // Find the next TableGen variable in the given pattern. These variables start |
52 | // with a `$` character and can contain alphanumeric characters or underscores. |
53 | // Return the position of the variable in the pattern and its length, including |
54 | // the `$` character. The escape syntax `$$` is also detected and returned. |
55 | static StringLoc findNextVariable(StringRef str) { |
56 | size_t startPos = str.find(C: '$'); |
57 | if (startPos == std::string::npos) |
58 | return {.pos: startPos, .length: 0}; |
59 | |
60 | // If we see "$$", return immediately. |
61 | if (startPos != str.size() - 1 && str[startPos + 1] == '$') |
62 | return {.pos: startPos, .length: 2}; |
63 | |
64 | // Otherwise, the symbol spans until the first character that is not |
65 | // alphanumeric or '_'. |
66 | size_t endPos = str.find_if_not(F: [](char c) { return isAlnum(C: c) || c == '_'; }, |
67 | From: startPos + 1); |
68 | if (endPos == std::string::npos) |
69 | endPos = str.size(); |
70 | |
71 | return {.pos: startPos, .length: endPos - startPos}; |
72 | } |
73 | |
74 | // Check if `name` is a variadic operand of `op`. Seach all operands since the |
75 | // MLIR and LLVM IR operand order may differ and only for the latter the |
76 | // variadic operand is guaranteed to be at the end of the operands list. |
77 | static bool isVariadicOperandName(const tblgen::Operator &op, StringRef name) { |
78 | for (int i = 0, e = op.getNumOperands(); i < e; ++i) |
79 | if (op.getOperand(index: i).name == name) |
80 | return op.getOperand(index: i).isVariadic(); |
81 | return false; |
82 | } |
83 | |
84 | // Check if `result` is a known name of a result of `op`. |
85 | static bool isResultName(const tblgen::Operator &op, StringRef name) { |
86 | for (int i = 0, e = op.getNumResults(); i < e; ++i) |
87 | if (op.getResultName(index: i) == name) |
88 | return true; |
89 | return false; |
90 | } |
91 | |
92 | // Check if `name` is a known name of an attribute of `op`. |
93 | static bool isAttributeName(const tblgen::Operator &op, StringRef name) { |
94 | return llvm::any_of( |
95 | Range: op.getAttributes(), |
96 | P: [name](const tblgen::NamedAttribute &attr) { return attr.name == name; }); |
97 | } |
98 | |
99 | // Check if `name` is a known name of an operand of `op`. |
100 | static bool isOperandName(const tblgen::Operator &op, StringRef name) { |
101 | for (int i = 0, e = op.getNumOperands(); i < e; ++i) |
102 | if (op.getOperand(index: i).name == name) |
103 | return true; |
104 | return false; |
105 | } |
106 | |
107 | // Return the `op` argument index of the argument with the given `name`. |
108 | static FailureOr<int> getArgumentIndex(const tblgen::Operator &op, |
109 | StringRef name) { |
110 | for (int i = 0, e = op.getNumArgs(); i != e; ++i) |
111 | if (op.getArgName(index: i) == name) |
112 | return i; |
113 | return failure(); |
114 | } |
115 | |
116 | // Emit to `os` the operator-name driven check and the call to LLVM IRBuilder |
117 | // for one definition of an LLVM IR Dialect operation. |
118 | static LogicalResult emitOneBuilder(const Record &record, raw_ostream &os) { |
119 | auto op = tblgen::Operator(record); |
120 | |
121 | if (!record.getValue(Name: "llvmBuilder" )) |
122 | return emitError(record, message: "expected 'llvmBuilder' field" ); |
123 | |
124 | // Return early if there is no builder specified. |
125 | StringRef builderStrRef = record.getValueAsString(FieldName: "llvmBuilder" ); |
126 | if (builderStrRef.empty()) |
127 | return success(); |
128 | |
129 | // Progressively create the builder string by replacing $-variables with |
130 | // value lookups. Keep only the not-yet-traversed part of the builder pattern |
131 | // to avoid re-traversing the string multiple times. |
132 | std::string builder; |
133 | llvm::raw_string_ostream bs(builder); |
134 | while (StringLoc loc = findNextVariable(str: builderStrRef)) { |
135 | auto name = loc.in(str: builderStrRef).drop_front(); |
136 | auto getterName = op.getGetterName(name); |
137 | // First, insert the non-matched part as is. |
138 | bs << builderStrRef.substr(Start: 0, N: loc.pos); |
139 | // Then, rewrite the name based on its kind. |
140 | bool isVariadicOperand = isVariadicOperandName(op, name); |
141 | if (isOperandName(op, name)) { |
142 | auto result = |
143 | isVariadicOperand |
144 | ? formatv(Fmt: "moduleTranslation.lookupValues(op.{0}())" , Vals&: getterName) |
145 | : formatv(Fmt: "moduleTranslation.lookupValue(op.{0}())" , Vals&: getterName); |
146 | bs << result; |
147 | } else if (isAttributeName(op, name)) { |
148 | bs << formatv(Fmt: "op.{0}()" , Vals&: getterName); |
149 | } else if (isResultName(op, name)) { |
150 | bs << formatv(Fmt: "moduleTranslation.mapValue(op.{0}())" , Vals&: getterName); |
151 | } else if (name == "_resultType" ) { |
152 | bs << "moduleTranslation.convertType(op.getResult().getType())" ; |
153 | } else if (name == "_hasResult" ) { |
154 | bs << "opInst.getNumResults() == 1" ; |
155 | } else if (name == "_location" ) { |
156 | bs << "opInst.getLoc()" ; |
157 | } else if (name == "_numOperands" ) { |
158 | bs << "opInst.getNumOperands()" ; |
159 | } else if (name == "$" ) { |
160 | bs << '$'; |
161 | } else { |
162 | return emitError( |
163 | record, message: "expected keyword, argument, or result, but got " + name); |
164 | } |
165 | // Finally, only keep the untraversed part of the string. |
166 | builderStrRef = builderStrRef.substr(Start: loc.pos + loc.length); |
167 | } |
168 | |
169 | // Output the check and the rewritten builder string. |
170 | os << "if (auto op = dyn_cast<" << op.getQualCppClassName() |
171 | << ">(opInst)) {\n" ; |
172 | os << bs.str() << builderStrRef << "\n" ; |
173 | os << " return success();\n" ; |
174 | os << "}\n" ; |
175 | |
176 | return success(); |
177 | } |
178 | |
179 | // Emit all builders. Returns false on success because of the generator |
180 | // registration requirements. |
181 | static bool emitBuilders(const RecordKeeper &records, raw_ostream &os) { |
182 | for (const Record *def : records.getAllDerivedDefinitions(ClassName: "LLVM_OpBase" )) { |
183 | if (failed(Result: emitOneBuilder(record: *def, os))) |
184 | return true; |
185 | } |
186 | return false; |
187 | } |
188 | |
189 | using ConditionFn = mlir::function_ref<llvm::Twine(const Record &record)>; |
190 | |
191 | // Emit a conditional call to the MLIR builder of the LLVM dialect operation to |
192 | // build for the given LLVM IR instruction. A condition function `conditionFn` |
193 | // emits a check to verify the opcode or intrinsic identifier of the LLVM IR |
194 | // instruction matches the LLVM dialect operation to build. |
195 | static LogicalResult emitOneMLIRBuilder(const Record &record, raw_ostream &os, |
196 | ConditionFn conditionFn) { |
197 | auto op = tblgen::Operator(record); |
198 | |
199 | if (!record.getValue(Name: "mlirBuilder" )) |
200 | return emitError(record, message: "expected 'mlirBuilder' field" ); |
201 | |
202 | // Return early if there is no builder specified. |
203 | StringRef builderStrRef = record.getValueAsString(FieldName: "mlirBuilder" ); |
204 | if (builderStrRef.empty()) |
205 | return success(); |
206 | |
207 | // Access the argument index array that maps argument indices to LLVM IR |
208 | // operand indices. If the operation defines no custom mapping, set the array |
209 | // to the identity permutation. |
210 | std::vector<int64_t> llvmArgIndices = |
211 | record.getValueAsListOfInts(FieldName: "llvmArgIndices" ); |
212 | if (llvmArgIndices.empty()) |
213 | append_range(C&: llvmArgIndices, R: seq<int64_t>(Begin: 0, End: op.getNumArgs())); |
214 | if (llvmArgIndices.size() != static_cast<size_t>(op.getNumArgs())) { |
215 | return emitError( |
216 | record, |
217 | message: "expected 'llvmArgIndices' size to match the number of arguments" ); |
218 | } |
219 | |
220 | // Progressively create the builder string by replacing $-variables. Keep only |
221 | // the not-yet-traversed part of the builder pattern to avoid re-traversing |
222 | // the string multiple times. Additionally, emit an argument string |
223 | // immediately before the builder string. This argument string converts all |
224 | // operands used by the builder to MLIR values and returns failure if one of |
225 | // the conversions fails. |
226 | std::string arguments, builder; |
227 | llvm::raw_string_ostream as(arguments), bs(builder); |
228 | while (StringLoc loc = findNextVariable(str: builderStrRef)) { |
229 | auto name = loc.in(str: builderStrRef).drop_front(); |
230 | // First, insert the non-matched part as is. |
231 | bs << builderStrRef.substr(Start: 0, N: loc.pos); |
232 | // Then, rewrite the name based on its kind. |
233 | FailureOr<int> argIndex = getArgumentIndex(op, name); |
234 | if (succeeded(Result: argIndex)) { |
235 | // Access the LLVM IR operand that maps to the given argument index using |
236 | // the provided argument indices mapping. |
237 | int64_t idx = llvmArgIndices[*argIndex]; |
238 | if (idx < 0) { |
239 | return emitError( |
240 | record, message: "expected non-negative operand index for argument " + name); |
241 | } |
242 | if (isAttributeName(op, name)) { |
243 | bs << formatv(Fmt: "llvmOperands[{0}]" , Vals&: idx); |
244 | } else { |
245 | if (isVariadicOperandName(op, name)) { |
246 | as << formatv( |
247 | Fmt: "FailureOr<SmallVector<Value>> _llvmir_gen_operand_{0} = " |
248 | "moduleImport.convertValues(llvmOperands.drop_front({1}));\n" , |
249 | Vals&: name, Vals&: idx); |
250 | } else { |
251 | as << formatv(Fmt: "FailureOr<Value> _llvmir_gen_operand_{0} = " |
252 | "moduleImport.convertValue(llvmOperands[{1}]);\n" , |
253 | Vals&: name, Vals&: idx); |
254 | } |
255 | as << formatv(Fmt: "if (failed(_llvmir_gen_operand_{0}))\n" |
256 | " return failure();\n" , |
257 | Vals&: name); |
258 | bs << formatv(Fmt: "*_llvmir_gen_operand_{0}" , Vals&: name); |
259 | } |
260 | } else if (isResultName(op, name)) { |
261 | if (op.getNumResults() != 1) |
262 | return emitError(record, message: "expected op to have one result" ); |
263 | bs << "moduleImport.mapValue(inst)" ; |
264 | } else if (name == "_op" ) { |
265 | bs << "moduleImport.mapNoResultOp(inst)" ; |
266 | } else if (name == "_int_attr" ) { |
267 | bs << "moduleImport.matchIntegerAttr" ; |
268 | } else if (name == "_float_attr" ) { |
269 | bs << "moduleImport.matchFloatAttr" ; |
270 | } else if (name == "_var_attr" ) { |
271 | bs << "moduleImport.matchLocalVariableAttr" ; |
272 | } else if (name == "_label_attr" ) { |
273 | bs << "moduleImport.matchLabelAttr" ; |
274 | } else if (name == "_fpExceptionBehavior_attr" ) { |
275 | bs << "moduleImport.matchFPExceptionBehaviorAttr" ; |
276 | } else if (name == "_roundingMode_attr" ) { |
277 | bs << "moduleImport.matchRoundingModeAttr" ; |
278 | } else if (name == "_resultType" ) { |
279 | bs << "moduleImport.convertType(inst->getType())" ; |
280 | } else if (name == "_location" ) { |
281 | bs << "moduleImport.translateLoc(inst->getDebugLoc())" ; |
282 | } else if (name == "_builder" ) { |
283 | bs << "odsBuilder" ; |
284 | } else if (name == "_qualCppClassName" ) { |
285 | bs << op.getQualCppClassName(); |
286 | } else if (name == "$" ) { |
287 | bs << '$'; |
288 | } else { |
289 | return emitError( |
290 | record, message: "expected keyword, argument, or result, but got " + name); |
291 | } |
292 | // Finally, only keep the untraversed part of the string. |
293 | builderStrRef = builderStrRef.substr(Start: loc.pos + loc.length); |
294 | } |
295 | |
296 | // Output the check, the argument conversion, and the builder string. |
297 | os << "if (" << conditionFn(record) << ") {\n" ; |
298 | os << as.str() << "\n" ; |
299 | os << bs.str() << builderStrRef << "\n" ; |
300 | os << " return success();\n" ; |
301 | os << "}\n" ; |
302 | |
303 | return success(); |
304 | } |
305 | |
306 | // Emit all intrinsic MLIR builders. Returns false on success because of the |
307 | // generator registration requirements. |
308 | static bool emitIntrMLIRBuilders(const RecordKeeper &records, raw_ostream &os) { |
309 | // Emit condition to check if "llvmEnumName" matches the intrinsic id. |
310 | auto emitIntrCond = [](const Record &record) { |
311 | return "intrinsicID == llvm::Intrinsic::" + |
312 | record.getValueAsString(FieldName: "llvmEnumName" ); |
313 | }; |
314 | for (const Record *def : |
315 | records.getAllDerivedDefinitions(ClassName: "LLVM_IntrOpBase" )) { |
316 | if (failed(Result: emitOneMLIRBuilder(record: *def, os, conditionFn: emitIntrCond))) |
317 | return true; |
318 | } |
319 | return false; |
320 | } |
321 | |
322 | // Emit all op builders. Returns false on success because of the |
323 | // generator registration requirements. |
324 | static bool emitOpMLIRBuilders(const RecordKeeper &records, raw_ostream &os) { |
325 | // Emit condition to check if "llvmInstName" matches the instruction opcode. |
326 | auto emitOpcodeCond = [](const Record &record) { |
327 | return "inst->getOpcode() == llvm::Instruction::" + |
328 | record.getValueAsString(FieldName: "llvmInstName" ); |
329 | }; |
330 | for (const Record *def : records.getAllDerivedDefinitions(ClassName: "LLVM_OpBase" )) { |
331 | if (failed(Result: emitOneMLIRBuilder(record: *def, os, conditionFn: emitOpcodeCond))) |
332 | return true; |
333 | } |
334 | return false; |
335 | } |
336 | |
337 | namespace { |
338 | // Wrapper class around a Tablegen definition of an LLVM enum attribute case. |
339 | class : public tblgen::EnumCase { |
340 | public: |
341 | using tblgen::EnumCase::EnumCase; |
342 | |
343 | // Constructs a case from a non LLVM-specific enum attribute case. |
344 | explicit (const tblgen::EnumCase &other) |
345 | : tblgen::EnumCase(&other.getDef()) {} |
346 | |
347 | // Returns the C++ enumerant for the LLVM API. |
348 | StringRef () const { |
349 | return def->getValueAsString(FieldName: "llvmEnumerant" ); |
350 | } |
351 | }; |
352 | |
353 | // Wraper class around a Tablegen definition of an LLVM enum attribute. |
354 | class : public tblgen::EnumInfo { |
355 | public: |
356 | using tblgen::EnumInfo::EnumInfo; |
357 | |
358 | // Returns the C++ enum name for the LLVM API. |
359 | StringRef () const { |
360 | return def->getValueAsString(FieldName: "llvmClassName" ); |
361 | } |
362 | |
363 | // Returns all associated cases viewed as LLVM-specific enum cases. |
364 | std::vector<LLVMEnumCase> () const { |
365 | std::vector<LLVMEnumCase> cases; |
366 | |
367 | for (auto &c : tblgen::EnumInfo::getAllCases()) |
368 | cases.emplace_back(args&: c); |
369 | |
370 | return cases; |
371 | } |
372 | |
373 | std::vector<LLVMEnumCase> () const { |
374 | const auto *inits = def->getValueAsListInit(FieldName: "unsupported" ); |
375 | |
376 | std::vector<LLVMEnumCase> cases; |
377 | cases.reserve(n: inits->size()); |
378 | |
379 | for (const llvm::Init *init : *inits) |
380 | cases.emplace_back(args: cast<llvm::DefInit>(Val: init)); |
381 | |
382 | return cases; |
383 | } |
384 | }; |
385 | |
386 | // Wraper class around a Tablegen definition of a C-style LLVM enum attribute. |
387 | class LLVMCEnumInfo : public tblgen::EnumInfo { |
388 | public: |
389 | using tblgen::EnumInfo::EnumInfo; |
390 | |
391 | // Returns the C++ enum name for the LLVM API. |
392 | StringRef getLLVMClassName() const { |
393 | return def->getValueAsString(FieldName: "llvmClassName" ); |
394 | } |
395 | |
396 | // Returns all associated cases viewed as LLVM-specific enum cases. |
397 | std::vector<LLVMEnumCase> getAllCases() const { |
398 | std::vector<LLVMEnumCase> cases; |
399 | |
400 | for (auto &c : tblgen::EnumInfo::getAllCases()) |
401 | cases.emplace_back(args&: c); |
402 | |
403 | return cases; |
404 | } |
405 | }; |
406 | } // namespace |
407 | |
408 | // Emits conversion function "LLVMClass convertEnumToLLVM(Enum)" and containing |
409 | // switch-based logic to convert from the MLIR LLVM dialect enum attribute case |
410 | // (Enum) to the corresponding LLVM API enumerant |
411 | static void emitOneEnumToConversion(const Record *record, raw_ostream &os) { |
412 | LLVMEnumInfo enumInfo(record); |
413 | StringRef llvmClass = enumInfo.getLLVMClassName(); |
414 | StringRef cppClassName = enumInfo.getEnumClassName(); |
415 | StringRef cppNamespace = enumInfo.getCppNamespace(); |
416 | |
417 | // Emit the function converting the enum attribute to its LLVM counterpart. |
418 | os << formatv( |
419 | Fmt: "static LLVM_ATTRIBUTE_UNUSED {0} convert{1}ToLLVM({2}::{1} value) {{\n" , |
420 | Vals&: llvmClass, Vals&: cppClassName, Vals&: cppNamespace); |
421 | os << " switch (value) {\n" ; |
422 | |
423 | for (const auto &enumerant : enumInfo.getAllCases()) { |
424 | StringRef = enumerant.getLLVMEnumerant(); |
425 | StringRef cppEnumerant = enumerant.getSymbol(); |
426 | os << formatv(Fmt: " case {0}::{1}::{2}:\n" , Vals&: cppNamespace, Vals&: cppClassName, |
427 | Vals&: cppEnumerant); |
428 | os << formatv(Fmt: " return {0}::{1};\n" , Vals&: llvmClass, Vals&: llvmEnumerant); |
429 | } |
430 | |
431 | os << " }\n" ; |
432 | os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");\n" , |
433 | Vals: enumInfo.getEnumClassName()); |
434 | os << "}\n\n" ; |
435 | } |
436 | |
437 | // Emits conversion function "LLVMClass convertEnumToLLVM(Enum)" and containing |
438 | // switch-based logic to convert from the MLIR LLVM dialect enum attribute case |
439 | // (Enum) to the corresponding LLVM API C-style enumerant |
440 | static void emitOneCEnumToConversion(const Record *record, raw_ostream &os) { |
441 | LLVMCEnumInfo enumAttr(record); |
442 | StringRef llvmClass = enumAttr.getLLVMClassName(); |
443 | StringRef cppClassName = enumAttr.getEnumClassName(); |
444 | StringRef cppNamespace = enumAttr.getCppNamespace(); |
445 | |
446 | // Emit the function converting the enum attribute to its LLVM counterpart. |
447 | os << formatv(Fmt: "static LLVM_ATTRIBUTE_UNUSED int64_t " |
448 | "convert{0}ToLLVM({1}::{0} value) {{\n" , |
449 | Vals&: cppClassName, Vals&: cppNamespace); |
450 | os << " switch (value) {\n" ; |
451 | |
452 | for (const auto &enumerant : enumAttr.getAllCases()) { |
453 | StringRef = enumerant.getLLVMEnumerant(); |
454 | StringRef cppEnumerant = enumerant.getSymbol(); |
455 | os << formatv(Fmt: " case {0}::{1}::{2}:\n" , Vals&: cppNamespace, Vals&: cppClassName, |
456 | Vals&: cppEnumerant); |
457 | os << formatv(Fmt: " return static_cast<int64_t>({0}::{1});\n" , Vals&: llvmClass, |
458 | Vals&: llvmEnumerant); |
459 | } |
460 | |
461 | os << " }\n" ; |
462 | os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");\n" , |
463 | Vals: enumAttr.getEnumClassName()); |
464 | os << "}\n\n" ; |
465 | } |
466 | |
467 | // Emits conversion function "Enum convertEnumFromLLVM(LLVMClass)" and |
468 | // containing switch-based logic to convert from the LLVM API enumerant to MLIR |
469 | // LLVM dialect enum attribute (Enum). |
470 | static void emitOneEnumFromConversion(const Record *record, raw_ostream &os) { |
471 | LLVMEnumInfo enumInfo(record); |
472 | StringRef llvmClass = enumInfo.getLLVMClassName(); |
473 | StringRef cppClassName = enumInfo.getEnumClassName(); |
474 | StringRef cppNamespace = enumInfo.getCppNamespace(); |
475 | |
476 | // Emit the function converting the enum attribute from its LLVM counterpart. |
477 | os << formatv(Fmt: "inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM({2} " |
478 | "value) {{\n" , |
479 | Vals&: cppNamespace, Vals&: cppClassName, Vals&: llvmClass); |
480 | os << " switch (value) {\n" ; |
481 | |
482 | for (const auto &enumerant : enumInfo.getAllCases()) { |
483 | StringRef = enumerant.getLLVMEnumerant(); |
484 | StringRef cppEnumerant = enumerant.getSymbol(); |
485 | os << formatv(Fmt: " case {0}::{1}:\n" , Vals&: llvmClass, Vals&: llvmEnumerant); |
486 | os << formatv(Fmt: " return {0}::{1}::{2};\n" , Vals&: cppNamespace, Vals&: cppClassName, |
487 | Vals&: cppEnumerant); |
488 | } |
489 | for (const auto &enumerant : enumInfo.getAllUnsupportedCases()) { |
490 | StringRef = enumerant.getLLVMEnumerant(); |
491 | os << formatv(Fmt: " case {0}::{1}:\n" , Vals&: llvmClass, Vals&: llvmEnumerant); |
492 | os << formatv(Fmt: " llvm_unreachable(\"unsupported case {0}::{1}\");\n" , |
493 | Vals: enumInfo.getLLVMClassName(), Vals&: llvmEnumerant); |
494 | } |
495 | |
496 | os << " }\n" ; |
497 | os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");" , |
498 | Vals: enumInfo.getLLVMClassName()); |
499 | os << "}\n\n" ; |
500 | } |
501 | |
502 | // Emits conversion function "Enum convertEnumFromLLVM(LLVMEnum)" and |
503 | // containing switch-based logic to convert from the LLVM API C-style enumerant |
504 | // to MLIR LLVM dialect enum attribute (Enum). |
505 | static void emitOneCEnumFromConversion(const Record *record, raw_ostream &os) { |
506 | LLVMCEnumInfo enumInfo(record); |
507 | StringRef llvmClass = enumInfo.getLLVMClassName(); |
508 | StringRef cppClassName = enumInfo.getEnumClassName(); |
509 | StringRef cppNamespace = enumInfo.getCppNamespace(); |
510 | |
511 | // Emit the function converting the enum attribute from its LLVM counterpart. |
512 | os << formatv( |
513 | Fmt: "inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM(int64_t " |
514 | "value) {{\n" , |
515 | Vals&: cppNamespace, Vals&: cppClassName); |
516 | os << " switch (value) {\n" ; |
517 | |
518 | for (const auto &enumerant : enumInfo.getAllCases()) { |
519 | StringRef = enumerant.getLLVMEnumerant(); |
520 | StringRef cppEnumerant = enumerant.getSymbol(); |
521 | os << formatv(Fmt: " case static_cast<int64_t>({0}::{1}):\n" , Vals&: llvmClass, |
522 | Vals&: llvmEnumerant); |
523 | os << formatv(Fmt: " return {0}::{1}::{2};\n" , Vals&: cppNamespace, Vals&: cppClassName, |
524 | Vals&: cppEnumerant); |
525 | } |
526 | |
527 | os << " }\n" ; |
528 | os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");" , |
529 | Vals: enumInfo.getLLVMClassName()); |
530 | os << "}\n\n" ; |
531 | } |
532 | |
533 | // Emits conversion functions between MLIR enum attribute case and corresponding |
534 | // LLVM API enumerants for all registered LLVM dialect enum attributes. |
535 | template <bool ConvertTo> |
536 | static bool emitEnumConversionDefs(const RecordKeeper &records, |
537 | raw_ostream &os) { |
538 | for (const Record *def : records.getAllDerivedDefinitions(ClassName: "LLVM_EnumAttr" )) |
539 | if (ConvertTo) |
540 | emitOneEnumToConversion(record: def, os); |
541 | else |
542 | emitOneEnumFromConversion(record: def, os); |
543 | |
544 | for (const Record *def : records.getAllDerivedDefinitions(ClassName: "LLVM_CEnumAttr" )) |
545 | if (ConvertTo) |
546 | emitOneCEnumToConversion(record: def, os); |
547 | else |
548 | emitOneCEnumFromConversion(record: def, os); |
549 | |
550 | return false; |
551 | } |
552 | |
553 | static void emitOneIntrinsic(const Record &record, raw_ostream &os) { |
554 | auto op = tblgen::Operator(record); |
555 | os << "llvm::Intrinsic::" << record.getValueAsString(FieldName: "llvmEnumName" ) << ",\n" ; |
556 | } |
557 | |
558 | // Emit the list of LLVM IR intrinsics identifiers that are convertible to a |
559 | // matching MLIR LLVM dialect intrinsic operation. |
560 | static bool emitConvertibleIntrinsics(const RecordKeeper &records, |
561 | raw_ostream &os) { |
562 | for (const Record *def : records.getAllDerivedDefinitions(ClassName: "LLVM_IntrOpBase" )) |
563 | emitOneIntrinsic(record: *def, os); |
564 | |
565 | return false; |
566 | } |
567 | |
568 | static mlir::GenRegistration |
569 | genLLVMIRConversions("gen-llvmir-conversions" , |
570 | "Generate LLVM IR conversions" , emitBuilders); |
571 | |
572 | static mlir::GenRegistration genOpFromLLVMIRConversions( |
573 | "gen-op-from-llvmir-conversions" , |
574 | "Generate conversions of operations from LLVM IR" , emitOpMLIRBuilders); |
575 | |
576 | static mlir::GenRegistration genIntrFromLLVMIRConversions( |
577 | "gen-intr-from-llvmir-conversions" , |
578 | "Generate conversions of intrinsics from LLVM IR" , emitIntrMLIRBuilders); |
579 | |
580 | static mlir::GenRegistration |
581 | genEnumToLLVMConversion("gen-enum-to-llvmir-conversions" , |
582 | "Generate conversions of EnumAttrs to LLVM IR" , |
583 | emitEnumConversionDefs</*ConvertTo=*/true>); |
584 | |
585 | static mlir::GenRegistration |
586 | genEnumFromLLVMConversion("gen-enum-from-llvmir-conversions" , |
587 | "Generate conversions of EnumAttrs from LLVM IR" , |
588 | emitEnumConversionDefs</*ConvertTo=*/false>); |
589 | |
590 | static mlir::GenRegistration genConvertibleLLVMIRIntrinsics( |
591 | "gen-convertible-llvmir-intrinsics" , |
592 | "Generate list of convertible LLVM IR intrinsics" , |
593 | emitConvertibleIntrinsics); |
594 | |