//===- ModuleImport.h - LLVM to MLIR conversion -----------------*- C++ -*-===// // // 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 implements the import of an LLVM IR module into an LLVM dialect // module. // //===----------------------------------------------------------------------===// #ifndef MLIR_TARGET_LLVMIR_MODULEIMPORT_H #define MLIR_TARGET_LLVMIR_MODULEIMPORT_H #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/Target/LLVMIR/Import.h" #include "mlir/Target/LLVMIR/LLVMImportInterface.h" #include "mlir/Target/LLVMIR/TypeFromLLVM.h" #include "llvm/IR/Module.h" namespace llvm { class BasicBlock; class CallBase; class DbgVariableIntrinsic; class Function; class Instruction; class Value; } // namespace llvm namespace mlir { namespace LLVM { namespace detail { class DataLayoutImporter; class DebugImporter; class LoopAnnotationImporter; } // namespace detail /// Module import implementation class that provides methods to import globals /// and functions from an LLVM module into an MLIR module. It holds mappings /// between the original and translated globals, basic blocks, and values used /// during the translation. Additionally, it keeps track of the current constant /// insertion point since LLVM immediate values translate to MLIR operations /// that are introduced at the beginning of the region. class ModuleImport { public: ModuleImport(ModuleOp mlirModule, std::unique_ptr llvmModule, bool emitExpensiveWarnings, bool importEmptyDICompositeTypes, bool preferUnregisteredIntrinsics, bool importStructsAsLiterals); /// Calls the LLVMImportInterface initialization that queries the registered /// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds /// and builds the dispatch tables. Returns failure if multiple dialect /// interfaces translate the same LLVM IR intrinsic. LogicalResult initializeImportInterface() { return iface.initializeImport(llvmModule->getContext()); } /// Converts all functions of the LLVM module to MLIR functions. LogicalResult convertFunctions(); /// Converts all comdat selectors of the LLVM module to MLIR comdat /// operations. LogicalResult convertComdats(); /// Converts all global variables of the LLVM module to MLIR global variables. LogicalResult convertGlobals(); /// Converts all aliases of the LLVM module to MLIR variables. LogicalResult convertAliases(); /// Converts all ifuncs of the LLVM module to MLIR variables. LogicalResult convertIFuncs(); /// Converts the data layout of the LLVM module to an MLIR data layout /// specification. LogicalResult convertDataLayout(); /// Converts target triple of the LLVM module to an MLIR target triple /// specification. void convertTargetTriple(); /// Converts the module level asm of the LLVM module to an MLIR module /// level asm specification. void convertModuleLevelAsm(); /// Stores the mapping between an LLVM value and its MLIR counterpart. void mapValue(llvm::Value *llvm, Value mlir) { mapValue(llvm) = mlir; } /// Provides write-once access to store the MLIR value corresponding to the /// given LLVM value. Value &mapValue(llvm::Value *value) { Value &mlir = valueMapping[value]; assert(mlir == nullptr && "attempting to map a value that is already mapped"); return mlir; } /// Returns the MLIR value mapped to the given LLVM value. Value lookupValue(llvm::Value *value) { return valueMapping.lookup(value); } /// Stores a mapping between an LLVM instruction and the imported MLIR /// operation if the operation returns no result. Asserts if the operation /// returns a result and should be added to valueMapping instead. void mapNoResultOp(llvm::Instruction *llvm, Operation *mlir) { mapNoResultOp(llvm) = mlir; } /// Provides write-once access to store the MLIR operation corresponding to /// the given LLVM instruction if the operation returns no result. Asserts if /// the operation returns a result and should be added to valueMapping /// instead. Operation *&mapNoResultOp(llvm::Instruction *inst) { Operation *&mlir = noResultOpMapping[inst]; assert(inst->getType()->isVoidTy() && "attempting to map an operation that returns a result"); assert(mlir == nullptr && "attempting to map an operation that is already mapped"); return mlir; } /// Returns the MLIR operation mapped to the given LLVM instruction. Queries /// valueMapping and noResultOpMapping to support operations with and without /// result. Operation *lookupOperation(llvm::Instruction *inst) { if (Value value = lookupValue(inst)) return value.getDefiningOp(); return noResultOpMapping.lookup(inst); } /// Stores the mapping between an LLVM block and its MLIR counterpart. void mapBlock(llvm::BasicBlock *llvm, Block *mlir) { auto result = blockMapping.try_emplace(llvm, mlir); (void)result; assert(result.second && "attempting to map a block that is already mapped"); } /// Returns the MLIR block mapped to the given LLVM block. Block *lookupBlock(llvm::BasicBlock *block) const { return blockMapping.lookup(block); } /// Converts an LLVM value to an MLIR value, or returns failure if the /// conversion fails. Uses the `convertConstant` method to translate constant /// LLVM values. FailureOr convertValue(llvm::Value *value); /// Converts an LLVM metadata value to an MLIR value, or returns failure if /// the conversion fails. Uses the `convertConstant` method to translate /// constant LLVM values. FailureOr convertMetadataValue(llvm::Value *value); /// Converts a range of LLVM values to a range of MLIR values using the /// `convertValue` method, or returns failure if the conversion fails. FailureOr> convertValues(ArrayRef values); /// Converts `value` to an integer attribute. Asserts if the matching fails. IntegerAttr matchIntegerAttr(llvm::Value *value); /// Converts `value` to a float attribute. Asserts if the matching fails. FloatAttr matchFloatAttr(llvm::Value *value); /// Converts `valOrVariable` to a local variable attribute. Asserts if the /// matching fails. DILocalVariableAttr matchLocalVariableAttr( llvm::PointerUnion valOrVariable); /// Converts `value` to a label attribute. Asserts if the matching fails. DILabelAttr matchLabelAttr(llvm::Value *value); /// Converts `value` to a FP exception behavior attribute. Asserts if the /// matching fails. FPExceptionBehaviorAttr matchFPExceptionBehaviorAttr(llvm::Value *value); /// Converts `value` to a rounding mode attribute. Asserts if the matching /// fails. RoundingModeAttr matchRoundingModeAttr(llvm::Value *value); /// Converts `value` to an array of alias scopes or returns failure if the /// conversion fails. FailureOr> matchAliasScopeAttrs(llvm::Value *value); /// Translates the debug location. Location translateLoc(llvm::DILocation *loc); /// Converts the type from LLVM to MLIR LLVM dialect. Type convertType(llvm::Type *type) { return typeTranslator.translateType(type); } /// Imports `func` into the current module. LogicalResult processFunction(llvm::Function *func); /// Converts function attributes of LLVM Function `func` into LLVM dialect /// attributes of LLVMFuncOp `funcOp`. void processFunctionAttributes(llvm::Function *func, LLVMFuncOp funcOp); /// Sets the integer overflow flags (nsw/nuw) attribute for the imported /// operation `op` given the original instruction `inst`. Asserts if the /// operation does not implement the integer overflow flag interface. void setIntegerOverflowFlags(llvm::Instruction *inst, Operation *op) const; /// Sets the exact flag attribute for the imported operation `op` given /// the original instruction `inst`. Asserts if the operation does not /// implement the exact flag interface. void setExactFlag(llvm::Instruction *inst, Operation *op) const; /// Sets the disjoint flag attribute for the imported operation `op` /// given the original instruction `inst`. Asserts if the operation does /// not implement the disjoint flag interface. void setDisjointFlag(llvm::Instruction *inst, Operation *op) const; /// Sets the nneg flag attribute for the imported operation `op` given /// the original instruction `inst`. Asserts if the operation does not /// implement the nneg flag interface. void setNonNegFlag(llvm::Instruction *inst, Operation *op) const; /// Sets the fastmath flags attribute for the imported operation `op` given /// the original instruction `inst`. Asserts if the operation does not /// implement the fastmath interface. void setFastmathFlagsAttr(llvm::Instruction *inst, Operation *op) const; /// Converts !llvm.linker.options metadata to the llvm.linker.options /// LLVM dialect operation. LogicalResult convertLinkerOptionsMetadata(); /// Converts !llvm.module.flags metadata. LogicalResult convertModuleFlagsMetadata(); /// Converts !llvm.ident metadata to the llvm.ident LLVM ModuleOp attribute. LogicalResult convertIdentMetadata(); /// Converts !llvm.commandline metadata to the llvm.commandline LLVM ModuleOp /// attribute. LogicalResult convertCommandlineMetadata(); /// Converts !llvm.dependent-libraries metadata to llvm.dependent_libraries /// LLVM ModuleOp attribute. LogicalResult convertDependentLibrariesMetadata(); /// Converts all LLVM metadata nodes that translate to attributes such as /// alias analysis or access group metadata, and builds a map from the /// metadata nodes to the converted attributes. /// Returns success if all conversions succeed and failure otherwise. LogicalResult convertMetadata(); /// Returns the MLIR attribute mapped to the given LLVM TBAA /// metadata `node`. Attribute lookupTBAAAttr(const llvm::MDNode *node) const { return tbaaMapping.lookup(node); } /// Returns the access group attributes that map to the access group nodes /// starting from the access group metadata `node`. Returns failure, if any of /// the attributes cannot be found. FailureOr> lookupAccessGroupAttrs(const llvm::MDNode *node) const; /// Returns the loop annotation attribute that corresponds to the given LLVM /// loop metadata `node`. LoopAnnotationAttr translateLoopAnnotationAttr(const llvm::MDNode *node, Location loc) const; /// Returns the dereferenceable attribute that corresponds to the given LLVM /// dereferenceable or dereferenceable_or_null metadata `node`. `kindID` /// specifies the kind of the metadata node (dereferenceable or /// dereferenceable_or_null). FailureOr translateDereferenceableAttr(const llvm::MDNode *node, unsigned kindID); /// Returns the alias scope attributes that map to the alias scope nodes /// starting from the metadata `node`. Returns failure, if any of the /// attributes cannot be found. FailureOr> lookupAliasScopeAttrs(const llvm::MDNode *node) const; /// Adds a debug intrinsics to the list of intrinsics that should be converted /// after the function conversion has finished. void addDebugIntrinsic(llvm::CallInst *intrinsic); /// Adds a debug record to the list of debug records that need to be imported /// after the function conversion has finished. void addDebugRecord(llvm::DbgVariableRecord *dbgRecord); /// Converts the LLVM values for an intrinsic to mixed MLIR values and /// attributes for LLVM_IntrOpBase. Attributes correspond to LLVM immargs. The /// list `immArgPositions` contains the positions of immargs on the LLVM /// intrinsic, and `immArgAttrNames` list (of the same length) contains the /// corresponding MLIR attribute names. LogicalResult convertIntrinsicArguments(ArrayRef values, ArrayRef opBundles, bool requiresOpBundles, ArrayRef immArgPositions, ArrayRef immArgAttrNames, SmallVectorImpl &valuesOut, SmallVectorImpl &attrsOut); /// Converts the argument and result attributes attached to `call` and adds /// them to `attrsOp`. For intrinsic calls, filters out attributes /// corresponding to immediate arguments specified by `immArgPositions`. void convertArgAndResultAttrs(llvm::CallBase *call, ArgAndResultAttrsOpInterface attrsOp, ArrayRef immArgPositions = {}); /// Whether the importer should try to convert all intrinsics to /// llvm.call_intrinsic instead of dialect supported operations. bool useUnregisteredIntrinsicsOnly() const { return preferUnregisteredIntrinsics; } private: /// Clears the accumulated state before processing a new region. void clearRegionState() { valueMapping.clear(); noResultOpMapping.clear(); blockMapping.clear(); debugIntrinsics.clear(); } /// Sets the constant insertion point to the start of the given block. void setConstantInsertionPointToStart(Block *block) { constantInsertionBlock = block; constantInsertionOp = nullptr; } /// Converts an LLVM global variable into an MLIR LLVM dialect global /// operation if a conversion exists. Otherwise, returns failure. LogicalResult convertGlobal(llvm::GlobalVariable *globalVar); /// Imports the magic globals "global_ctors" and "global_dtors". LogicalResult convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar); /// Converts an LLVM global alias variable into an MLIR LLVM dialect alias /// operation if a conversion exists. Otherwise, returns failure. LogicalResult convertAlias(llvm::GlobalAlias *alias); // Converts an LLVM global ifunc into an MLIR LLVM dialect ifunc operation. LogicalResult convertIFunc(llvm::GlobalIFunc *ifunc); /// Returns personality of `func` as a FlatSymbolRefAttr. FlatSymbolRefAttr getPersonalityAsAttr(llvm::Function *func); /// Imports `bb` into `block`, which must be initially empty. LogicalResult processBasicBlock(llvm::BasicBlock *bb, Block *block); /// Converts all debug intrinsics in `debugIntrinsics`. Assumes that the /// function containing the intrinsics has been fully converted to MLIR. LogicalResult processDebugIntrinsics(); /// Converts all debug records in `dbgRecords`. Assumes that the /// function containing the record has been fully converted to MLIR. LogicalResult processDebugRecords(); /// Converts a single debug intrinsic. LogicalResult processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr, DominanceInfo &domInfo); /// Converts a single debug record. LogicalResult processDebugRecord(llvm::DbgVariableRecord &dbgRecord, DominanceInfo &domInfo); /// Process arguments for declare/value operation insertion. `localVarAttr` /// and `localExprAttr` are the attained attributes after importing the debug /// variable and expressions. This also sets the builder insertion point to be /// used by these operations. std::tuple processDebugOpArgumentsAndInsertionPt( Location loc, llvm::function_ref()> convertArgOperandToValue, llvm::Value *address, llvm::PointerUnion variable, llvm::DIExpression *expression, DominanceInfo &domInfo); /// Converts LLMV IR asm inline call operand's attributes into an array of /// MLIR attributes to be utilized in `llvm.inline_asm`. ArrayAttr convertAsmInlineOperandAttrs(const llvm::CallBase &llvmCall); /// Converts an LLVM intrinsic to an MLIR LLVM dialect operation if an MLIR /// counterpart exists. Otherwise, returns failure. LogicalResult convertIntrinsic(llvm::CallInst *inst); /// Converts an LLVM instruction to an MLIR LLVM dialect operation if an MLIR /// counterpart exists. Otherwise, returns failure. LogicalResult convertInstruction(llvm::Instruction *inst); /// Converts the metadata attached to the original instruction `inst` if /// a dialect interfaces supports the specific kind of metadata and attaches /// the resulting dialect attributes to the converted operation `op`. Emits a /// warning if the conversion of a supported metadata kind fails. void setNonDebugMetadataAttrs(llvm::Instruction *inst, Operation *op); /// Imports `inst` and populates valueMapping[inst] with the result of the /// imported operation or noResultOpMapping[inst] with the imported operation /// if it has no result. LogicalResult processInstruction(llvm::Instruction *inst); /// Converts the `branch` arguments in the order of the phi's found in /// `target` and appends them to the `blockArguments` to attach to the /// generated branch operation. The `blockArguments` thus have the same order /// as the phi's in `target`. LogicalResult convertBranchArgs(llvm::Instruction *branch, llvm::BasicBlock *target, SmallVectorImpl &blockArguments); /// Convert `callInst` operands. For indirect calls, the method additionally /// inserts the called function at the beginning of the returned `operands` /// array. If `allowInlineAsm` is set to false (the default), it will return /// failure if the called operand is an inline asm which isn't convertible to /// MLIR as a value. FailureOr> convertCallOperands(llvm::CallBase *callInst, bool allowInlineAsm = false); /// Converts the callee's function type. For direct calls, it converts the /// actual function type, which may differ from the called operand type in /// variadic functions. For indirect calls, it converts the function type /// associated with the call instruction. When the call and the callee are not /// compatible (or when nested type conversions failed), emit a warning and /// update `isIncompatibleCall` to indicate it. FailureOr convertFunctionType(llvm::CallBase *callInst, bool &isIncompatibleCall); /// Returns the callee name, or an empty symbol if the call is not direct. FlatSymbolRefAttr convertCalleeName(llvm::CallBase *callInst); /// Converts the argument and result attributes attached to `func` and adds /// them to the `funcOp`. void convertArgAndResultAttrs(llvm::Function *func, LLVMFuncOp funcOp); /// Converts the argument or result attributes in `llvmAttrSet` to a /// corresponding MLIR LLVM dialect attribute dictionary. DictionaryAttr convertArgOrResultAttrSet(llvm::AttributeSet llvmAttrSet); /// Converts the attributes attached to `inst` and adds them to the `op`. LogicalResult convertCallAttributes(llvm::CallInst *inst, CallOp op); /// Converts the attributes attached to `inst` and adds them to the `op`. LogicalResult convertInvokeAttributes(llvm::InvokeInst *inst, InvokeOp op); /// Returns the builtin type equivalent to the given LLVM dialect type or /// nullptr if there is no equivalent. The returned type can be used to create /// an attribute for a GlobalOp or a ConstantOp. Type getBuiltinTypeForAttr(Type type); /// Returns `constant` as an attribute to attach to a GlobalOp or ConstantOp /// or nullptr if the constant is not convertible. It supports scalar integer /// and float constants as well as shaped types thereof including strings. Attribute getConstantAsAttr(llvm::Constant *constant); /// Returns the topologically sorted set of transitive dependencies needed to /// convert the given constant. SetVector getConstantsToConvert(llvm::Constant *constant); /// Converts an LLVM constant to an MLIR value, or returns failure if the /// conversion fails. The MLIR value may be produced by a ConstantOp, /// AddressOfOp, NullOp, or a side-effect free operation (for ConstantExprs or /// ConstantGEPs). FailureOr convertConstant(llvm::Constant *constant); /// Converts an LLVM constant and its transitive constant dependencies to MLIR /// operations by converting them in topological order using the /// `convertConstant` method, or returns failure if the conversion of any of /// them fails. All operations are inserted at the start of the current /// function entry block. FailureOr convertConstantExpr(llvm::Constant *constant); /// Returns a global comdat operation that serves as a container for LLVM /// comdat selectors. Creates the global comdat operation on the first /// invocation. ComdatOp getGlobalComdatOp(); /// Performs conversion of LLVM TBAA metadata starting from /// `node`. On exit from this function all nodes reachable /// from `node` are converted, and tbaaMapping map is updated /// (unless all dependencies have been converted by a previous /// invocation of this function). LogicalResult processTBAAMetadata(const llvm::MDNode *node); /// Converts all LLVM access groups starting from `node` to MLIR access group /// operations and stores a mapping from every nested access group node to the /// translated attribute. Returns success if all conversions succeed and /// failure otherwise. LogicalResult processAccessGroupMetadata(const llvm::MDNode *node); /// Converts all LLVM alias scopes and domains starting from `node` to MLIR /// alias scope and domain attributes and stores a mapping from every nested /// alias scope or alias domain node to the translated attribute. Returns /// success if all conversions succeed and failure otherwise. LogicalResult processAliasScopeMetadata(const llvm::MDNode *node); /// Converts the given LLVM comdat struct to an MLIR comdat selector operation /// and stores a mapping from the struct to the symbol pointing to the /// translated operation. void processComdat(const llvm::Comdat *comdat); /// Returns a symbol name for a nameless global. MLIR, in contrast to LLVM, /// always requires a symbol name. FlatSymbolRefAttr getOrCreateNamelessSymbolName(llvm::GlobalVariable *globalVar); /// Returns the global insertion point for the next global operation. If the /// `globalInsertionOp` is set, the insertion point is placed after the /// specified operation. Otherwise, it defaults to the start of the module. OpBuilder::InsertionGuard setGlobalInsertionPoint(); /// Builder pointing at where the next instruction should be generated. OpBuilder builder; /// Block to insert the next constant into. Block *constantInsertionBlock = nullptr; /// Operation to insert the next constant after. Operation *constantInsertionOp = nullptr; /// Operation to insert the next global after. Operation *globalInsertionOp = nullptr; /// Operation to insert comdat selector operations into. ComdatOp globalComdatOp = nullptr; /// The current context. MLIRContext *context; /// The MLIR module being created. ModuleOp mlirModule; /// The LLVM module being imported. std::unique_ptr llvmModule; /// Nameless globals. DenseMap namelessGlobals; /// Counter used to assign a unique ID to each nameless global. unsigned namelessGlobalId = 0; /// A dialect interface collection used for dispatching the import to specific /// dialects. LLVMImportInterface iface; /// Function-local mapping between original and imported block. DenseMap blockMapping; /// Function-local mapping between original and imported values. DenseMap valueMapping; /// Function-local mapping between original instructions and imported /// operations for all operations that return no result. All operations that /// return a result have a valueMapping entry instead. DenseMap noResultOpMapping; /// Function-local list of debug intrinsics that need to be imported after the /// function conversion has finished. SetVector debugIntrinsics; /// Function-local list of debug records that need to be imported after the /// function conversion has finished. SetVector dbgRecords; /// Mapping between LLVM alias scope and domain metadata nodes and /// attributes in the LLVM dialect corresponding to these nodes. DenseMap aliasScopeMapping; /// Mapping between LLVM TBAA metadata nodes and LLVM dialect TBAA attributes /// corresponding to these nodes. DenseMap tbaaMapping; /// Mapping between LLVM comdat structs and symbol references to LLVM dialect /// comdat selector operations corresponding to these structs. DenseMap comdatMapping; /// The stateful type translator (contains named structs). LLVM::TypeFromLLVMIRTranslator typeTranslator; /// Stateful debug information importer. std::unique_ptr debugImporter; /// Loop annotation importer. std::unique_ptr loopAnnotationImporter; /// An option to control if expensive but uncritical diagnostics should be /// emitted. Avoids generating warnings for unhandled debug intrinsics and /// metadata that otherwise dominate the translation time for large inputs. bool emitExpensiveWarnings; /// An option to control whether the importer should try to convert all /// intrinsics to llvm.call_intrinsic instead of dialect supported operations. bool preferUnregisteredIntrinsics; }; } // namespace LLVM } // namespace mlir #endif // MLIR_TARGET_LLVMIR_MODULEIMPORT_H