//===-- 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 # "\")"), ", ") # "}";
string baseLlvmBuilder = [{
auto *inst = LLVM::detail::createIntrinsicCall(
builder, moduleTranslation, &opInst, llvm::Intrinsic::}] # !interleave([
enumName, "" # numResults, overloadedResultsCpp, overloadedOperandsCpp,
immArgPositionsCpp, immArgAttrNamesCpp], ",") # [{);
(void) inst;
}];
string baseLlvmBuilderCoda = !if(!gt(numResults, 0), "$res = inst;", "");
let llvmBuilder = baseLlvmBuilder # !if(!gt(requiresAccessGroup, 0), setAccessGroupsMetadataCode, "")
# !if(!gt(requiresAliasAnalysis, 0), setAliasAnalysisMetadataCode, "")
# baseLlvmBuilderCoda;
string baseMlirBuilder = [{
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);
}];
string baseMlirBuilderCoda = !if(!gt(numResults, 0), "$res = op;", "$_op = op;");
let mlirBuilder = baseMlirBuilder # !if(!gt(requiresFastmath, 0),
"moduleImport.setFastmathFlagsAttr(inst, op);", "")
# 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<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