1 //===- LLVMImportInterface.h - Import from LLVM interface -------*- C++ -*-===// 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 header file defines dialect interfaces for the LLVM IR import. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef MLIR_TARGET_LLVMIR_LLVMIMPORTINTERFACE_H 14 #define MLIR_TARGET_LLVMIR_LLVMIMPORTINTERFACE_H 15 16 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 17 #include "mlir/IR/Builders.h" 18 #include "mlir/IR/BuiltinAttributes.h" 19 #include "mlir/IR/Diagnostics.h" 20 #include "mlir/IR/DialectInterface.h" 21 #include "mlir/IR/Location.h" 22 #include "llvm/IR/Instruction.h" 23 #include "llvm/IR/Instructions.h" 24 #include "llvm/Support/FormatVariadic.h" 25 26 namespace llvm { 27 class IRBuilderBase; 28 } // namespace llvm 29 30 namespace mlir { 31 namespace LLVM { 32 class ModuleImport; 33 } // namespace LLVM 34 35 /// Base class for dialect interfaces used to import LLVM IR. Dialects that can 36 /// be imported should provide an implementation of this interface for the 37 /// supported intrinsics. The interface may be implemented in a separate library 38 /// to avoid the "main" dialect library depending on LLVM IR. The interface can 39 /// be attached using the delayed registration mechanism available in 40 /// DialectRegistry. 41 class LLVMImportDialectInterface 42 : public DialectInterface::Base<LLVMImportDialectInterface> { 43 public: 44 LLVMImportDialectInterface(Dialect *dialect) : Base(dialect) {} 45 46 /// Hook for derived dialect interfaces to implement the import of 47 /// intrinsics into MLIR. 48 virtual LogicalResult 49 convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst, 50 LLVM::ModuleImport &moduleImport) const { 51 return failure(); 52 } 53 54 /// Hook for derived dialect interfaces to implement the import of 55 /// instructions into MLIR. 56 virtual LogicalResult 57 convertInstruction(OpBuilder &builder, llvm::Instruction *inst, 58 ArrayRef<llvm::Value *> llvmOperands, 59 LLVM::ModuleImport &moduleImport) const { 60 return failure(); 61 } 62 63 /// Hook for derived dialect interfaces to implement the import of metadata 64 /// into MLIR. Attaches the converted metadata kind and node to the provided 65 /// operation. 66 virtual LogicalResult 67 setMetadataAttrs(OpBuilder &builder, unsigned kind, llvm::MDNode *node, 68 Operation *op, LLVM::ModuleImport &moduleImport) const { 69 return failure(); 70 } 71 72 /// Hook for derived dialect interfaces to publish the supported intrinsics. 73 /// As every LLVM IR intrinsic has a unique integer identifier, the function 74 /// returns the list of supported intrinsic identifiers. 75 virtual ArrayRef<unsigned> getSupportedIntrinsics() const { return {}; } 76 77 /// Hook for derived dialect interfaces to publish the supported instructions. 78 /// As every LLVM IR instruction has a unique integer identifier, the function 79 /// returns the list of supported instruction identifiers. These identifiers 80 /// will then be used to match LLVM instructions to the appropriate import 81 /// interface and `convertInstruction` method. It is an error to have multiple 82 /// interfaces overriding the same instruction. 83 virtual ArrayRef<unsigned> getSupportedInstructions() const { return {}; } 84 85 /// Hook for derived dialect interfaces to publish the supported metadata 86 /// kinds. As every metadata kind has a unique integer identifier, the 87 /// function returns the list of supported metadata identifiers. `ctx` can be 88 /// used to obtain IDs of metadata kinds that do not have a fixed static one. 89 virtual ArrayRef<unsigned> 90 getSupportedMetadata(llvm::LLVMContext &ctx) const { 91 return {}; 92 } 93 }; 94 95 /// Interface collection for the import of LLVM IR that dispatches to a concrete 96 /// dialect interface implementation. Queries the dialect interfaces to obtain a 97 /// list of the supported LLVM IR constructs and then builds a mapping for the 98 /// efficient dispatch. 99 class LLVMImportInterface 100 : public DialectInterfaceCollection<LLVMImportDialectInterface> { 101 public: 102 using Base::Base; 103 104 /// Queries all registered dialect interfaces for the supported LLVM IR 105 /// intrinsic and metadata kinds and builds the dispatch tables for the 106 /// conversion. Returns failure if multiple dialect interfaces translate the 107 /// same LLVM IR intrinsic. 108 LogicalResult initializeImport(llvm::LLVMContext &llvmContext) { 109 for (const LLVMImportDialectInterface &iface : *this) { 110 // Verify the supported intrinsics have not been mapped before. 111 const auto *intrinsicIt = 112 llvm::find_if(iface.getSupportedIntrinsics(), [&](unsigned id) { 113 return intrinsicToDialect.count(id); 114 }); 115 if (intrinsicIt != iface.getSupportedIntrinsics().end()) { 116 return emitError( 117 UnknownLoc::get(iface.getContext()), 118 llvm::formatv( 119 "expected unique conversion for intrinsic ({0}), but " 120 "got conflicting {1} and {2} conversions", 121 *intrinsicIt, iface.getDialect()->getNamespace(), 122 intrinsicToDialect.lookup(*intrinsicIt)->getNamespace())); 123 } 124 const auto *instructionIt = 125 llvm::find_if(iface.getSupportedInstructions(), [&](unsigned id) { 126 return instructionToDialect.count(id); 127 }); 128 if (instructionIt != iface.getSupportedInstructions().end()) { 129 return emitError( 130 UnknownLoc::get(iface.getContext()), 131 llvm::formatv( 132 "expected unique conversion for instruction ({0}), but " 133 "got conflicting {1} and {2} conversions", 134 *intrinsicIt, iface.getDialect()->getNamespace(), 135 instructionToDialect.lookup(*intrinsicIt) 136 ->getDialect() 137 ->getNamespace())); 138 } 139 // Add a mapping for all supported intrinsic identifiers. 140 for (unsigned id : iface.getSupportedIntrinsics()) 141 intrinsicToDialect[id] = iface.getDialect(); 142 // Add a mapping for all supported instruction identifiers. 143 for (unsigned id : iface.getSupportedInstructions()) 144 instructionToDialect[id] = &iface; 145 // Add a mapping for all supported metadata kinds. 146 for (unsigned kind : iface.getSupportedMetadata(llvmContext)) 147 metadataToDialect[kind].push_back(iface.getDialect()); 148 } 149 150 return success(); 151 } 152 153 /// Converts the LLVM intrinsic to an MLIR operation if a conversion exists. 154 /// Returns failure otherwise. 155 LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst, 156 LLVM::ModuleImport &moduleImport) const { 157 // Lookup the dialect interface for the given intrinsic. 158 Dialect *dialect = intrinsicToDialect.lookup(inst->getIntrinsicID()); 159 if (!dialect) 160 return failure(); 161 162 // Dispatch the conversion to the dialect interface. 163 const LLVMImportDialectInterface *iface = getInterfaceFor(dialect); 164 assert(iface && "expected to find a dialect interface"); 165 return iface->convertIntrinsic(builder, inst, moduleImport); 166 } 167 168 /// Returns true if the given LLVM IR intrinsic is convertible to an MLIR 169 /// operation. 170 bool isConvertibleIntrinsic(llvm::Intrinsic::ID id) { 171 return intrinsicToDialect.count(id); 172 } 173 174 /// Converts the LLVM instruction to an MLIR operation if a conversion exists. 175 /// Returns failure otherwise. 176 LogicalResult convertInstruction(OpBuilder &builder, llvm::Instruction *inst, 177 ArrayRef<llvm::Value *> llvmOperands, 178 LLVM::ModuleImport &moduleImport) const { 179 // Lookup the dialect interface for the given instruction. 180 const LLVMImportDialectInterface *iface = 181 instructionToDialect.lookup(inst->getOpcode()); 182 if (!iface) 183 return failure(); 184 185 return iface->convertInstruction(builder, inst, llvmOperands, moduleImport); 186 } 187 188 /// Returns true if the given LLVM IR instruction is convertible to an MLIR 189 /// operation. 190 bool isConvertibleInstruction(unsigned id) { 191 return instructionToDialect.count(id); 192 } 193 194 /// Attaches the given LLVM metadata to the imported operation if a conversion 195 /// to one or more MLIR dialect attributes exists and succeeds. Returns 196 /// success if at least one of the conversions is successful and failure if 197 /// all of them fail. 198 LogicalResult setMetadataAttrs(OpBuilder &builder, unsigned kind, 199 llvm::MDNode *node, Operation *op, 200 LLVM::ModuleImport &moduleImport) const { 201 // Lookup the dialect interfaces for the given metadata. 202 auto it = metadataToDialect.find(kind); 203 if (it == metadataToDialect.end()) 204 return failure(); 205 206 // Dispatch the conversion to the dialect interfaces. 207 bool isSuccess = false; 208 for (Dialect *dialect : it->getSecond()) { 209 const LLVMImportDialectInterface *iface = getInterfaceFor(dialect); 210 assert(iface && "expected to find a dialect interface"); 211 if (succeeded( 212 iface->setMetadataAttrs(builder, kind, node, op, moduleImport))) 213 isSuccess = true; 214 } 215 216 // Returns failure if all conversions fail. 217 return success(isSuccess); 218 } 219 220 /// Returns true if the given LLVM IR metadata is convertible to an MLIR 221 /// attribute. 222 bool isConvertibleMetadata(unsigned kind) { 223 return metadataToDialect.count(kind); 224 } 225 226 private: 227 DenseMap<unsigned, Dialect *> intrinsicToDialect; 228 DenseMap<unsigned, const LLVMImportDialectInterface *> instructionToDialect; 229 DenseMap<unsigned, SmallVector<Dialect *, 1>> metadataToDialect; 230 }; 231 232 } // namespace mlir 233 234 #endif // MLIR_TARGET_LLVMIR_LLVMIMPORTINTERFACE_H 235