| //===-- LLVMOpBase.td - LLVM IR dialect shared definitions -*- tablegen -*-===// |
| // |
| // 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 contains shared definitions for the LLVM IR dialect and its |
| // subdialects. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVMIR_OP_BASE |
| #define LLVMIR_OP_BASE |
| |
| include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td" |
| include "mlir/Dialect/LLVMIR/LLVMInterfaces.td" |
| include "mlir/IR/OpBase.td" |
| include "mlir/Interfaces/SideEffectInterfaces.td" |
| |
| //===----------------------------------------------------------------------===// |
| // LLVM dialect type constraints. |
| //===----------------------------------------------------------------------===// |
| |
| // LLVM dialect type. |
| def LLVM_Type : DialectType<LLVM_Dialect, |
| CPred<"::mlir::LLVM::isCompatibleOuterType($_self)">, |
| "LLVM dialect-compatible type">; |
| |
| // Type constraint accepting LLVM token type. |
| def LLVM_TokenType : Type< |
| CPred<"::llvm::isa<::mlir::LLVM::LLVMTokenType>($_self)">, |
| "LLVM token type">, |
| BuildableType<"::mlir::LLVM::LLVMTokenType::get($_builder.getContext())">; |
| |
| // Type constraint accepting LLVM primitive types, i.e. all types except void |
| // and function. |
| def LLVM_PrimitiveType : Type< |
| And<[LLVM_Type.predicate, |
| CPred<"!::llvm::isa<::mlir::LLVM::LLVMVoidType, " |
| "::mlir::LLVM::LLVMFunctionType>($_self)">]>, |
| "primitive LLVM type">; |
| |
| // Type constraint accepting any LLVM function type. |
| def LLVM_FunctionType : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMFunctionType>($_self)">, |
| "LLVM function type", "::mlir::LLVM::LLVMFunctionType">; |
| |
| // Type constraint accepting any LLVM floating point type. |
| def LLVM_AnyFloat : Type< |
| CPred<"::mlir::LLVM::isCompatibleFloatingPointType($_self)">, |
| "floating point LLVM type">; |
| |
| // Type constraint accepting any LLVM pointer type. |
| def LLVM_AnyPointer : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMPointerType>($_self)">, |
| "LLVM pointer type", "::mlir::LLVM::LLVMPointerType">; |
| |
| // Pointer in a given address space. |
| class LLVM_PointerInAddressSpace<int addressSpace> : Type< |
| And<[LLVM_AnyPointer.predicate, |
| CPred< |
| "::llvm::cast<::mlir::LLVM::LLVMPointerType>($_self).getAddressSpace() == " |
| # addressSpace>]>, |
| "LLVM pointer in address space " # addressSpace, |
| "::mlir::LLVM::LLVMPointerType"> { |
| let builderCall = "$_builder.getType<::mlir::LLVM::LLVMPointerType>(" |
| # addressSpace # ")"; |
| } |
| |
| // Type constraint accepting an LLVM pointer type in address space 0. |
| def LLVM_DefaultPointer : LLVM_PointerInAddressSpace<0>; |
| |
| // Type constraint accepting any LLVM structure type. |
| def LLVM_AnyStruct : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMStructType>($_self)">, |
| "LLVM structure type">; |
| |
| // Type constraint accepting opaque LLVM structure type. |
| def LLVM_OpaqueStruct : Type< |
| And<[LLVM_AnyStruct.predicate, |
| CPred<"::llvm::cast<::mlir::LLVM::LLVMStructType>($_self).isOpaque()">]>>; |
| |
| // Type constraint accepting any LLVM target extension type. |
| def LLVM_AnyTargetExt : Type<CPred<"::llvm::isa<::mlir::LLVM::LLVMTargetExtType>($_self)">, |
| "LLVM target extension type">; |
| |
| // Type constraint accepting LLVM target extension types with no support for |
| // memory operations such as alloca, load and store. |
| def LLVM_NonLoadableTargetExtType : Type< |
| And<[LLVM_AnyTargetExt.predicate, |
| CPred<"!::llvm::cast<::mlir::LLVM::LLVMTargetExtType>($_self).supportsMemOps()">] |
| >>; |
| |
| // Type constraint accepting any LLVM type that can be loaded or stored, i.e. a |
| // type that has size (not void, function, opaque struct type or target |
| // extension type which does not support memory operations). |
| def LLVM_LoadableType : Type< |
| Or<[And<[LLVM_PrimitiveType.predicate, Neg<LLVM_OpaqueStruct.predicate>, |
| Neg<LLVM_NonLoadableTargetExtType.predicate>]>, |
| LLVM_PointerElementTypeInterface.predicate]>, |
| "LLVM type with size">; |
| |
| // Type constraint accepting any LLVM aggregate type, i.e. structure or array. |
| def LLVM_AnyAggregate : Type< |
| CPred<"::llvm::isa<::mlir::LLVM::LLVMStructType, " |
| "::mlir::LLVM::LLVMArrayType>($_self)">, |
| "LLVM aggregate type">; |
| |
| // Type constraint accepting any LLVM non-aggregate type, i.e. not structure or |
| // array. |
| def LLVM_AnyNonAggregate : Type<And<[LLVM_Type.predicate, |
| Neg<LLVM_AnyAggregate.predicate>]>, |
| "LLVM-compatible non-aggregate type">; |
| |
| // Type constraint accepting any LLVM vector type. |
| def LLVM_AnyVector : Type<CPred<"::mlir::LLVM::isCompatibleVectorType($_self)">, |
| "LLVM dialect-compatible vector type">; |
| |
| // Type constraint accepting any LLVM fixed-length vector type. |
| def LLVM_AnyFixedVector : Type<CPred< |
| "!::mlir::LLVM::isScalableVectorType($_self)">, |
| "LLVM dialect-compatible fixed-length vector type">; |
| |
| // Type constraint accepting any LLVM scalable vector type. |
| def LLVM_AnyScalableVector : Type<CPred< |
| "::mlir::LLVM::isScalableVectorType($_self)">, |
| "LLVM dialect-compatible scalable vector type">; |
| |
| // Type constraint accepting an LLVM vector type with an additional constraint |
| // on the vector element type. |
| class LLVM_VectorOf<Type element> : Type< |
| And<[LLVM_AnyVector.predicate, |
| SubstLeaves< |
| "$_self", |
| "::mlir::LLVM::getVectorElementType($_self)", |
| element.predicate>]>, |
| "LLVM dialect-compatible vector of " # element.summary>; |
| |
| // Type constraint accepting a constrained type, or a vector of such types. |
| class LLVM_ScalarOrVectorOf<Type element> : |
| AnyTypeOf<[element, LLVM_VectorOf<element>]>; |
| |
| // Base class for LLVM operations. Defines the interface to the llvm::IRBuilder |
| // used to translate to proper LLVM IR and the interface to the mlir::OpBuilder |
| // used to import from LLVM IR. |
| class LLVM_OpBase<Dialect dialect, string mnemonic, list<Trait> traits = []> : |
| Op<dialect, mnemonic, traits> { |
| // A pattern for constructing the LLVM IR Instruction (or other Value) that |
| // corresponds to this op. This pattern can use `builder` to refer to an |
| // `llvm::IRBuilder<>` instance, $-names of arguments and results and the |
| // following special variable names: |
| // - $_resultType - substituted with the LLVM IR type of the result; |
| // - $_numOperands - substituted with the number of operands (including |
| // the variadic ones); |
| // - $_hasResult - substituted with a check that a variadic-result op does |
| // have a result (LLVM ops can have 0 or 1 result); |
| // - $_location - mlir::Location object of the instruction. |
| // Additionally, `$$` can be used to produce the dollar character. |
| string llvmBuilder = ""; |
| |
| // A builder to construct the MLIR LLVM dialect operation given the matching |
| // LLVM IR instruction `inst` and its operands `llvmOperands`. The |
| // following $-variables exist: |
| // - $name - substituted by the remapped `inst` operand value at the index |
| // of the MLIR operation argument with the given name, or if the |
| // name matches the result name, by a reference to store the |
| // result of the newly created MLIR operation to; |
| // - $_op - substituted by a reference to store the newly created MLIR |
| // operation (only for MLIR operations that return no result); |
| // - $_int_attr - substituted by a call to an integer attribute matcher; |
| // - $_float_attr - substituted by a call to a float attribute matcher; |
| // - $_var_attr - substituted by a call to a variable attribute matcher; |
| // - $_label_attr - substituted by a call to a label attribute matcher; |
| // - $_roundingMode_attr - substituted by a call to a rounding mode |
| // attribute matcher; |
| // - $_fpExceptionBehavior_attr - substituted by a call to a FP exception |
| // behavior attribute matcher; |
| // - $_resultType - substituted with the MLIR result type; |
| // - $_location - substituted with the MLIR location; |
| // - $_builder - substituted with the MLIR builder; |
| // - $_qualCppClassName - substitiuted with the MLIR operation class name. |
| // Always either store a reference to the result of the newly created |
| // operation, or to the operation itself if it does not return a result. |
| // Additionally, `$$` can be used to produce the dollar character. |
| string mlirBuilder = ""; |
| |
| // An array that specifies a mapping from MLIR argument indices to LLVM IR |
| // operand indices. The mapping is necessary since argument and operand |
| // indices do not always match. If not defined, the array is set to the |
| // identity permutation. An operation may define any custom index permutation |
| // and set a specific argument index to -1 if it does not map to an LLVM IR |
| // operand. |
| list<int> llvmArgIndices = []; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Patterns for LLVM dialect operations. |
| //===----------------------------------------------------------------------===// |
| |
| // Patterns with code to set flags and metadata of memory operations after their |
| // translation to LLVM IR instructions. Operations may use the patterns to |
| // implement their "llvmBuilder". The patterns assume the `op` and `inst` |
| // variables exist and refer to the original MLIR operation and the translated |
| // LLVM IR instruction, respectively. |
| class LLVM_MemOpPatterns { |
| code setAlignmentCode = [{ |
| if ($alignment.has_value()) { |
| auto align = *$alignment; |
| if (align != 0) |
| inst->setAlignment(llvm::Align(align)); |
| } |
| }]; |
| code setVolatileCode = [{ |
| inst->setVolatile($volatile_); |
| }]; |
| code setSyncScopeCode = [{ |
| if ($syncscope.has_value()) { |
| llvm::LLVMContext &llvmContext = builder.getContext(); |
| inst->setSyncScopeID(llvmContext.getOrInsertSyncScopeID(*$syncscope)); |
| } |
| }]; |
| code setOrderingCode = [{ |
| inst->setAtomic(convertAtomicOrderingToLLVM($ordering)); |
| }]; |
| code setNonTemporalMetadataCode = [{ |
| if ($nontemporal) { |
| llvm::MDNode *metadata = llvm::MDNode::get( |
| inst->getContext(), llvm::ConstantAsMetadata::get( |
| builder.getInt32(1))); |
| inst->setMetadata(llvm::LLVMContext::MD_nontemporal, metadata); |
| } |
| }]; |
| code setAccessGroupsMetadataCode = [{ |
| moduleTranslation.setAccessGroupsMetadata(op, inst); |
| }]; |
| code setAliasAnalysisMetadataCode = [{ |
| moduleTranslation.setAliasScopeMetadata(op, inst); |
| moduleTranslation.setTBAAMetadata(op, inst); |
| }]; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Base classes for LLVM dialect operations. |
| //===----------------------------------------------------------------------===// |
| |
| // Base class for LLVM operations. All operations get an "llvm." prefix in |
| // their name automatically and should either have zero or one result. |
| class LLVM_Op<string mnemonic, list<Trait> traits = []> : |
| LLVM_OpBase<LLVM_Dialect, mnemonic, traits>; |
| |
| // Base class for LLVM memory access operations that implement the access group |
| // and alias analysis interfaces. The "aliasAttrs" list contains the arguments |
| // required by the access group and alias analysis interfaces. Derived |
| // operations should append the "aliasAttrs" to their argument list. |
| class LLVM_MemAccessOpBase<string mnemonic, list<Trait> traits = []> : |
| LLVM_Op<mnemonic, !listconcat([ |
| DeclareOpInterfaceMethods<AccessGroupOpInterface>, |
| DeclareOpInterfaceMethods<AliasAnalysisOpInterface>], traits)>, |
| LLVM_MemOpPatterns { |
| dag aliasAttrs = (ins OptionalAttr<LLVM_AccessGroupArrayAttr>:$access_groups, |
| OptionalAttr<LLVM_AliasScopeArrayAttr>:$alias_scopes, |
| OptionalAttr<LLVM_AliasScopeArrayAttr>:$noalias_scopes, |
| OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa); |
| } |
| |
| // Base class for LLVM intrinsics operation. It is similar to LLVM_Op, but |
| // provides the "llvmBuilder" field for constructing the intrinsic. |
| // The builder relies on the contents of "overloadedResults" and |
| // "overloadedOperands" lists that contain the positions of intrinsic results |
| // and operands that are overloadable in the LLVM sense, that is their types |
| // must be passed in during the construction of the intrinsic declaration to |
| // differentiate between differently-typed versions of the intrinsic. |
| // If the intrinsic has multiple results, this will eventually be packed into a |
| // single struct result. In this case, the types of any overloaded results need |
| // to be accessed via the LLVMStructType, instead of directly via the result. |
| // "opName" contains the name of the operation to be associated with the |
| // intrinsic and "enumName" contains the name of the intrinsic as appears in |
| // `llvm::Intrinsic` enum; one usually wants these to be related. Additionally, |
| // the base class also defines the "mlirBuilder" field to support the inverse |
| // translation starting from an LLVM IR intrinsic. The "requiresAccessGroup", |
| // "requiresAliasAnalysis", and "requiresFastmath" flags specify which |
| // interfaces the intrinsic implements. If the corresponding flags are set, the |
| // "aliasAttrs" list contains the arguments required by the access group and |
| // alias analysis interfaces. Derived intrinsics should append the "aliasAttrs" |
| // to their argument list if they set one of the flags. LLVM `immargs` can be |
| // represented as MLIR attributes by providing both the `immArgPositions` and |
| // `immArgAttrNames` lists. These two lists should have equal length, with |
| // `immArgPositions` containing the argument positions on the LLVM IR attribute |
| // that are `immargs`, and `immArgAttrNames` mapping these to corresponding |
| // MLIR attributes. |
| class LLVM_IntrOpBase<Dialect dialect, string opName, string enumName, |
| list<int> overloadedResults, list<int> overloadedOperands, |
| list<Trait> traits, int numResults, |
| bit requiresAccessGroup = 0, bit requiresAliasAnalysis = 0, |
| bit requiresFastmath = 0, |
| list<int> immArgPositions = [], |
| list<string> immArgAttrNames = []> |
| : LLVM_OpBase<dialect, opName, !listconcat( |
| !if(!gt(requiresAccessGroup, 0), |
| [DeclareOpInterfaceMethods<AccessGroupOpInterface>], []), |
| !if(!gt(requiresAliasAnalysis, 0), |
| [DeclareOpInterfaceMethods<AliasAnalysisOpInterface>], []), |
| !if(!gt(requiresFastmath, 0), |
| [DeclareOpInterfaceMethods<FastmathFlagsInterface>], []), |
| traits)>, |
| LLVM_MemOpPatterns, |
| Results<!if(!gt(numResults, 0), (outs LLVM_Type:$res), (outs))> { |
| dag aliasAttrs = !con( |
| !if(!gt(requiresAccessGroup, 0), |
| (ins OptionalAttr<LLVM_AccessGroupArrayAttr>:$access_groups), |
| (ins )), |
| !if(!gt(requiresAliasAnalysis, 0), |
| (ins OptionalAttr<LLVM_AliasScopeArrayAttr>:$alias_scopes, |
| OptionalAttr<LLVM_AliasScopeArrayAttr>:$noalias_scopes, |
| OptionalAttr<LLVM_TBAATagArrayAttr>:$tbaa), |
| (ins ))); |
| string llvmEnumName = enumName; |
| string overloadedResultsCpp = "{" # !interleave(overloadedResults, ", ") # "}"; |
| string overloadedOperandsCpp = "{" # !interleave(overloadedOperands, ", ") # "}"; |
| string immArgPositionsCpp = "{" # !interleave(immArgPositions, ", ") # "}"; |
| string immArgAttrNamesCpp = "{" # !interleave(!foreach(name, immArgAttrNames, |
| "StringLiteral(\"" # name # "\")"), ", ") # "}"; |
| let llvmBuilder = [{ |
| auto *inst = LLVM::detail::createIntrinsicCall( |
| builder, moduleTranslation, &opInst, llvm::Intrinsic::}] # !interleave([ |
| enumName, "" # numResults, overloadedResultsCpp, overloadedOperandsCpp, |
| immArgPositionsCpp, immArgAttrNamesCpp], ",") # [{); |
| (void) inst; |
| }] # !if(!gt(requiresAccessGroup, 0), setAccessGroupsMetadataCode, "") |
| # !if(!gt(requiresAliasAnalysis, 0), setAliasAnalysisMetadataCode, "") |
| # !if(!gt(numResults, 0), "$res = inst;", ""); |
| |
| string mlirBuilder = [{ |
| SmallVector<Value> mlirOperands; |
| SmallVector<NamedAttribute> mlirAttrs; |
| if (failed(moduleImport.convertIntrinsicArguments( |
| llvmOperands, |
| }] # immArgPositionsCpp # [{, |
| }] # immArgAttrNamesCpp # [{, |
| mlirOperands, |
| mlirAttrs)) |
| ) { |
| return failure(); |
| } |
| SmallVector<Type> resultTypes = |
| }] # !if(!gt(numResults, 0), "{$_resultType};", "{};") # [{ |
| auto op = $_builder.create<$_qualCppClassName>( |
| $_location, resultTypes, mlirOperands, mlirAttrs); |
| }] # !if(!gt(requiresFastmath, 0), |
| "moduleImport.setFastmathFlagsAttr(inst, op);", "") |
| # !if(!gt(numResults, 0), "$res = op;", "$_op = op;"); |
| } |
| |
| // Base class for LLVM intrinsic operations, should not be used directly. Places |
| // the intrinsic into the LLVM dialect and prefixes its name with "intr.". |
| class LLVM_IntrOp<string mnem, list<int> overloadedResults, |
| list<int> overloadedOperands, list<Trait> traits, |
| int numResults, bit requiresAccessGroup = 0, |
| bit requiresAliasAnalysis = 0, bit requiresFastmath = 0, |
| list<int> immArgPositions = [], |
| list<string> immArgAttrNames = []> |
| : LLVM_IntrOpBase<LLVM_Dialect, "intr." # mnem, !subst(".", "_", mnem), |
| overloadedResults, overloadedOperands, traits, |
| numResults, requiresAccessGroup, requiresAliasAnalysis, |
| requiresFastmath, immArgPositions, immArgAttrNames>; |
| |
| // Base class for LLVM intrinsic operations returning no results. Places the |
| // intrinsic into the LLVM dialect and prefixes its name with "intr.". |
| // |
| // Sample use: derive an entry from this class and populate the fields. |
| // |
| // def LLVM_Name : LLVM_ZeroResultIntrOp<"name", [0], [Pure]>, |
| // Arguments<(ins LLVM_Type, LLVM_Type)>; |
| // |
| // The mnemonic will be prefixed with "llvm.intr.", where the "llvm." part comes |
| // from the LLVM dialect. The overloadedOperands list contains the indices of |
| // the operands the type of which will be passed in the LLVM IR intrinsic |
| // builder. In the example above, the Op has two arguments, but only the first |
| // one (as indicated by `[0]`) is necessary to resolve the overloaded intrinsic. |
| // The Op has no results. |
| class LLVM_ZeroResultIntrOp<string mnem, list<int> overloadedOperands = [], |
| list<Trait> traits = [], |
| bit requiresAccessGroup = 0, |
| bit requiresAliasAnalysis = 0, |
| list<int> immArgPositions = [], |
| list<string> immArgAttrNames = []> |
| : LLVM_IntrOp<mnem, [], overloadedOperands, traits, /*numResults=*/0, |
| requiresAccessGroup, requiresAliasAnalysis, |
| /*requiresFastMath=*/0, immArgPositions, immArgAttrNames>; |
| |
| // Base class for LLVM intrinsic operations returning one result. Places the |
| // intrinsic into the LLVM dialect and prefixes its name with "intr.". This is |
| // similar to LLVM_ZeroResultIntrOp but allows one to define Ops returning one |
| // result, called "res". Additionally, the overloadedResults list should contain |
| // "0" if the result must be used to resolve overloaded intrinsics, or remain |
| // empty otherwise. |
| class LLVM_OneResultIntrOp<string mnem, list<int> overloadedResults = [], |
| list<int> overloadedOperands = [], |
| list<Trait> traits = [], |
| bit requiresFastmath = 0, |
| list<int> immArgPositions = [], |
| list<string> immArgAttrNames = []> |
| : LLVM_IntrOp<mnem, overloadedResults, overloadedOperands, traits, 1, |
| /*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0, |
| requiresFastmath, immArgPositions, immArgAttrNames>; |
| |
| def LLVM_OneResultOpBuilder : |
| OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), |
| [{ |
| if (resultType) $_state.addTypes(resultType); |
| $_state.addOperands(operands); |
| for (auto namedAttr : attributes) |
| $_state.addAttribute(namedAttr.getName(), namedAttr.getValue()); |
| }]>; |
| |
| def LLVM_ZeroResultOpBuilder : |
| OpBuilder<(ins "ValueRange":$operands, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), |
| [{ |
| $_state.addOperands(operands); |
| for (auto namedAttr : attributes) |
| $_state.addAttribute(namedAttr.getName(), namedAttr.getValue()); |
| }]>; |
| |
| // Compatibility builder that takes an instance of wrapped llvm::VoidType |
| // to indicate no result. |
| def LLVM_VoidResultTypeOpBuilder : |
| OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), |
| [{ |
| assert(isCompatibleType(resultType) && "result must be an LLVM type"); |
| assert(::llvm::isa<LLVMVoidType>(resultType) && |
| "for zero-result operands, only 'void' is accepted as result type"); |
| build($_builder, $_state, operands, attributes); |
| }]>; |
| |
| |
| // Opaque builder used for terminator operations that contain successors. |
| def LLVM_TerminatorPassthroughOpBuilder : |
| OpBuilder<(ins "ValueRange":$operands, "SuccessorRange":$destinations, |
| CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes), |
| [{ |
| $_state.addOperands(operands); |
| $_state.addSuccessors(destinations); |
| $_state.addAttributes(attributes); |
| }]>; |
| |
| |
| #endif // LLVMIR_OP_BASE |