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
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 &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
189using 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.
195static 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.
308static 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.
324static 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
337namespace {
338// Wrapper class around a Tablegen definition of an LLVM enum attribute case.
339class LLVMEnumCase : public tblgen::EnumCase {
340public:
341 using tblgen::EnumCase::EnumCase;
342
343 // Constructs a case from a non LLVM-specific enum attribute case.
344 explicit LLVMEnumCase(const tblgen::EnumCase &other)
345 : tblgen::EnumCase(&other.getDef()) {}
346
347 // Returns the C++ enumerant for the LLVM API.
348 StringRef getLLVMEnumerant() const {
349 return def->getValueAsString(FieldName: "llvmEnumerant");
350 }
351};
352
353// Wraper class around a Tablegen definition of an LLVM enum attribute.
354class LLVMEnumInfo : public tblgen::EnumInfo {
355public:
356 using tblgen::EnumInfo::EnumInfo;
357
358 // Returns the C++ enum name for the LLVM API.
359 StringRef getLLVMClassName() const {
360 return def->getValueAsString(FieldName: "llvmClassName");
361 }
362
363 // Returns all associated cases viewed as LLVM-specific enum cases.
364 std::vector<LLVMEnumCase> getAllCases() 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> getAllUnsupportedCases() 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.
387class LLVMCEnumInfo : public tblgen::EnumInfo {
388public:
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
411static 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 llvmEnumerant = 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
440static 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 llvmEnumerant = 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).
470static 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 llvmEnumerant = 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 llvmEnumerant = 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).
505static 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 llvmEnumerant = 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.
535template <bool ConvertTo>
536static 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
553static 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.
560static 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
568static mlir::GenRegistration
569 genLLVMIRConversions("gen-llvmir-conversions",
570 "Generate LLVM IR conversions", emitBuilders);
571
572static mlir::GenRegistration genOpFromLLVMIRConversions(
573 "gen-op-from-llvmir-conversions",
574 "Generate conversions of operations from LLVM IR", emitOpMLIRBuilders);
575
576static mlir::GenRegistration genIntrFromLLVMIRConversions(
577 "gen-intr-from-llvmir-conversions",
578 "Generate conversions of intrinsics from LLVM IR", emitIntrMLIRBuilders);
579
580static mlir::GenRegistration
581 genEnumToLLVMConversion("gen-enum-to-llvmir-conversions",
582 "Generate conversions of EnumAttrs to LLVM IR",
583 emitEnumConversionDefs</*ConvertTo=*/true>);
584
585static mlir::GenRegistration
586 genEnumFromLLVMConversion("gen-enum-from-llvmir-conversions",
587 "Generate conversions of EnumAttrs from LLVM IR",
588 emitEnumConversionDefs</*ConvertTo=*/false>);
589
590static mlir::GenRegistration genConvertibleLLVMIRIntrinsics(
591 "gen-convertible-llvmir-intrinsics",
592 "Generate list of convertible LLVM IR intrinsics",
593 emitConvertibleIntrinsics);
594

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