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