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/Support/LogicalResult.h"
15#include "mlir/TableGen/Argument.h"
16#include "mlir/TableGen/Attribute.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
29using namespace llvm;
30using namespace mlir;
31
32static LogicalResult emitError(const Record &record, const Twine &message) {
33 PrintError(Rec: &record, Msg: message);
34 return failure();
35}
36
37namespace {
38// Helper structure to return a position of the substring in a string.
39struct 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.
55static 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.
77static 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`.
85static 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`.
93static 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`.
100static 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`.
108static 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.
118static 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.
181static bool emitBuilders(const RecordKeeper &recordKeeper, raw_ostream &os) {
182 for (const Record *def :
183 recordKeeper.getAllDerivedDefinitions(ClassName: "LLVM_OpBase")) {
184 if (failed(result: emitOneBuilder(record: *def, os)))
185 return true;
186 }
187 return false;
188}
189
190using ConditionFn = mlir::function_ref<llvm::Twine(const Record &record)>;
191
192// Emit a conditional call to the MLIR builder of the LLVM dialect operation to
193// build for the given LLVM IR instruction. A condition function `conditionFn`
194// emits a check to verify the opcode or intrinsic identifier of the LLVM IR
195// instruction matches the LLVM dialect operation to build.
196static LogicalResult emitOneMLIRBuilder(const Record &record, raw_ostream &os,
197 ConditionFn conditionFn) {
198 auto op = tblgen::Operator(record);
199
200 if (!record.getValue(Name: "mlirBuilder"))
201 return emitError(record, message: "expected 'mlirBuilder' field");
202
203 // Return early if there is no builder specified.
204 StringRef builderStrRef = record.getValueAsString(FieldName: "mlirBuilder");
205 if (builderStrRef.empty())
206 return success();
207
208 // Access the argument index array that maps argument indices to LLVM IR
209 // operand indices. If the operation defines no custom mapping, set the array
210 // to the identity permutation.
211 std::vector<int64_t> llvmArgIndices =
212 record.getValueAsListOfInts(FieldName: "llvmArgIndices");
213 if (llvmArgIndices.empty())
214 append_range(C&: llvmArgIndices, R: seq<int64_t>(Begin: 0, End: op.getNumArgs()));
215 if (llvmArgIndices.size() != static_cast<size_t>(op.getNumArgs())) {
216 return emitError(
217 record,
218 message: "expected 'llvmArgIndices' size to match the number of arguments");
219 }
220
221 // Progressively create the builder string by replacing $-variables. Keep only
222 // the not-yet-traversed part of the builder pattern to avoid re-traversing
223 // the string multiple times. Additionally, emit an argument string
224 // immediately before the builder string. This argument string converts all
225 // operands used by the builder to MLIR values and returns failure if one of
226 // the conversions fails.
227 std::string arguments, builder;
228 llvm::raw_string_ostream as(arguments), bs(builder);
229 while (StringLoc loc = findNextVariable(str: builderStrRef)) {
230 auto name = loc.in(str: builderStrRef).drop_front();
231 // First, insert the non-matched part as is.
232 bs << builderStrRef.substr(Start: 0, N: loc.pos);
233 // Then, rewrite the name based on its kind.
234 FailureOr<int> argIndex = getArgumentIndex(op, name);
235 if (succeeded(result: argIndex)) {
236 // Access the LLVM IR operand that maps to the given argument index using
237 // the provided argument indices mapping.
238 int64_t idx = llvmArgIndices[*argIndex];
239 if (idx < 0) {
240 return emitError(
241 record, message: "expected non-negative operand index for argument " + name);
242 }
243 if (isAttributeName(op, name)) {
244 bs << formatv(Fmt: "llvmOperands[{0}]", Vals&: idx);
245 } else {
246 if (isVariadicOperandName(op, name)) {
247 as << formatv(
248 Fmt: "FailureOr<SmallVector<Value>> _llvmir_gen_operand_{0} = "
249 "moduleImport.convertValues(llvmOperands.drop_front({1}));\n",
250 Vals&: name, Vals&: idx);
251 } else {
252 as << formatv(Fmt: "FailureOr<Value> _llvmir_gen_operand_{0} = "
253 "moduleImport.convertValue(llvmOperands[{1}]);\n",
254 Vals&: name, Vals&: idx);
255 }
256 as << formatv(Fmt: "if (failed(_llvmir_gen_operand_{0}))\n"
257 " return failure();\n",
258 Vals&: name);
259 bs << formatv(Fmt: "*_llvmir_gen_operand_{0}", Vals&: name);
260 }
261 } else if (isResultName(op, name)) {
262 if (op.getNumResults() != 1)
263 return emitError(record, message: "expected op to have one result");
264 bs << "moduleImport.mapValue(inst)";
265 } else if (name == "_op") {
266 bs << "moduleImport.mapNoResultOp(inst)";
267 } else if (name == "_int_attr") {
268 bs << "moduleImport.matchIntegerAttr";
269 } else if (name == "_float_attr") {
270 bs << "moduleImport.matchFloatAttr";
271 } else if (name == "_var_attr") {
272 bs << "moduleImport.matchLocalVariableAttr";
273 } else if (name == "_label_attr") {
274 bs << "moduleImport.matchLabelAttr";
275 } else if (name == "_fpExceptionBehavior_attr") {
276 bs << "moduleImport.matchFPExceptionBehaviorAttr";
277 } else if (name == "_roundingMode_attr") {
278 bs << "moduleImport.matchRoundingModeAttr";
279 } else if (name == "_resultType") {
280 bs << "moduleImport.convertType(inst->getType())";
281 } else if (name == "_location") {
282 bs << "moduleImport.translateLoc(inst->getDebugLoc())";
283 } else if (name == "_builder") {
284 bs << "odsBuilder";
285 } else if (name == "_qualCppClassName") {
286 bs << op.getQualCppClassName();
287 } else if (name == "$") {
288 bs << '$';
289 } else {
290 return emitError(
291 record, message: "expected keyword, argument, or result, but got " + name);
292 }
293 // Finally, only keep the untraversed part of the string.
294 builderStrRef = builderStrRef.substr(Start: loc.pos + loc.length);
295 }
296
297 // Output the check, the argument conversion, and the builder string.
298 os << "if (" << conditionFn(record) << ") {\n";
299 os << as.str() << "\n";
300 os << bs.str() << builderStrRef << "\n";
301 os << " return success();\n";
302 os << "}\n";
303
304 return success();
305}
306
307// Emit all intrinsic MLIR builders. Returns false on success because of the
308// generator registration requirements.
309static bool emitIntrMLIRBuilders(const RecordKeeper &recordKeeper,
310 raw_ostream &os) {
311 // Emit condition to check if "llvmEnumName" matches the intrinsic id.
312 auto emitIntrCond = [](const Record &record) {
313 return "intrinsicID == llvm::Intrinsic::" +
314 record.getValueAsString(FieldName: "llvmEnumName");
315 };
316 for (const Record *def :
317 recordKeeper.getAllDerivedDefinitions(ClassName: "LLVM_IntrOpBase")) {
318 if (failed(result: emitOneMLIRBuilder(record: *def, os, conditionFn: emitIntrCond)))
319 return true;
320 }
321 return false;
322}
323
324// Emit all op builders. Returns false on success because of the
325// generator registration requirements.
326static bool emitOpMLIRBuilders(const RecordKeeper &recordKeeper,
327 raw_ostream &os) {
328 // Emit condition to check if "llvmInstName" matches the instruction opcode.
329 auto emitOpcodeCond = [](const Record &record) {
330 return "inst->getOpcode() == llvm::Instruction::" +
331 record.getValueAsString(FieldName: "llvmInstName");
332 };
333 for (const Record *def :
334 recordKeeper.getAllDerivedDefinitions(ClassName: "LLVM_OpBase")) {
335 if (failed(result: emitOneMLIRBuilder(record: *def, os, conditionFn: emitOpcodeCond)))
336 return true;
337 }
338 return false;
339}
340
341namespace {
342// Wrapper class around a Tablegen definition of an LLVM enum attribute case.
343class LLVMEnumAttrCase : public tblgen::EnumAttrCase {
344public:
345 using tblgen::EnumAttrCase::EnumAttrCase;
346
347 // Constructs a case from a non LLVM-specific enum attribute case.
348 explicit LLVMEnumAttrCase(const tblgen::EnumAttrCase &other)
349 : tblgen::EnumAttrCase(&other.getDef()) {}
350
351 // Returns the C++ enumerant for the LLVM API.
352 StringRef getLLVMEnumerant() const {
353 return def->getValueAsString(FieldName: "llvmEnumerant");
354 }
355};
356
357// Wraper class around a Tablegen definition of an LLVM enum attribute.
358class LLVMEnumAttr : public tblgen::EnumAttr {
359public:
360 using tblgen::EnumAttr::EnumAttr;
361
362 // Returns the C++ enum name for the LLVM API.
363 StringRef getLLVMClassName() const {
364 return def->getValueAsString(FieldName: "llvmClassName");
365 }
366
367 // Returns all associated cases viewed as LLVM-specific enum cases.
368 std::vector<LLVMEnumAttrCase> getAllCases() const {
369 std::vector<LLVMEnumAttrCase> cases;
370
371 for (auto &c : tblgen::EnumAttr::getAllCases())
372 cases.emplace_back(args&: c);
373
374 return cases;
375 }
376
377 std::vector<LLVMEnumAttrCase> getAllUnsupportedCases() const {
378 const auto *inits = def->getValueAsListInit(FieldName: "unsupported");
379
380 std::vector<LLVMEnumAttrCase> cases;
381 cases.reserve(n: inits->size());
382
383 for (const llvm::Init *init : *inits)
384 cases.emplace_back(args: cast<llvm::DefInit>(Val: init));
385
386 return cases;
387 }
388};
389
390// Wraper class around a Tablegen definition of a C-style LLVM enum attribute.
391class LLVMCEnumAttr : public tblgen::EnumAttr {
392public:
393 using tblgen::EnumAttr::EnumAttr;
394
395 // Returns the C++ enum name for the LLVM API.
396 StringRef getLLVMClassName() const {
397 return def->getValueAsString(FieldName: "llvmClassName");
398 }
399
400 // Returns all associated cases viewed as LLVM-specific enum cases.
401 std::vector<LLVMEnumAttrCase> getAllCases() const {
402 std::vector<LLVMEnumAttrCase> cases;
403
404 for (auto &c : tblgen::EnumAttr::getAllCases())
405 cases.emplace_back(args&: c);
406
407 return cases;
408 }
409};
410} // namespace
411
412// Emits conversion function "LLVMClass convertEnumToLLVM(Enum)" and containing
413// switch-based logic to convert from the MLIR LLVM dialect enum attribute case
414// (Enum) to the corresponding LLVM API enumerant
415static void emitOneEnumToConversion(const llvm::Record *record,
416 raw_ostream &os) {
417 LLVMEnumAttr enumAttr(record);
418 StringRef llvmClass = enumAttr.getLLVMClassName();
419 StringRef cppClassName = enumAttr.getEnumClassName();
420 StringRef cppNamespace = enumAttr.getCppNamespace();
421
422 // Emit the function converting the enum attribute to its LLVM counterpart.
423 os << formatv(
424 Fmt: "static LLVM_ATTRIBUTE_UNUSED {0} convert{1}ToLLVM({2}::{1} value) {{\n",
425 Vals&: llvmClass, Vals&: cppClassName, Vals&: cppNamespace);
426 os << " switch (value) {\n";
427
428 for (const auto &enumerant : enumAttr.getAllCases()) {
429 StringRef llvmEnumerant = enumerant.getLLVMEnumerant();
430 StringRef cppEnumerant = enumerant.getSymbol();
431 os << formatv(Fmt: " case {0}::{1}::{2}:\n", Vals&: cppNamespace, Vals&: cppClassName,
432 Vals&: cppEnumerant);
433 os << formatv(Fmt: " return {0}::{1};\n", Vals&: llvmClass, Vals&: llvmEnumerant);
434 }
435
436 os << " }\n";
437 os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");\n",
438 Vals: enumAttr.getEnumClassName());
439 os << "}\n\n";
440}
441
442// Emits conversion function "LLVMClass convertEnumToLLVM(Enum)" and containing
443// switch-based logic to convert from the MLIR LLVM dialect enum attribute case
444// (Enum) to the corresponding LLVM API C-style enumerant
445static void emitOneCEnumToConversion(const llvm::Record *record,
446 raw_ostream &os) {
447 LLVMCEnumAttr enumAttr(record);
448 StringRef llvmClass = enumAttr.getLLVMClassName();
449 StringRef cppClassName = enumAttr.getEnumClassName();
450 StringRef cppNamespace = enumAttr.getCppNamespace();
451
452 // Emit the function converting the enum attribute to its LLVM counterpart.
453 os << formatv(Fmt: "static LLVM_ATTRIBUTE_UNUSED int64_t "
454 "convert{0}ToLLVM({1}::{0} value) {{\n",
455 Vals&: cppClassName, Vals&: cppNamespace);
456 os << " switch (value) {\n";
457
458 for (const auto &enumerant : enumAttr.getAllCases()) {
459 StringRef llvmEnumerant = enumerant.getLLVMEnumerant();
460 StringRef cppEnumerant = enumerant.getSymbol();
461 os << formatv(Fmt: " case {0}::{1}::{2}:\n", Vals&: cppNamespace, Vals&: cppClassName,
462 Vals&: cppEnumerant);
463 os << formatv(Fmt: " return static_cast<int64_t>({0}::{1});\n", Vals&: llvmClass,
464 Vals&: llvmEnumerant);
465 }
466
467 os << " }\n";
468 os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");\n",
469 Vals: enumAttr.getEnumClassName());
470 os << "}\n\n";
471}
472
473// Emits conversion function "Enum convertEnumFromLLVM(LLVMClass)" and
474// containing switch-based logic to convert from the LLVM API enumerant to MLIR
475// LLVM dialect enum attribute (Enum).
476static void emitOneEnumFromConversion(const llvm::Record *record,
477 raw_ostream &os) {
478 LLVMEnumAttr enumAttr(record);
479 StringRef llvmClass = enumAttr.getLLVMClassName();
480 StringRef cppClassName = enumAttr.getEnumClassName();
481 StringRef cppNamespace = enumAttr.getCppNamespace();
482
483 // Emit the function converting the enum attribute from its LLVM counterpart.
484 os << formatv(Fmt: "inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM({2} "
485 "value) {{\n",
486 Vals&: cppNamespace, Vals&: cppClassName, Vals&: llvmClass);
487 os << " switch (value) {\n";
488
489 for (const auto &enumerant : enumAttr.getAllCases()) {
490 StringRef llvmEnumerant = enumerant.getLLVMEnumerant();
491 StringRef cppEnumerant = enumerant.getSymbol();
492 os << formatv(Fmt: " case {0}::{1}:\n", Vals&: llvmClass, Vals&: llvmEnumerant);
493 os << formatv(Fmt: " return {0}::{1}::{2};\n", Vals&: cppNamespace, Vals&: cppClassName,
494 Vals&: cppEnumerant);
495 }
496 for (const auto &enumerant : enumAttr.getAllUnsupportedCases()) {
497 StringRef llvmEnumerant = enumerant.getLLVMEnumerant();
498 os << formatv(Fmt: " case {0}::{1}:\n", Vals&: llvmClass, Vals&: llvmEnumerant);
499 os << formatv(Fmt: " llvm_unreachable(\"unsupported case {0}::{1}\");\n",
500 Vals: enumAttr.getLLVMClassName(), Vals&: llvmEnumerant);
501 }
502
503 os << " }\n";
504 os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");",
505 Vals: enumAttr.getLLVMClassName());
506 os << "}\n\n";
507}
508
509// Emits conversion function "Enum convertEnumFromLLVM(LLVMEnum)" and
510// containing switch-based logic to convert from the LLVM API C-style enumerant
511// to MLIR LLVM dialect enum attribute (Enum).
512static void emitOneCEnumFromConversion(const llvm::Record *record,
513 raw_ostream &os) {
514 LLVMCEnumAttr enumAttr(record);
515 StringRef llvmClass = enumAttr.getLLVMClassName();
516 StringRef cppClassName = enumAttr.getEnumClassName();
517 StringRef cppNamespace = enumAttr.getCppNamespace();
518
519 // Emit the function converting the enum attribute from its LLVM counterpart.
520 os << formatv(
521 Fmt: "inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM(int64_t "
522 "value) {{\n",
523 Vals&: cppNamespace, Vals&: cppClassName, Vals&: llvmClass);
524 os << " switch (value) {\n";
525
526 for (const auto &enumerant : enumAttr.getAllCases()) {
527 StringRef llvmEnumerant = enumerant.getLLVMEnumerant();
528 StringRef cppEnumerant = enumerant.getSymbol();
529 os << formatv(Fmt: " case static_cast<int64_t>({0}::{1}):\n", Vals&: llvmClass,
530 Vals&: llvmEnumerant);
531 os << formatv(Fmt: " return {0}::{1}::{2};\n", Vals&: cppNamespace, Vals&: cppClassName,
532 Vals&: cppEnumerant);
533 }
534
535 os << " }\n";
536 os << formatv(Fmt: " llvm_unreachable(\"unknown {0} type\");",
537 Vals: enumAttr.getLLVMClassName());
538 os << "}\n\n";
539}
540
541// Emits conversion functions between MLIR enum attribute case and corresponding
542// LLVM API enumerants for all registered LLVM dialect enum attributes.
543template <bool ConvertTo>
544static bool emitEnumConversionDefs(const RecordKeeper &recordKeeper,
545 raw_ostream &os) {
546 for (const Record *def :
547 recordKeeper.getAllDerivedDefinitions(ClassName: "LLVM_EnumAttr"))
548 if (ConvertTo)
549 emitOneEnumToConversion(record: def, os);
550 else
551 emitOneEnumFromConversion(record: def, os);
552
553 for (const Record *def :
554 recordKeeper.getAllDerivedDefinitions(ClassName: "LLVM_CEnumAttr"))
555 if (ConvertTo)
556 emitOneCEnumToConversion(record: def, os);
557 else
558 emitOneCEnumFromConversion(record: def, os);
559
560 return false;
561}
562
563static void emitOneIntrinsic(const Record &record, raw_ostream &os) {
564 auto op = tblgen::Operator(record);
565 os << "llvm::Intrinsic::" << record.getValueAsString(FieldName: "llvmEnumName") << ",\n";
566}
567
568// Emit the list of LLVM IR intrinsics identifiers that are convertible to a
569// matching MLIR LLVM dialect intrinsic operation.
570static bool emitConvertibleIntrinsics(const RecordKeeper &recordKeeper,
571 raw_ostream &os) {
572 for (const Record *def :
573 recordKeeper.getAllDerivedDefinitions(ClassName: "LLVM_IntrOpBase"))
574 emitOneIntrinsic(record: *def, os);
575
576 return false;
577}
578
579static mlir::GenRegistration
580 genLLVMIRConversions("gen-llvmir-conversions",
581 "Generate LLVM IR conversions", emitBuilders);
582
583static mlir::GenRegistration genOpFromLLVMIRConversions(
584 "gen-op-from-llvmir-conversions",
585 "Generate conversions of operations from LLVM IR", emitOpMLIRBuilders);
586
587static mlir::GenRegistration genIntrFromLLVMIRConversions(
588 "gen-intr-from-llvmir-conversions",
589 "Generate conversions of intrinsics from LLVM IR", emitIntrMLIRBuilders);
590
591static mlir::GenRegistration
592 genEnumToLLVMConversion("gen-enum-to-llvmir-conversions",
593 "Generate conversions of EnumAttrs to LLVM IR",
594 emitEnumConversionDefs</*ConvertTo=*/true>);
595
596static mlir::GenRegistration
597 genEnumFromLLVMConversion("gen-enum-from-llvmir-conversions",
598 "Generate conversions of EnumAttrs from LLVM IR",
599 emitEnumConversionDefs</*ConvertTo=*/false>);
600
601static mlir::GenRegistration genConvertibleLLVMIRIntrinsics(
602 "gen-convertible-llvmir-intrinsics",
603 "Generate list of convertible LLVM IR intrinsics",
604 emitConvertibleIntrinsics);
605

source code of mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp