| //===- LLVMIRConversionGen.cpp - MLIR LLVM IR builder generator -----------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file uses tablegen definitions of the LLVM IR Dialect operations to |
| // generate the code building the LLVM IR from it. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mlir/TableGen/Argument.h" |
| #include "mlir/TableGen/Attribute.h" |
| #include "mlir/TableGen/GenInfo.h" |
| #include "mlir/TableGen/Operator.h" |
| |
| #include "llvm/ADT/Sequence.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/Support/FormatVariadic.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/TableGen/Error.h" |
| #include "llvm/TableGen/Record.h" |
| #include "llvm/TableGen/TableGenBackend.h" |
| |
| using namespace llvm; |
| using namespace mlir; |
| |
| static LogicalResult emitError(const Record &record, const Twine &message) { |
| PrintError(&record, message); |
| return failure(); |
| } |
| |
| namespace { |
| // Helper structure to return a position of the substring in a string. |
| struct StringLoc { |
| size_t pos; |
| size_t length; |
| |
| // Take a substring identified by this location in the given string. |
| StringRef in(StringRef str) const { return str.substr(pos, length); } |
| |
| // A location is invalid if its position is outside the string. |
| explicit operator bool() { return pos != std::string::npos; } |
| }; |
| } // namespace |
| |
| // Find the next TableGen variable in the given pattern. These variables start |
| // with a `$` character and can contain alphanumeric characters or underscores. |
| // Return the position of the variable in the pattern and its length, including |
| // the `$` character. The escape syntax `$$` is also detected and returned. |
| static StringLoc findNextVariable(StringRef str) { |
| size_t startPos = str.find('$'); |
| if (startPos == std::string::npos) |
| return {startPos, 0}; |
| |
| // If we see "$$", return immediately. |
| if (startPos != str.size() - 1 && str[startPos + 1] == '$') |
| return {startPos, 2}; |
| |
| // Otherwise, the symbol spans until the first character that is not |
| // alphanumeric or '_'. |
| size_t endPos = str.find_if_not([](char c) { return isAlnum(c) || c == '_'; }, |
| startPos + 1); |
| if (endPos == std::string::npos) |
| endPos = str.size(); |
| |
| return {startPos, endPos - startPos}; |
| } |
| |
| // Check if `name` is a variadic operand of `op`. Seach all operands since the |
| // MLIR and LLVM IR operand order may differ and only for the latter the |
| // variadic operand is guaranteed to be at the end of the operands list. |
| static bool isVariadicOperandName(const tblgen::Operator &op, StringRef name) { |
| for (int i = 0, e = op.getNumOperands(); i < e; ++i) |
| if (op.getOperand(i).name == name) |
| return op.getOperand(i).isVariadic(); |
| return false; |
| } |
| |
| // Check if `result` is a known name of a result of `op`. |
| static bool isResultName(const tblgen::Operator &op, StringRef name) { |
| for (int i = 0, e = op.getNumResults(); i < e; ++i) |
| if (op.getResultName(i) == name) |
| return true; |
| return false; |
| } |
| |
| // Check if `name` is a known name of an attribute of `op`. |
| static bool isAttributeName(const tblgen::Operator &op, StringRef name) { |
| return llvm::any_of( |
| op.getAttributes(), |
| [name](const tblgen::NamedAttribute &attr) { return attr.name == name; }); |
| } |
| |
| // Check if `name` is a known name of an operand of `op`. |
| static bool isOperandName(const tblgen::Operator &op, StringRef name) { |
| for (int i = 0, e = op.getNumOperands(); i < e; ++i) |
| if (op.getOperand(i).name == name) |
| return true; |
| return false; |
| } |
| |
| // Return the `op` argument index of the argument with the given `name`. |
| static FailureOr<int> getArgumentIndex(const tblgen::Operator &op, |
| StringRef name) { |
| for (int i = 0, e = op.getNumArgs(); i != e; ++i) |
| if (op.getArgName(i) == name) |
| return i; |
| return failure(); |
| } |
| |
| // Emit to `os` the operator-name driven check and the call to LLVM IRBuilder |
| // for one definition of an LLVM IR Dialect operation. |
| static LogicalResult emitOneBuilder(const Record &record, raw_ostream &os) { |
| auto op = tblgen::Operator(record); |
| |
| if (!record.getValue("llvmBuilder")) |
| return emitError(record, "expected 'llvmBuilder' field"); |
| |
| // Return early if there is no builder specified. |
| StringRef builderStrRef = record.getValueAsString("llvmBuilder"); |
| if (builderStrRef.empty()) |
| return success(); |
| |
| // Progressively create the builder string by replacing $-variables with |
| // value lookups. Keep only the not-yet-traversed part of the builder pattern |
| // to avoid re-traversing the string multiple times. |
| std::string builder; |
| llvm::raw_string_ostream bs(builder); |
| while (StringLoc loc = findNextVariable(builderStrRef)) { |
| auto name = loc.in(builderStrRef).drop_front(); |
| auto getterName = op.getGetterName(name); |
| // First, insert the non-matched part as is. |
| bs << builderStrRef.substr(0, loc.pos); |
| // Then, rewrite the name based on its kind. |
| bool isVariadicOperand = isVariadicOperandName(op, name); |
| if (isOperandName(op, name)) { |
| auto result = |
| isVariadicOperand |
| ? formatv("moduleTranslation.lookupValues(op.{0}())", getterName) |
| : formatv("moduleTranslation.lookupValue(op.{0}())", getterName); |
| bs << result; |
| } else if (isAttributeName(op, name)) { |
| bs << formatv("op.{0}()", getterName); |
| } else if (isResultName(op, name)) { |
| bs << formatv("moduleTranslation.mapValue(op.{0}())", getterName); |
| } else if (name == "_resultType") { |
| bs << "moduleTranslation.convertType(op.getResult().getType())"; |
| } else if (name == "_hasResult") { |
| bs << "opInst.getNumResults() == 1"; |
| } else if (name == "_location") { |
| bs << "opInst.getLoc()"; |
| } else if (name == "_numOperands") { |
| bs << "opInst.getNumOperands()"; |
| } else if (name == "$") { |
| bs << '$'; |
| } else { |
| return emitError( |
| record, "expected keyword, argument, or result, but got " + name); |
| } |
| // Finally, only keep the untraversed part of the string. |
| builderStrRef = builderStrRef.substr(loc.pos + loc.length); |
| } |
| |
| // Output the check and the rewritten builder string. |
| os << "if (auto op = dyn_cast<" << op.getQualCppClassName() |
| << ">(opInst)) {\n"; |
| os << bs.str() << builderStrRef << "\n"; |
| os << " return success();\n"; |
| os << "}\n"; |
| |
| return success(); |
| } |
| |
| // Emit all builders. Returns false on success because of the generator |
| // registration requirements. |
| static bool emitBuilders(const RecordKeeper &records, raw_ostream &os) { |
| for (const Record *def : records.getAllDerivedDefinitions("LLVM_OpBase")) { |
| if (failed(emitOneBuilder(*def, os))) |
| return true; |
| } |
| return false; |
| } |
| |
| using ConditionFn = mlir::function_ref<llvm::Twine(const Record &record)>; |
| |
| // Emit a conditional call to the MLIR builder of the LLVM dialect operation to |
| // build for the given LLVM IR instruction. A condition function `conditionFn` |
| // emits a check to verify the opcode or intrinsic identifier of the LLVM IR |
| // instruction matches the LLVM dialect operation to build. |
| static LogicalResult emitOneMLIRBuilder(const Record &record, raw_ostream &os, |
| ConditionFn conditionFn) { |
| auto op = tblgen::Operator(record); |
| |
| if (!record.getValue("mlirBuilder")) |
| return emitError(record, "expected 'mlirBuilder' field"); |
| |
| // Return early if there is no builder specified. |
| StringRef builderStrRef = record.getValueAsString("mlirBuilder"); |
| if (builderStrRef.empty()) |
| return success(); |
| |
| // Access the argument index array that maps argument indices to LLVM IR |
| // operand indices. If the operation defines no custom mapping, set the array |
| // to the identity permutation. |
| std::vector<int64_t> llvmArgIndices = |
| record.getValueAsListOfInts("llvmArgIndices"); |
| if (llvmArgIndices.empty()) |
| append_range(llvmArgIndices, seq<int64_t>(0, op.getNumArgs())); |
| if (llvmArgIndices.size() != static_cast<size_t>(op.getNumArgs())) { |
| return emitError( |
| record, |
| "expected 'llvmArgIndices' size to match the number of arguments"); |
| } |
| |
| // Progressively create the builder string by replacing $-variables. Keep only |
| // the not-yet-traversed part of the builder pattern to avoid re-traversing |
| // the string multiple times. Additionally, emit an argument string |
| // immediately before the builder string. This argument string converts all |
| // operands used by the builder to MLIR values and returns failure if one of |
| // the conversions fails. |
| std::string arguments, builder; |
| llvm::raw_string_ostream as(arguments), bs(builder); |
| while (StringLoc loc = findNextVariable(builderStrRef)) { |
| auto name = loc.in(builderStrRef).drop_front(); |
| // First, insert the non-matched part as is. |
| bs << builderStrRef.substr(0, loc.pos); |
| // Then, rewrite the name based on its kind. |
| FailureOr<int> argIndex = getArgumentIndex(op, name); |
| if (succeeded(argIndex)) { |
| // Access the LLVM IR operand that maps to the given argument index using |
| // the provided argument indices mapping. |
| int64_t idx = llvmArgIndices[*argIndex]; |
| if (idx < 0) { |
| return emitError( |
| record, "expected non-negative operand index for argument " + name); |
| } |
| if (isAttributeName(op, name)) { |
| bs << formatv("llvmOperands[{0}]", idx); |
| } else { |
| if (isVariadicOperandName(op, name)) { |
| as << formatv( |
| "FailureOr<SmallVector<Value>> _llvmir_gen_operand_{0} = " |
| "moduleImport.convertValues(llvmOperands.drop_front({1}));\n", |
| name, idx); |
| } else { |
| as << formatv("FailureOr<Value> _llvmir_gen_operand_{0} = " |
| "moduleImport.convertValue(llvmOperands[{1}]);\n", |
| name, idx); |
| } |
| as << formatv("if (failed(_llvmir_gen_operand_{0}))\n" |
| " return failure();\n", |
| name); |
| bs << formatv("*_llvmir_gen_operand_{0}", name); |
| } |
| } else if (isResultName(op, name)) { |
| if (op.getNumResults() != 1) |
| return emitError(record, "expected op to have one result"); |
| bs << "moduleImport.mapValue(inst)"; |
| } else if (name == "_op") { |
| bs << "moduleImport.mapNoResultOp(inst)"; |
| } else if (name == "_int_attr") { |
| bs << "moduleImport.matchIntegerAttr"; |
| } else if (name == "_float_attr") { |
| bs << "moduleImport.matchFloatAttr"; |
| } else if (name == "_var_attr") { |
| bs << "moduleImport.matchLocalVariableAttr"; |
| } else if (name == "_label_attr") { |
| bs << "moduleImport.matchLabelAttr"; |
| } else if (name == "_fpExceptionBehavior_attr") { |
| bs << "moduleImport.matchFPExceptionBehaviorAttr"; |
| } else if (name == "_roundingMode_attr") { |
| bs << "moduleImport.matchRoundingModeAttr"; |
| } else if (name == "_resultType") { |
| bs << "moduleImport.convertType(inst->getType())"; |
| } else if (name == "_location") { |
| bs << "moduleImport.translateLoc(inst->getDebugLoc())"; |
| } else if (name == "_builder") { |
| bs << "odsBuilder"; |
| } else if (name == "_qualCppClassName") { |
| bs << op.getQualCppClassName(); |
| } else if (name == "$") { |
| bs << '$'; |
| } else { |
| return emitError( |
| record, "expected keyword, argument, or result, but got " + name); |
| } |
| // Finally, only keep the untraversed part of the string. |
| builderStrRef = builderStrRef.substr(loc.pos + loc.length); |
| } |
| |
| // Output the check, the argument conversion, and the builder string. |
| os << "if (" << conditionFn(record) << ") {\n"; |
| os << as.str() << "\n"; |
| os << bs.str() << builderStrRef << "\n"; |
| os << " return success();\n"; |
| os << "}\n"; |
| |
| return success(); |
| } |
| |
| // Emit all intrinsic MLIR builders. Returns false on success because of the |
| // generator registration requirements. |
| static bool emitIntrMLIRBuilders(const RecordKeeper &records, raw_ostream &os) { |
| // Emit condition to check if "llvmEnumName" matches the intrinsic id. |
| auto emitIntrCond = [](const Record &record) { |
| return "intrinsicID == llvm::Intrinsic::" + |
| record.getValueAsString("llvmEnumName"); |
| }; |
| for (const Record *def : |
| records.getAllDerivedDefinitions("LLVM_IntrOpBase")) { |
| if (failed(emitOneMLIRBuilder(*def, os, emitIntrCond))) |
| return true; |
| } |
| return false; |
| } |
| |
| // Emit all op builders. Returns false on success because of the |
| // generator registration requirements. |
| static bool emitOpMLIRBuilders(const RecordKeeper &records, raw_ostream &os) { |
| // Emit condition to check if "llvmInstName" matches the instruction opcode. |
| auto emitOpcodeCond = [](const Record &record) { |
| return "inst->getOpcode() == llvm::Instruction::" + |
| record.getValueAsString("llvmInstName"); |
| }; |
| for (const Record *def : records.getAllDerivedDefinitions("LLVM_OpBase")) { |
| if (failed(emitOneMLIRBuilder(*def, os, emitOpcodeCond))) |
| return true; |
| } |
| return false; |
| } |
| |
| namespace { |
| // Wrapper class around a Tablegen definition of an LLVM enum attribute case. |
| class LLVMEnumAttrCase : public tblgen::EnumAttrCase { |
| public: |
| using tblgen::EnumAttrCase::EnumAttrCase; |
| |
| // Constructs a case from a non LLVM-specific enum attribute case. |
| explicit LLVMEnumAttrCase(const tblgen::EnumAttrCase &other) |
| : tblgen::EnumAttrCase(&other.getDef()) {} |
| |
| // Returns the C++ enumerant for the LLVM API. |
| StringRef getLLVMEnumerant() const { |
| return def->getValueAsString("llvmEnumerant"); |
| } |
| }; |
| |
| // Wraper class around a Tablegen definition of an LLVM enum attribute. |
| class LLVMEnumAttr : public tblgen::EnumAttr { |
| public: |
| using tblgen::EnumAttr::EnumAttr; |
| |
| // Returns the C++ enum name for the LLVM API. |
| StringRef getLLVMClassName() const { |
| return def->getValueAsString("llvmClassName"); |
| } |
| |
| // Returns all associated cases viewed as LLVM-specific enum cases. |
| std::vector<LLVMEnumAttrCase> getAllCases() const { |
| std::vector<LLVMEnumAttrCase> cases; |
| |
| for (auto &c : tblgen::EnumAttr::getAllCases()) |
| cases.emplace_back(c); |
| |
| return cases; |
| } |
| |
| std::vector<LLVMEnumAttrCase> getAllUnsupportedCases() const { |
| const auto *inits = def->getValueAsListInit("unsupported"); |
| |
| std::vector<LLVMEnumAttrCase> cases; |
| cases.reserve(inits->size()); |
| |
| for (const llvm::Init *init : *inits) |
| cases.emplace_back(cast<llvm::DefInit>(init)); |
| |
| return cases; |
| } |
| }; |
| |
| // Wraper class around a Tablegen definition of a C-style LLVM enum attribute. |
| class LLVMCEnumAttr : public tblgen::EnumAttr { |
| public: |
| using tblgen::EnumAttr::EnumAttr; |
| |
| // Returns the C++ enum name for the LLVM API. |
| StringRef getLLVMClassName() const { |
| return def->getValueAsString("llvmClassName"); |
| } |
| |
| // Returns all associated cases viewed as LLVM-specific enum cases. |
| std::vector<LLVMEnumAttrCase> getAllCases() const { |
| std::vector<LLVMEnumAttrCase> cases; |
| |
| for (auto &c : tblgen::EnumAttr::getAllCases()) |
| cases.emplace_back(c); |
| |
| return cases; |
| } |
| }; |
| } // namespace |
| |
| // Emits conversion function "LLVMClass convertEnumToLLVM(Enum)" and containing |
| // switch-based logic to convert from the MLIR LLVM dialect enum attribute case |
| // (Enum) to the corresponding LLVM API enumerant |
| static void emitOneEnumToConversion(const Record *record, raw_ostream &os) { |
| LLVMEnumAttr enumAttr(record); |
| StringRef llvmClass = enumAttr.getLLVMClassName(); |
| StringRef cppClassName = enumAttr.getEnumClassName(); |
| StringRef cppNamespace = enumAttr.getCppNamespace(); |
| |
| // Emit the function converting the enum attribute to its LLVM counterpart. |
| os << formatv( |
| "static LLVM_ATTRIBUTE_UNUSED {0} convert{1}ToLLVM({2}::{1} value) {{\n", |
| llvmClass, cppClassName, cppNamespace); |
| os << " switch (value) {\n"; |
| |
| for (const auto &enumerant : enumAttr.getAllCases()) { |
| StringRef llvmEnumerant = enumerant.getLLVMEnumerant(); |
| StringRef cppEnumerant = enumerant.getSymbol(); |
| os << formatv(" case {0}::{1}::{2}:\n", cppNamespace, cppClassName, |
| cppEnumerant); |
| os << formatv(" return {0}::{1};\n", llvmClass, llvmEnumerant); |
| } |
| |
| os << " }\n"; |
| os << formatv(" llvm_unreachable(\"unknown {0} type\");\n", |
| enumAttr.getEnumClassName()); |
| os << "}\n\n"; |
| } |
| |
| // Emits conversion function "LLVMClass convertEnumToLLVM(Enum)" and containing |
| // switch-based logic to convert from the MLIR LLVM dialect enum attribute case |
| // (Enum) to the corresponding LLVM API C-style enumerant |
| static void emitOneCEnumToConversion(const Record *record, raw_ostream &os) { |
| LLVMCEnumAttr enumAttr(record); |
| StringRef llvmClass = enumAttr.getLLVMClassName(); |
| StringRef cppClassName = enumAttr.getEnumClassName(); |
| StringRef cppNamespace = enumAttr.getCppNamespace(); |
| |
| // Emit the function converting the enum attribute to its LLVM counterpart. |
| os << formatv("static LLVM_ATTRIBUTE_UNUSED int64_t " |
| "convert{0}ToLLVM({1}::{0} value) {{\n", |
| cppClassName, cppNamespace); |
| os << " switch (value) {\n"; |
| |
| for (const auto &enumerant : enumAttr.getAllCases()) { |
| StringRef llvmEnumerant = enumerant.getLLVMEnumerant(); |
| StringRef cppEnumerant = enumerant.getSymbol(); |
| os << formatv(" case {0}::{1}::{2}:\n", cppNamespace, cppClassName, |
| cppEnumerant); |
| os << formatv(" return static_cast<int64_t>({0}::{1});\n", llvmClass, |
| llvmEnumerant); |
| } |
| |
| os << " }\n"; |
| os << formatv(" llvm_unreachable(\"unknown {0} type\");\n", |
| enumAttr.getEnumClassName()); |
| os << "}\n\n"; |
| } |
| |
| // Emits conversion function "Enum convertEnumFromLLVM(LLVMClass)" and |
| // containing switch-based logic to convert from the LLVM API enumerant to MLIR |
| // LLVM dialect enum attribute (Enum). |
| static void emitOneEnumFromConversion(const Record *record, raw_ostream &os) { |
| LLVMEnumAttr enumAttr(record); |
| StringRef llvmClass = enumAttr.getLLVMClassName(); |
| StringRef cppClassName = enumAttr.getEnumClassName(); |
| StringRef cppNamespace = enumAttr.getCppNamespace(); |
| |
| // Emit the function converting the enum attribute from its LLVM counterpart. |
| os << formatv("inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM({2} " |
| "value) {{\n", |
| cppNamespace, cppClassName, llvmClass); |
| os << " switch (value) {\n"; |
| |
| for (const auto &enumerant : enumAttr.getAllCases()) { |
| StringRef llvmEnumerant = enumerant.getLLVMEnumerant(); |
| StringRef cppEnumerant = enumerant.getSymbol(); |
| os << formatv(" case {0}::{1}:\n", llvmClass, llvmEnumerant); |
| os << formatv(" return {0}::{1}::{2};\n", cppNamespace, cppClassName, |
| cppEnumerant); |
| } |
| for (const auto &enumerant : enumAttr.getAllUnsupportedCases()) { |
| StringRef llvmEnumerant = enumerant.getLLVMEnumerant(); |
| os << formatv(" case {0}::{1}:\n", llvmClass, llvmEnumerant); |
| os << formatv(" llvm_unreachable(\"unsupported case {0}::{1}\");\n", |
| enumAttr.getLLVMClassName(), llvmEnumerant); |
| } |
| |
| os << " }\n"; |
| os << formatv(" llvm_unreachable(\"unknown {0} type\");", |
| enumAttr.getLLVMClassName()); |
| os << "}\n\n"; |
| } |
| |
| // Emits conversion function "Enum convertEnumFromLLVM(LLVMEnum)" and |
| // containing switch-based logic to convert from the LLVM API C-style enumerant |
| // to MLIR LLVM dialect enum attribute (Enum). |
| static void emitOneCEnumFromConversion(const Record *record, raw_ostream &os) { |
| LLVMCEnumAttr enumAttr(record); |
| StringRef llvmClass = enumAttr.getLLVMClassName(); |
| StringRef cppClassName = enumAttr.getEnumClassName(); |
| StringRef cppNamespace = enumAttr.getCppNamespace(); |
| |
| // Emit the function converting the enum attribute from its LLVM counterpart. |
| os << formatv( |
| "inline LLVM_ATTRIBUTE_UNUSED {0}::{1} convert{1}FromLLVM(int64_t " |
| "value) {{\n", |
| cppNamespace, cppClassName); |
| os << " switch (value) {\n"; |
| |
| for (const auto &enumerant : enumAttr.getAllCases()) { |
| StringRef llvmEnumerant = enumerant.getLLVMEnumerant(); |
| StringRef cppEnumerant = enumerant.getSymbol(); |
| os << formatv(" case static_cast<int64_t>({0}::{1}):\n", llvmClass, |
| llvmEnumerant); |
| os << formatv(" return {0}::{1}::{2};\n", cppNamespace, cppClassName, |
| cppEnumerant); |
| } |
| |
| os << " }\n"; |
| os << formatv(" llvm_unreachable(\"unknown {0} type\");", |
| enumAttr.getLLVMClassName()); |
| os << "}\n\n"; |
| } |
| |
| // Emits conversion functions between MLIR enum attribute case and corresponding |
| // LLVM API enumerants for all registered LLVM dialect enum attributes. |
| template <bool ConvertTo> |
| static bool emitEnumConversionDefs(const RecordKeeper &records, |
| raw_ostream &os) { |
| for (const Record *def : records.getAllDerivedDefinitions("LLVM_EnumAttr")) |
| if (ConvertTo) |
| emitOneEnumToConversion(def, os); |
| else |
| emitOneEnumFromConversion(def, os); |
| |
| for (const Record *def : records.getAllDerivedDefinitions("LLVM_CEnumAttr")) |
| if (ConvertTo) |
| emitOneCEnumToConversion(def, os); |
| else |
| emitOneCEnumFromConversion(def, os); |
| |
| return false; |
| } |
| |
| static void emitOneIntrinsic(const Record &record, raw_ostream &os) { |
| auto op = tblgen::Operator(record); |
| os << "llvm::Intrinsic::" << record.getValueAsString("llvmEnumName") << ",\n"; |
| } |
| |
| // Emit the list of LLVM IR intrinsics identifiers that are convertible to a |
| // matching MLIR LLVM dialect intrinsic operation. |
| static bool emitConvertibleIntrinsics(const RecordKeeper &records, |
| raw_ostream &os) { |
| for (const Record *def : records.getAllDerivedDefinitions("LLVM_IntrOpBase")) |
| emitOneIntrinsic(*def, os); |
| |
| return false; |
| } |
| |
| static mlir::GenRegistration |
| genLLVMIRConversions("gen-llvmir-conversions", |
| "Generate LLVM IR conversions", emitBuilders); |
| |
| static mlir::GenRegistration genOpFromLLVMIRConversions( |
| "gen-op-from-llvmir-conversions", |
| "Generate conversions of operations from LLVM IR", emitOpMLIRBuilders); |
| |
| static mlir::GenRegistration genIntrFromLLVMIRConversions( |
| "gen-intr-from-llvmir-conversions", |
| "Generate conversions of intrinsics from LLVM IR", emitIntrMLIRBuilders); |
| |
| static mlir::GenRegistration |
| genEnumToLLVMConversion("gen-enum-to-llvmir-conversions", |
| "Generate conversions of EnumAttrs to LLVM IR", |
| emitEnumConversionDefs</*ConvertTo=*/true>); |
| |
| static mlir::GenRegistration |
| genEnumFromLLVMConversion("gen-enum-from-llvmir-conversions", |
| "Generate conversions of EnumAttrs from LLVM IR", |
| emitEnumConversionDefs</*ConvertTo=*/false>); |
| |
| static mlir::GenRegistration genConvertibleLLVMIRIntrinsics( |
| "gen-convertible-llvmir-intrinsics", |
| "Generate list of convertible LLVM IR intrinsics", |
| emitConvertibleIntrinsics); |