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