//===-- 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" include "mlir/Interfaces/CallInterfaces.td" //===----------------------------------------------------------------------===// // LLVM dialect type constraints. //===----------------------------------------------------------------------===// // LLVM dialect type. def LLVM_Type : DialectType, "LLVM dialect-compatible type">; // Type constraint accepting LLVM metadata type. def LLVM_MetadataType : Type< CPred<"::llvm::isa<::mlir::LLVM::LLVMMetadataType>($_self)">, "LLVM metadata type">, BuildableType<"::mlir::LLVM::LLVMMetadataType::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($_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($_self)">, "LLVM pointer type", "::mlir::LLVM::LLVMPointerType">; // Pointer in a given address space. class LLVM_PointerInAddressSpace : 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($_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($_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<[CPred<"mlir::LLVM::isLoadableType($_self)">, 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]>, "LLVM-compatible non-aggregate type">; // Type constraint accepting any LLVM vector type. def LLVM_AnyVector : Type, "LLVM dialect-compatible vector type", "::mlir::VectorType">; // Type constraint accepting any LLVM fixed-length vector type. def LLVM_AnyFixedVector : Type, "LLVM dialect-compatible fixed-length vector type", "::mlir::VectorType">; // Type constraint accepting any LLVM scalable vector type. def LLVM_AnyScalableVector : Type, "LLVM dialect-compatible scalable vector type", "::mlir::VectorType">; // Type constraint accepting an LLVM vector type with an additional constraint // on the vector element type. class LLVM_VectorOf : Type< And<[LLVM_AnyVector.predicate, SubstLeaves< "$_self", "::llvm::cast<::mlir::VectorType>($_self).getElementType()", element.predicate>]>, "LLVM dialect-compatible vector of " # element.summary, "::mlir::VectorType">; // Type constraint accepting a constrained type, or a vector of such types. class LLVM_ScalarOrVectorOf : AnyTypeOf<[element, LLVM_VectorOf]>; // 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 traits = []> : Op { // 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 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 setInvariantGroupCode = [{ if ($invariantGroup) { llvm::MDNode *metadata = llvm::MDNode::get(inst->getContext(), {}); inst->setMetadata(llvm::LLVMContext::MD_invariant_group, 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 traits = []> : LLVM_OpBase; // 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 traits = []> : LLVM_Op, DeclareOpInterfaceMethods], traits)>, LLVM_MemOpPatterns { dag aliasAttrs = (ins OptionalAttr:$access_groups, OptionalAttr:$alias_scopes, OptionalAttr:$noalias_scopes, OptionalAttr:$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 flags "requiresAccessGroup", "requiresAliasAnalysis", // "requiresFastmath", and "requiresArgAndResultAttrs" indicate which // interfaces the intrinsic implements. When a flag is set, the "baseArgs" // list includes the arguments required by the corresponding interface. // Derived intrinsics must append "baseArgs" to their argument list if they // enable any of these 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 overloadedResults, list overloadedOperands, list traits, int numResults, bit requiresAccessGroup = 0, bit requiresAliasAnalysis = 0, bit requiresFastmath = 0, bit requiresArgAndResultAttrs = 0, bit requiresOpBundles = 0, list immArgPositions = [], list immArgAttrNames = []> : LLVM_OpBase], []), !if(!gt(requiresAliasAnalysis, 0), [DeclareOpInterfaceMethods], []), !if(!gt(requiresFastmath, 0), [DeclareOpInterfaceMethods], []), !if(!gt(requiresArgAndResultAttrs, 0), [DeclareOpInterfaceMethods], []), traits)>, LLVM_MemOpPatterns, Results { dag baseArgs = !con( !if(!gt(requiresAccessGroup, 0), (ins OptionalAttr:$access_groups), (ins )), !if(!gt(requiresAliasAnalysis, 0), (ins OptionalAttr:$alias_scopes, OptionalAttr:$noalias_scopes, OptionalAttr:$tbaa), (ins )), !if(!gt(requiresArgAndResultAttrs, 0), (ins OptionalAttr:$arg_attrs, OptionalAttr:$res_attrs), (ins )), !if(!gt(requiresOpBundles, 0), (ins VariadicOfVariadic:$op_bundle_operands, DenseI32ArrayAttr:$op_bundle_sizes, OptionalAttr:$op_bundle_tags), (ins ))); string llvmEnumName = enumName; string overloadedResultsCpp = "{" # !interleave(overloadedResults, ", ") # "}"; string overloadedOperandsCpp = "{" # !interleave(overloadedOperands, ", ") # "}"; string immArgPositionsCpp = "{" # !interleave(immArgPositions, ", ") # "}"; string immArgAttrNamesCpp = "{" # !interleave(!foreach(name, immArgAttrNames, "StringLiteral(\"" # name # "\")"), ", ") # "}"; string baseLlvmBuilder = [{ auto *inst = LLVM::detail::createIntrinsicCall( builder, moduleTranslation, &opInst, llvm::Intrinsic::}] # !interleave([ enumName, "" # numResults, overloadedResultsCpp, overloadedOperandsCpp, immArgPositionsCpp, immArgAttrNamesCpp], ",") # [{); (void) inst; }]; string baseLlvmBuilderArgAndResultAttrs = [{ if (failed(moduleTranslation.convertArgAndResultAttrs( op, inst, }] # immArgPositionsCpp # [{))) { return failure(); } }]; string baseLlvmBuilderCoda = !if(!gt(numResults, 0), "$res = inst;", ""); let llvmBuilder = baseLlvmBuilder # !if(!gt(requiresAccessGroup, 0), setAccessGroupsMetadataCode, "") # !if(!gt(requiresAliasAnalysis, 0), setAliasAnalysisMetadataCode, "") # !if(!gt(requiresArgAndResultAttrs, 0), baseLlvmBuilderArgAndResultAttrs, "") # baseLlvmBuilderCoda; string baseMlirBuilder = [{ SmallVector mlirOperands; SmallVector mlirAttrs; if (failed(moduleImport.convertIntrinsicArguments( llvmOperands, llvmOpBundles, }] # !if(!gt(requiresOpBundles, 0), "true", "false") # [{, }] # immArgPositionsCpp # [{, }] # immArgAttrNamesCpp # [{, mlirOperands, mlirAttrs))) { return failure(); } SmallVector resultTypes = }] # !if(!gt(numResults, 0), "{$_resultType};", "{};") # [{ auto op = $_qualCppClassName::create($_builder, $_location, resultTypes, mlirOperands, mlirAttrs); }]; string baseMlirBuilderArgAndResultAttrs = [{ moduleImport.convertArgAndResultAttrs( inst, op, }] # immArgPositionsCpp # [{); }]; string baseMlirBuilderCoda = !if(!gt(numResults, 0), "$res = op;", "$_op = op;"); let mlirBuilder = baseMlirBuilder # !if(!gt(requiresFastmath, 0), "moduleImport.setFastmathFlagsAttr(inst, op);", "") # !if(!gt(requiresArgAndResultAttrs, 0), baseMlirBuilderArgAndResultAttrs, "") # baseMlirBuilderCoda; // Code for handling a `range` attribute that holds the constant range of the // intrinsic's result (if one is specified at the call site). This is intended // for GPU IDs and other calls where range() is meaningful. It expects // an optional LLVM_ConstantRangeAttr named `range` to be present on the // operation. These are included to abstract out common code in several // dialects. string setRangeRetAttrCode = [{ if ($range) { inst->addRangeRetAttr(::llvm::ConstantRange( $range->getLower(), $range->getUpper())); } }]; string importRangeRetAttrCode = [{ // Note: we don't want to look in to the declaration here. auto rangeAttr = inst->getAttributes().getRetAttr(::llvm::Attribute::Range); if (rangeAttr.isValid()) { const ::llvm::ConstantRange& value = rangeAttr.getValueAsConstantRange(); op.setRangeAttr(::mlir::LLVM::ConstantRangeAttr::get($_builder.getContext(), value.getLower(), value.getUpper())); } }]; } // 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 overloadedResults, list overloadedOperands, list traits, int numResults, bit requiresAccessGroup = 0, bit requiresAliasAnalysis = 0, bit requiresFastmath = 0, bit requiresArgAndResultAttrs = 0, bit requiresOpBundles = 0, list immArgPositions = [], list immArgAttrNames = []> : LLVM_IntrOpBase; // 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 overloadedOperands = [], list traits = [], bit requiresAccessGroup = 0, bit requiresAliasAnalysis = 0, bit requiresArgAndResultAttrs = 0, bit requiresOpBundles = 0, list immArgPositions = [], list immArgAttrNames = []> : LLVM_IntrOp; // 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 overloadedResults = [], list overloadedOperands = [], list traits = [], bit requiresFastmath = 0, bit requiresArgAndResultAttrs = 0, list immArgPositions = [], list immArgAttrNames = []> : LLVM_IntrOp; // Base class for LLVM intrinsic operations returning two results. 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 two // results. Additionally, the overloadedResults list should contain "0", "1" // if the result must be used to resolve overloaded intrinsics, or remain // empty otherwise. class LLVM_TwoResultIntrOp overloadedResults = [], list overloadedOperands = [], list traits = [], bit requiresFastmath = 0, list immArgPositions = [], list immArgAttrNames = []> : LLVM_IntrOp; def LLVM_OneResultOpBuilder : OpBuilder<(ins "Type":$resultType, "ValueRange":$operands, CArg<"ArrayRef", "{}">:$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", "{}">:$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", "{}">:$attributes), [{ assert(isCompatibleType(resultType) && "result must be an LLVM type"); assert(::llvm::isa(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", "{}">:$attributes), [{ $_state.addOperands(operands); $_state.addSuccessors(destinations); $_state.addAttributes(attributes); }]>; #endif // LLVMIR_OP_BASE