blob: 28526f1a1560ce9346baae8456752716e4b909cc [file] [log] [blame]
#ifndef LLVM_INTRINSIC_OPS
#define LLVM_INTRINSIC_OPS
include "mlir/IR/OpBase.td"
include "mlir/Dialect/LLVMIR/LLVMAttrDefs.td"
include "mlir/Dialect/LLVMIR/LLVMEnums.td"
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/Interfaces/MemorySlotInterfaces.td"
// Operations that correspond to LLVM intrinsics. With MLIR operation set being
// extendable, there is no reason to introduce a hard boundary between "core"
// operations and intrinsics. However, we systematically prefix them with
// "intr." to avoid potential name clashes.
class LLVM_UnaryIntrOpBase<string func, Type element,
list<Trait> traits = [], bit requiresFastmath = 0> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([Pure, SameOperandsAndResultType], traits),
requiresFastmath> {
dag commonArgs = (ins LLVM_ScalarOrVectorOf<element>:$in);
let assemblyFormat = "`(` operands `)` custom<LLVMOpAttrs>(attr-dict) `:` "
"functional-type(operands, results)";
}
class LLVM_UnaryIntrOpI<string func, list<Trait> traits = []> :
LLVM_UnaryIntrOpBase<func, AnySignlessInteger, traits> {
let arguments = commonArgs;
}
class LLVM_UnaryIntrOpF<string func, list<Trait> traits = []> :
LLVM_UnaryIntrOpBase<func, LLVM_AnyFloat, traits, /*requiresFastmath=*/1> {
dag fmfArg = (
ins DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags);
let arguments = !con(commonArgs, fmfArg);
}
class LLVM_BinarySameArgsIntrOpBase<string func, Type element,
list<Trait> traits = [], bit requiresFastmath = 0> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([Pure, SameOperandsAndResultType], traits),
requiresFastmath> {
dag commonArgs = (ins LLVM_ScalarOrVectorOf<element>:$a,
LLVM_ScalarOrVectorOf<element>:$b);
let assemblyFormat = "`(` operands `)` custom<LLVMOpAttrs>(attr-dict) `:` "
"functional-type(operands, results)";
}
class LLVM_BinarySameArgsIntrOpI<string func, list<Trait> traits = []> :
LLVM_BinarySameArgsIntrOpBase<func, AnySignlessInteger, traits> {
let arguments = commonArgs;
}
class LLVM_BinarySameArgsIntrOpF<string func, list<Trait> traits = []> :
LLVM_BinarySameArgsIntrOpBase<func, LLVM_AnyFloat, traits,
/*requiresFastmath=*/1> {
dag fmfArg = (
ins DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags);
let arguments = !con(commonArgs, fmfArg);
}
class LLVM_TernarySameArgsIntrOpBase<string func, Type element,
list<Trait> traits = [], bit requiresFastmath = 0> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([Pure, SameOperandsAndResultType], traits),
requiresFastmath> {
dag commonArgs = (ins LLVM_ScalarOrVectorOf<element>:$a,
LLVM_ScalarOrVectorOf<element>:$b,
LLVM_ScalarOrVectorOf<element>:$c);
let assemblyFormat = "`(` operands `)` custom<LLVMOpAttrs>(attr-dict) `:` "
"functional-type(operands, results)";
}
class LLVM_TernarySameArgsIntrOpI<string func, list<Trait> traits = []> :
LLVM_TernarySameArgsIntrOpBase<func, AnySignlessInteger, traits> {
let arguments = commonArgs;
}
class LLVM_TernarySameArgsIntrOpF<string func, list<Trait> traits = []> :
LLVM_TernarySameArgsIntrOpBase<func, LLVM_AnyFloat, traits,
/*requiresFastmath=*/1> {
dag fmfArg = (
ins DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags);
let arguments = !con(commonArgs, fmfArg);
}
class LLVM_CountZerosIntrOp<string func, list<Trait> traits = []> :
LLVM_OneResultIntrOp<func, [], [0],
!listconcat([Pure], traits),
/*requiresFastmath=*/0,
/*immArgPositions=*/[1], /*immArgAttrNames=*/["is_zero_poison"]> {
let arguments = (ins LLVM_ScalarOrVectorOf<AnySignlessInteger>:$in,
I1Attr:$is_zero_poison);
}
def LLVM_AbsOp : LLVM_OneResultIntrOp<"abs", [], [0], [Pure],
/*requiresFastmath=*/0,
/*immArgPositions=*/[1], /*immArgAttrNames=*/["is_int_min_poison"]> {
let arguments = (ins LLVM_ScalarOrVectorOf<AnySignlessInteger>:$in,
I1Attr:$is_int_min_poison);
}
def LLVM_IsFPClass : LLVM_OneResultIntrOp<"is.fpclass", [], [0], [Pure],
/*requiresFastmath=*/0,
/*immArgPositions=*/[1], /*immArgAttrNames=*/["bit"]> {
let arguments = (ins LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$in, I32Attr:$bit);
}
def LLVM_CopySignOp : LLVM_BinarySameArgsIntrOpF<"copysign">;
def LLVM_CosOp : LLVM_UnaryIntrOpF<"cos">;
def LLVM_ExpOp : LLVM_UnaryIntrOpF<"exp">;
def LLVM_Exp2Op : LLVM_UnaryIntrOpF<"exp2">;
def LLVM_FAbsOp : LLVM_UnaryIntrOpF<"fabs">;
def LLVM_FCeilOp : LLVM_UnaryIntrOpF<"ceil">;
def LLVM_FFloorOp : LLVM_UnaryIntrOpF<"floor">;
def LLVM_FMAOp : LLVM_TernarySameArgsIntrOpF<"fma">;
def LLVM_FMulAddOp : LLVM_TernarySameArgsIntrOpF<"fmuladd">;
def LLVM_Log10Op : LLVM_UnaryIntrOpF<"log10">;
def LLVM_Log2Op : LLVM_UnaryIntrOpF<"log2">;
def LLVM_LogOp : LLVM_UnaryIntrOpF<"log">;
def LLVM_Prefetch : LLVM_ZeroResultIntrOp<"prefetch", [0],
/*traits=*/[], /*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*immArgPositions=*/[1, 2, 3], /*immArgAttrNames=*/["rw", "hint", "cache"]
> {
let arguments = (ins LLVM_AnyPointer:$addr, I32Attr:$rw, I32Attr:$hint, I32Attr:$cache);
}
def LLVM_SinOp : LLVM_UnaryIntrOpF<"sin">;
def LLVM_RoundEvenOp : LLVM_UnaryIntrOpF<"roundeven">;
def LLVM_RoundOp : LLVM_UnaryIntrOpF<"round">;
def LLVM_FTruncOp : LLVM_UnaryIntrOpF<"trunc">;
def LLVM_SqrtOp : LLVM_UnaryIntrOpF<"sqrt">;
def LLVM_PowOp : LLVM_BinarySameArgsIntrOpF<"pow">;
def LLVM_PowIOp : LLVM_OneResultIntrOp<"powi", [], [0,1],
[Pure], /*requiresFastmath=*/1> {
let arguments =
(ins LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$val,
AnySignlessInteger:$power,
DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags);
let assemblyFormat = "`(` operands `)` custom<LLVMOpAttrs>(attr-dict) `:` "
"functional-type(operands, results)";
}
def LLVM_RintOp : LLVM_UnaryIntrOpF<"rint">;
def LLVM_NearbyintOp : LLVM_UnaryIntrOpF<"nearbyint">;
class LLVM_IntRoundIntrOpBase<string func> :
LLVM_OneResultIntrOp<func, [0], [0], [Pure]> {
let arguments = (ins LLVM_AnyFloat:$val);
let assemblyFormat = "`(` operands `)` custom<LLVMOpAttrs>(attr-dict) `:` "
"functional-type(operands, results)";
}
def LLVM_LroundOp : LLVM_IntRoundIntrOpBase<"lround">;
def LLVM_LlroundOp : LLVM_IntRoundIntrOpBase<"llround">;
def LLVM_LrintOp : LLVM_IntRoundIntrOpBase<"lrint">;
def LLVM_LlrintOp : LLVM_IntRoundIntrOpBase<"llrint">;
def LLVM_BitReverseOp : LLVM_UnaryIntrOpI<"bitreverse">;
def LLVM_ByteSwapOp : LLVM_UnaryIntrOpI<"bswap">;
def LLVM_CountLeadingZerosOp : LLVM_CountZerosIntrOp<"ctlz">;
def LLVM_CountTrailingZerosOp : LLVM_CountZerosIntrOp<"cttz">;
def LLVM_CtPopOp : LLVM_UnaryIntrOpI<"ctpop">;
def LLVM_FshlOp : LLVM_TernarySameArgsIntrOpI<"fshl">;
def LLVM_FshrOp : LLVM_TernarySameArgsIntrOpI<"fshr">;
def LLVM_MaxNumOp : LLVM_BinarySameArgsIntrOpF<"maxnum">;
def LLVM_MinNumOp : LLVM_BinarySameArgsIntrOpF<"minnum">;
def LLVM_MaximumOp : LLVM_BinarySameArgsIntrOpF<"maximum">;
def LLVM_MinimumOp : LLVM_BinarySameArgsIntrOpF<"minimum">;
def LLVM_SMaxOp : LLVM_BinarySameArgsIntrOpI<"smax">;
def LLVM_SMinOp : LLVM_BinarySameArgsIntrOpI<"smin">;
def LLVM_UMaxOp : LLVM_BinarySameArgsIntrOpI<"umax">;
def LLVM_UMinOp : LLVM_BinarySameArgsIntrOpI<"umin">;
class LLVM_MemcpyIntrOpBase<string name> :
LLVM_ZeroResultIntrOp<name, [0, 1, 2],
[DeclareOpInterfaceMethods<PromotableMemOpInterface>,
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*immArgPositions=*/[3], /*immArgAttrNames=*/["isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
Arg<LLVM_AnyPointer,"",[MemRead]>:$src,
AnySignlessInteger:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$src, "Value":$len,
"bool":$isVolatile), [{
build($_builder, $_state, dst, src, len,
$_builder.getBoolAttr(isVolatile));
}]>,
OpBuilder<(ins "Value":$dst, "Value":$src, "Value":$len,
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, src, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
}]>
];
}
def LLVM_MemcpyOp : LLVM_MemcpyIntrOpBase<"memcpy">;
def LLVM_MemmoveOp : LLVM_MemcpyIntrOpBase<"memmove">;
def LLVM_MemcpyInlineOp :
LLVM_ZeroResultIntrOp<"memcpy.inline", [0, 1, 2],
[DeclareOpInterfaceMethods<PromotableMemOpInterface>,
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*immArgPositions=*/[2, 3], /*immArgAttrNames=*/["len", "isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
Arg<LLVM_AnyPointer,"",[MemRead]>:$src,
APIntAttr:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$src, "IntegerAttr":$len,
"bool":$isVolatile), [{
build($_builder, $_state, dst, src, len,
$_builder.getBoolAttr(isVolatile));
}]>,
OpBuilder<(ins "Value":$dst, "Value":$src, "IntegerAttr":$len,
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, src, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
}]>
];
}
def LLVM_MemsetOp : LLVM_ZeroResultIntrOp<"memset", [0, 2],
[DeclareOpInterfaceMethods<PromotableMemOpInterface>,
DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
DeclareOpInterfaceMethods<SafeMemorySlotAccessOpInterface>],
/*requiresAccessGroup=*/1, /*requiresAliasAnalysis=*/1,
/*immArgPositions=*/[3], /*immArgAttrNames=*/["isVolatile"]> {
dag args = (ins Arg<LLVM_AnyPointer,"",[MemWrite]>:$dst,
I8:$val, AnySignlessInteger:$len, I1Attr:$isVolatile);
// Append the alias attributes defined by LLVM_IntrOpBase.
let arguments = !con(args, aliasAttrs);
let builders = [
OpBuilder<(ins "Value":$dst, "Value":$val, "Value":$len,
"bool":$isVolatile), [{
build($_builder, $_state, dst, val, len,
$_builder.getBoolAttr(isVolatile));
}]>,
OpBuilder<(ins "Value":$dst, "Value":$val, "Value":$len,
"IntegerAttr":$isVolatile), [{
build($_builder, $_state, dst, val, len, isVolatile,
/*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
/*noalias_scopes=*/nullptr, /*tbaa=*/nullptr);
}]>
];
}
def LLVM_NoAliasScopeDeclOp
: LLVM_ZeroResultIntrOp<"experimental.noalias.scope.decl"> {
let arguments = (ins LLVM_AliasScopeAttr:$scope);
string llvmBuilder = [{
// Wrap the scope argument into a list since the LLVM IR intrinsic takes
// a list containing exactly one scope rather than a scope itself.
llvm::MDNode* node = moduleTranslation.getOrCreateAliasScopes({$scope});
builder.CreateNoAliasScopeDeclaration(node);
}];
string mlirBuilder = [{
FailureOr<SmallVector<LLVM::AliasScopeAttr>> scopeAttrs =
moduleImport.matchAliasScopeAttrs(llvmOperands[0]);
// Drop the intrinsic if the alias scope translation fails since the scope
// is not used by an aliasing operation, such as a load or store, that is
// used to convert the alias scope metadata.
if (failed(scopeAttrs))
return success();
if (scopeAttrs->size() != 1)
return failure();
$_op = $_builder.create<LLVM::NoAliasScopeDeclOp>(
$_location, (*scopeAttrs)[0]);
}];
let assemblyFormat = "$scope attr-dict";
}
//
// Memory marker intrinsics.
//
/// Base operation for lifetime markers. The LLVM intrinsics require the size
/// operand to be an immediate. In MLIR it is encoded as an attribute.
class LLVM_LifetimeBaseOp<string opName> : LLVM_ZeroResultIntrOp<opName, [1],
[DeclareOpInterfaceMethods<PromotableOpInterface>],
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*immArgPositions=*/[0], /*immArgAttrNames=*/["size"]> {
let arguments = (ins I64Attr:$size, LLVM_AnyPointer:$ptr);
let assemblyFormat = "$size `,` $ptr attr-dict `:` qualified(type($ptr))";
}
def LLVM_LifetimeStartOp : LLVM_LifetimeBaseOp<"lifetime.start">;
def LLVM_LifetimeEndOp : LLVM_LifetimeBaseOp<"lifetime.end">;
def LLVM_InvariantStartOp : LLVM_OneResultIntrOp<"invariant.start", [], [1],
[DeclareOpInterfaceMethods<PromotableOpInterface>],
/*requiresFastmath=*/0, /*immArgPositions=*/[0],
/*immArgAttrNames=*/["size"]> {
let arguments = (ins I64Attr:$size, LLVM_AnyPointer:$ptr);
let results = (outs LLVM_DefaultPointer:$res);
let assemblyFormat = "$size `,` $ptr attr-dict `:` qualified(type($ptr))";
}
def LLVM_InvariantEndOp : LLVM_ZeroResultIntrOp<"invariant.end", [2],
[DeclareOpInterfaceMethods<PromotableOpInterface>],
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*immArgPositions=*/[1], /*immArgAttrNames=*/["size"]> {
let arguments = (ins LLVM_DefaultPointer:$start,
I64Attr:$size,
LLVM_AnyPointer:$ptr);
let assemblyFormat = "$start `,` $size `,` $ptr attr-dict `:` "
"qualified(type($ptr))";
}
// Constrained Floating-Point Intrinsics.
class LLVM_ConstrainedIntr<string mnem, int numArgs,
bit overloadedResult, list<int> overloadedOperands,
bit hasRoundingMode>
: LLVM_OneResultIntrOp<"experimental.constrained." # mnem,
/*overloadedResults=*/
!cond(!gt(overloadedResult, 0) : [0],
true : []),
overloadedOperands,
/*traits=*/[Pure, DeclareOpInterfaceMethods<FPExceptionBehaviorOpInterface>]
# !cond(
!gt(hasRoundingMode, 0) : [DeclareOpInterfaceMethods<RoundingModeOpInterface>],
true : []),
/*requiresFastmath=*/0,
/*immArgPositions=*/[],
/*immArgAttrNames=*/[]> {
dag regularArgs = !dag(ins, !listsplat(LLVM_Type, numArgs), !foreach(i, !range(numArgs), "arg_" #i));
dag attrArgs = !con(!cond(!gt(hasRoundingMode, 0) : (ins ValidRoundingModeAttr:$roundingmode),
true : (ins)),
(ins FPExceptionBehaviorAttr:$fpExceptionBehavior));
let arguments = !con(regularArgs, attrArgs);
let llvmBuilder = [{
SmallVector<llvm::Value *> args =
moduleTranslation.lookupValues(opInst.getOperands());
SmallVector<llvm::Type *> overloadedTypes; }] #
!cond(!gt(overloadedResult, 0) : [{
// Take into account overloaded result type.
overloadedTypes.push_back($_resultType); }],
// No overloaded result type.
true : "") # [{
llvm::transform(ArrayRef<unsigned>}] # overloadedOperandsCpp # [{,
std::back_inserter(overloadedTypes),
[&args](unsigned index) { return args[index]->getType(); });
llvm::Module *module = builder.GetInsertBlock()->getModule();
llvm::Function *callee =
llvm::Intrinsic::getDeclaration(module,
llvm::Intrinsic::experimental_constrained_}] #
mnem # [{, overloadedTypes); }] #
!cond(!gt(hasRoundingMode, 0) : [{
// Get rounding mode using interface.
llvm::RoundingMode rounding =
moduleTranslation.translateRoundingMode($roundingmode); }],
true : [{
// No rounding mode.
std::optional<llvm::RoundingMode> rounding; }]) # [{
llvm::fp::ExceptionBehavior except =
moduleTranslation.translateFPExceptionBehavior($fpExceptionBehavior);
$res = builder.CreateConstrainedFPCall(callee, args, "", rounding, except);
}];
let mlirBuilder = [{
SmallVector<Value> mlirOperands;
SmallVector<NamedAttribute> mlirAttrs;
if (failed(moduleImport.convertIntrinsicArguments(
llvmOperands.take_front( }] # numArgs # [{),
{}, {}, mlirOperands, mlirAttrs))) {
return failure();
}
FPExceptionBehaviorAttr fpExceptionBehaviorAttr =
$_fpExceptionBehavior_attr($fpExceptionBehavior);
mlirAttrs.push_back(
$_builder.getNamedAttr(
$_qualCppClassName::getFPExceptionBehaviorAttrName(),
fpExceptionBehaviorAttr)); }] #
!cond(!gt(hasRoundingMode, 0) : [{
RoundingModeAttr roundingModeAttr = $_roundingMode_attr($roundingmode);
mlirAttrs.push_back(
$_builder.getNamedAttr($_qualCppClassName::getRoundingModeAttrName(),
roundingModeAttr));
}], true : "") # [{
$res = $_builder.create<$_qualCppClassName>($_location,
$_resultType, mlirOperands, mlirAttrs);
}];
}
def LLVM_ConstrainedFPTruncIntr
: LLVM_ConstrainedIntr<"fptrunc", /*numArgs=*/1,
/*overloadedResult=*/1, /*overloadedOperands=*/[0],
/*hasRoundingMode=*/1> {
let assemblyFormat = [{
$arg_0 $roundingmode $fpExceptionBehavior attr-dict `:` type($arg_0) `to` type(results)
}];
}
// Intrinsics with multiple returns.
class LLVM_ArithWithOverflowOp<string mnem>
: LLVM_IntrOp<mnem, [0], [], [Pure, SameOperandsElementType], 2>,
Arguments<(ins LLVM_ScalarOrVectorOf<AnySignlessInteger>,
LLVM_ScalarOrVectorOf<AnySignlessInteger>)>;
def LLVM_SAddWithOverflowOp : LLVM_ArithWithOverflowOp<"sadd.with.overflow">;
def LLVM_UAddWithOverflowOp : LLVM_ArithWithOverflowOp<"uadd.with.overflow">;
def LLVM_SSubWithOverflowOp : LLVM_ArithWithOverflowOp<"ssub.with.overflow">;
def LLVM_USubWithOverflowOp : LLVM_ArithWithOverflowOp<"usub.with.overflow">;
def LLVM_SMulWithOverflowOp : LLVM_ArithWithOverflowOp<"smul.with.overflow">;
def LLVM_UMulWithOverflowOp : LLVM_ArithWithOverflowOp<"umul.with.overflow">;
//
// Saturation Arithmetic Intrinsics.
//
def LLVM_SAddSat : LLVM_BinarySameArgsIntrOpI<"sadd.sat">;
def LLVM_UAddSat : LLVM_BinarySameArgsIntrOpI<"uadd.sat">;
def LLVM_SSubSat : LLVM_BinarySameArgsIntrOpI<"ssub.sat">;
def LLVM_USubSat : LLVM_BinarySameArgsIntrOpI<"usub.sat">;
def LLVM_SSHLSat : LLVM_BinarySameArgsIntrOpI<"sshl.sat">;
def LLVM_USHLSat : LLVM_BinarySameArgsIntrOpI<"ushl.sat">;
//
// Optimization hint intrinsics.
//
def LLVM_AssumeOp
: LLVM_ZeroResultIntrOp<"assume", []>, Arguments<(ins I1:$cond)>;
def LLVM_SSACopyOp : LLVM_OneResultIntrOp<"ssa.copy", [], [0],
[Pure, SameOperandsAndResultType]> {
let arguments = (ins AnyType:$operand);
let assemblyFormat = "$operand attr-dict `:` type($operand)";
}
def LLVM_IsConstantOp : LLVM_IntrOp<"is.constant", [], [0], [Pure], 1> {
let arguments = (ins LLVM_Type:$val);
let results = (outs I1:$res);
}
def LLVM_ExpectOp
: LLVM_OneResultIntrOp<"expect", [], [0],
[Pure, SameOperandsAndResultType]> {
let arguments = (ins AnySignlessInteger:$val,
AnySignlessInteger:$expected);
let assemblyFormat = "$val `,` $expected attr-dict `:` type($val)";
}
def LLVM_ExpectWithProbabilityOp
: LLVM_OneResultIntrOp<"expect.with.probability", [], [0],
[Pure, AllTypesMatch<["val", "expected", "res"]>],
/*requiresFastmath=*/0,
/*immArgPositions=*/[2], /*immArgAttrNames=*/["prob"]> {
let arguments = (ins AnySignlessInteger:$val,
AnySignlessInteger:$expected,
F64Attr:$prob);
let assemblyFormat = "$val `,` $expected `,` $prob attr-dict `:` type($val)";
}
def LLVM_ThreadlocalAddressOp : LLVM_OneResultIntrOp<"threadlocal.address", [],
[0], [Pure]> {
let arguments = (ins LLVM_AnyPointer:$global);
}
//
// Coroutine intrinsics.
//
def LLVM_CoroIdOp : LLVM_IntrOp<"coro.id", [], [], [], 1> {
let arguments = (ins I32:$align,
LLVM_AnyPointer:$promise,
LLVM_AnyPointer:$coroaddr,
LLVM_AnyPointer:$fnaddrs);
let assemblyFormat = "$align `,` $promise `,` $coroaddr `,` $fnaddrs"
" attr-dict `:` functional-type(operands, results)";
}
def LLVM_CoroBeginOp : LLVM_IntrOp<"coro.begin", [], [], [], 1> {
let arguments = (ins LLVM_TokenType:$token,
LLVM_AnyPointer:$mem);
let assemblyFormat = "$token `,` $mem attr-dict `:` functional-type(operands, results)";
}
def LLVM_CoroSizeOp : LLVM_IntrOp<"coro.size", [0], [], [], 1> {
let assemblyFormat = "attr-dict `:` type($res)";
}
def LLVM_CoroAlignOp : LLVM_IntrOp<"coro.align", [0], [], [], 1> {
let assemblyFormat = "attr-dict `:` type($res)";
}
def LLVM_CoroSaveOp : LLVM_IntrOp<"coro.save", [], [], [], 1> {
let arguments = (ins LLVM_AnyPointer:$handle);
let assemblyFormat = "$handle attr-dict `:` functional-type(operands, results)";
}
def LLVM_CoroSuspendOp : LLVM_IntrOp<"coro.suspend", [], [], [], 1> {
let arguments = (ins LLVM_TokenType:$save,
I1:$final);
let assemblyFormat = "$save `,` $final attr-dict `:` type($res)";
}
def LLVM_CoroEndOp : LLVM_IntrOp<"coro.end", [], [], [], 1> {
let arguments = (ins LLVM_AnyPointer:$handle,
I1:$unwind,
LLVM_TokenType:$retvals);
let assemblyFormat = "$handle `,` $unwind `,` $retvals attr-dict `:` functional-type(operands, results)";
}
def LLVM_CoroFreeOp : LLVM_IntrOp<"coro.free", [], [], [], 1> {
let arguments = (ins LLVM_TokenType:$id,
LLVM_AnyPointer:$handle);
let assemblyFormat = "$id `,` $handle attr-dict `:` functional-type(operands, results)";
}
def LLVM_CoroResumeOp : LLVM_IntrOp<"coro.resume", [], [], [], 0> {
let arguments = (ins LLVM_AnyPointer:$handle);
let assemblyFormat = "$handle attr-dict `:` qualified(type($handle))";
}
def LLVM_CoroPromiseOp : LLVM_IntrOp<"coro.promise", [], [], [], 1> {
let arguments = (ins LLVM_AnyPointer:$handle,
I32:$align,
I1:$from);
let results = (outs LLVM_AnyPointer:$res);
let assemblyFormat = "$handle `,` $align `,` $from attr-dict `:` functional-type(operands, results)";
}
//
// Debug function intrinsics.
//
class LLVM_DbgIntrOp<string name, string argName, list<Trait> traits = []>
: LLVM_IntrOp<name, [], [], traits, 0> {
let llvmBuilder = [{
// Debug intrinsics without debug locations are invalid.
if(!builder.getCurrentDebugLocation())
return success();
llvm::Module *module = builder.GetInsertBlock()->getModule();
llvm::LLVMContext &ctx = module->getContext();
llvm::Function *fn =
llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::}]
# !subst(".", "_", name) # [{);
builder.CreateCall(fn, {
llvm::MetadataAsValue::get(ctx,
llvm::ValueAsMetadata::get(moduleTranslation.lookupValue(opInst.getOperand(0)))),
llvm::MetadataAsValue::get(ctx, moduleTranslation.translateDebugInfo($varInfo)),
llvm::MetadataAsValue::get(ctx, moduleTranslation.translateExpression($locationExpr)),
});
}];
let mlirBuilder = [{
// Add debug intrindic to the list of intrinsics that need to be converted once the
// full function was converted.
moduleImport.addDebugIntrinsic(inst);
return success();
}];
let assemblyFormat = [{
qualified($varInfo) (qualified($locationExpr)^)? `=` $}] # argName #
[{ `:` qualified(type($}] # argName # [{)) attr-dict
}];
}
def LLVM_DbgDeclareOp : LLVM_DbgIntrOp<"dbg.declare", "addr",
[DeclareOpInterfaceMethods<PromotableOpInterface>]> {
let summary = "Describes how the address relates to a source language variable.";
let arguments = (ins
LLVM_AnyPointer:$addr,
LLVM_DILocalVariableAttr:$varInfo,
DefaultValuedAttr<LLVM_DIExpressionAttr, "{}">:$locationExpr
);
}
def LLVM_DbgValueOp : LLVM_DbgIntrOp<"dbg.value", "value",
[DeclareOpInterfaceMethods<PromotableOpInterface>]> {
let summary = "Describes how the value relates to a source language variable.";
let arguments = (ins
LLVM_Type:$value,
LLVM_DILocalVariableAttr:$varInfo,
DefaultValuedAttr<LLVM_DIExpressionAttr, "{}">:$locationExpr
);
}
def LLVM_DbgLabelOp : LLVM_IntrOp<"dbg.label", [], [], [], 0> {
let summary = "Relates the program to a debug information label.";
let arguments = (ins LLVM_DILabelAttr:$label);
let llvmBuilder = [{
// Debug intrinsics without debug locations are invalid.
if(!builder.getCurrentDebugLocation())
return success();
llvm::Module *module = builder.GetInsertBlock()->getModule();
llvm::LLVMContext &ctx = module->getContext();
llvm::Function *fn =
llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::dbg_label);
builder.CreateCall(fn, {
llvm::MetadataAsValue::get(ctx, moduleTranslation.translateDebugInfo($label))
});
}];
let mlirBuilder = [{
DILabelAttr labelAttr = $_label_attr($label);
// Drop the intrinsic if the label translation fails due to cylic metadata.
if (!labelAttr)
return success();
$_op = $_builder.create<$_qualCppClassName>($_location, labelAttr);
}];
let assemblyFormat = "$label attr-dict";
}
//
// Variadic function intrinsics.
//
def LLVM_VaStartOp : LLVM_ZeroResultIntrOp<"vastart", [0]>,
Arguments<(ins LLVM_AnyPointer:$arg_list)> {
let assemblyFormat = "$arg_list attr-dict `:` qualified(type($arg_list))";
let summary = "Initializes `arg_list` for subsequent variadic argument extractions.";
}
def LLVM_VaCopyOp : LLVM_ZeroResultIntrOp<"vacopy", [0]>,
Arguments<(ins LLVM_AnyPointer:$dest_list, LLVM_AnyPointer:$src_list)> {
let assemblyFormat = "$src_list `to` $dest_list attr-dict `:` type(operands)";
let summary = "Copies the current argument position from `src_list` to `dest_list`.";
}
def LLVM_VaEndOp : LLVM_ZeroResultIntrOp<"vaend", [0]>,
Arguments<(ins LLVM_AnyPointer:$arg_list)> {
let assemblyFormat = "$arg_list attr-dict `:` qualified(type($arg_list))";
let summary = "Destroys `arg_list`, which has been initialized by `intr.vastart` or `intr.vacopy`.";
}
//
// Exception handling intrinsics.
//
def LLVM_EhTypeidForOp : LLVM_OneResultIntrOp<"eh.typeid.for"> {
let arguments = (ins LLVM_AnyPointer:$type_info);
let assemblyFormat = "$type_info attr-dict `:` functional-type(operands, results)";
}
//
// Stack save/restore intrinsics.
//
def LLVM_StackSaveOp : LLVM_OneResultIntrOp<"stacksave", [0]> {
let assemblyFormat = "attr-dict `:` qualified(type($res))";
}
def LLVM_StackRestoreOp : LLVM_ZeroResultIntrOp<"stackrestore", [0]> {
let arguments = (ins LLVM_AnyPointer:$ptr);
let assemblyFormat = "$ptr attr-dict `:` qualified(type($ptr))";
}
//
// Vector Reductions.
//
// LLVM vector reduction over a single vector.
class LLVM_VecReductionBase<string mnem, Type element, bit requiresFastmath=0>
: LLVM_OneResultIntrOp<"vector.reduce." # mnem, [], [0],
[Pure, SameOperandsAndResultElementType],
requiresFastmath> {
dag commonArgs = (ins LLVM_VectorOf<element>:$in);
}
class LLVM_VecReductionF<string mnem>
: LLVM_VecReductionBase<mnem, AnyFloat, /*requiresFastmath=*/1> {
dag fmfArg = (
ins DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags);
let arguments = !con(commonArgs, fmfArg);
let assemblyFormat = "`(` operands `)` custom<LLVMOpAttrs>(attr-dict) `:` "
"functional-type(operands, results)";
}
class LLVM_VecReductionI<string mnem>
: LLVM_VecReductionBase<mnem, AnySignlessInteger> {
let arguments = commonArgs;
}
// LLVM vector reduction over a single vector, with an initial value,
// and with permission to reassociate the reduction operations.
class LLVM_VecReductionAccBase<string mnem, Type element>
: LLVM_OneResultIntrOp</*mnem=*/"vector.reduce." # mnem,
/*overloadedResults=*/[],
/*overloadedOperands=*/[1],
/*traits=*/[Pure, SameOperandsAndResultElementType],
/*equiresFastmath=*/1>,
Arguments<(ins element:$start_value,
LLVM_VectorOf<element>:$input,
DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags)>;
class LLVM_VecReductionAccF<string mnem>
: LLVM_VecReductionAccBase<mnem, AnyFloat>;
def LLVM_vector_reduce_add : LLVM_VecReductionI<"add">;
def LLVM_vector_reduce_and : LLVM_VecReductionI<"and">;
def LLVM_vector_reduce_mul : LLVM_VecReductionI<"mul">;
def LLVM_vector_reduce_or : LLVM_VecReductionI<"or">;
def LLVM_vector_reduce_smax : LLVM_VecReductionI<"smax">;
def LLVM_vector_reduce_smin : LLVM_VecReductionI<"smin">;
def LLVM_vector_reduce_umax : LLVM_VecReductionI<"umax">;
def LLVM_vector_reduce_umin : LLVM_VecReductionI<"umin">;
def LLVM_vector_reduce_xor : LLVM_VecReductionI<"xor">;
def LLVM_vector_reduce_fmax : LLVM_VecReductionF<"fmax">;
def LLVM_vector_reduce_fmin : LLVM_VecReductionF<"fmin">;
def LLVM_vector_reduce_fmaximum : LLVM_VecReductionF<"fmaximum">;
def LLVM_vector_reduce_fminimum : LLVM_VecReductionF<"fminimum">;
def LLVM_vector_reduce_fadd : LLVM_VecReductionAccF<"fadd">;
def LLVM_vector_reduce_fmul : LLVM_VecReductionAccF<"fmul">;
//
// LLVM Matrix operations.
//
/// Create a column major, strided 2-D matrix load, as specified in the LLVM
/// MatrixBuilder.
/// data - Start address of the matrix read
/// rows - Number of rows in matrix (must be a constant)
/// isVolatile - True if the load operation is marked as volatile.
/// columns - Number of columns in matrix (must be a constant)
/// stride - Space between columns
def LLVM_MatrixColumnMajorLoadOp : LLVM_OneResultIntrOp<"matrix.column.major.load"> {
let arguments = (ins LLVM_AnyPointer:$data, AnySignlessInteger:$stride, I1Attr:$isVolatile,
I32Attr:$rows, I32Attr:$columns);
let results = (outs LLVM_AnyVector:$res);
let builders = [LLVM_OneResultOpBuilder];
let assemblyFormat = "$data `,` `<` `stride` `=` $stride `>` attr-dict"
"`:` type($res) `from` qualified(type($data)) `stride` type($stride)";
string llvmBuilder = [{
llvm::MatrixBuilder mb(builder);
const llvm::DataLayout &dl =
builder.GetInsertBlock()->getModule()->getDataLayout();
llvm::Type *ElemTy = moduleTranslation.convertType(
getVectorElementType(op.getType()));
llvm::Align align = dl.getABITypeAlign(ElemTy);
$res = mb.CreateColumnMajorLoad(
ElemTy, $data, align, $stride, $isVolatile, $rows,
$columns);
}];
string mlirBuilder = [{
$res = $_builder.create<LLVM::MatrixColumnMajorLoadOp>(
$_location, $_resultType, $data, $stride,
$_int_attr($isVolatile), $_int_attr($rows), $_int_attr($columns));
}];
}
/// Create a column major, strided 2-D matrix store, as specified in the LLVM
/// MatrixBuilder.
/// matrix - Matrix to store
/// ptr - Pointer to write back to
/// isVolatile - True if the load operation is marked as volatile.
/// rows - Number of rows in matrix (must be a constant)
/// columns - Number of columns in matrix (must be a constant)
/// stride - Space between columns
def LLVM_MatrixColumnMajorStoreOp : LLVM_ZeroResultIntrOp<"matrix.column.major.store"> {
let arguments = (ins LLVM_AnyVector:$matrix, LLVM_AnyPointer:$data,
AnySignlessInteger:$stride, I1Attr:$isVolatile, I32Attr:$rows,
I32Attr:$columns);
let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder];
let assemblyFormat = "$matrix `,` $data `,` `<` `stride` `=` $stride `>` "
"attr-dict`:` type($matrix) `to` qualified(type($data)) `stride` type($stride)";
string llvmBuilder = [{
llvm::MatrixBuilder mb(builder);
const llvm::DataLayout &dl =
builder.GetInsertBlock()->getModule()->getDataLayout();
Type elementType = getVectorElementType(op.getMatrix().getType());
llvm::Align align = dl.getABITypeAlign(
moduleTranslation.convertType(elementType));
mb.CreateColumnMajorStore(
$matrix, $data, align, $stride, $isVolatile,
$rows, $columns);
}];
string mlirBuilder = [{
$_op = $_builder.create<LLVM::MatrixColumnMajorStoreOp>(
$_location, $matrix, $data, $stride,
$_int_attr($isVolatile), $_int_attr($rows), $_int_attr($columns));
}];
}
/// Create a llvm.matrix.multiply call, multiplying 2-D matrices LHS and RHS, as
/// specified in the LLVM MatrixBuilder.
def LLVM_MatrixMultiplyOp : LLVM_OneResultIntrOp<"matrix.multiply"> {
let arguments = (ins LLVM_AnyVector:$lhs, LLVM_AnyVector:$rhs, I32Attr:$lhs_rows,
I32Attr:$lhs_columns, I32Attr:$rhs_columns);
let results = (outs LLVM_AnyVector:$res);
let builders = [LLVM_OneResultOpBuilder];
let assemblyFormat = "$lhs `,` $rhs attr-dict "
"`:` `(` type($lhs) `,` type($rhs) `)` `->` type($res)";
string llvmBuilder = [{
llvm::MatrixBuilder mb(builder);
$res = mb.CreateMatrixMultiply(
$lhs, $rhs, $lhs_rows, $lhs_columns,
$rhs_columns);
}];
string mlirBuilder = [{
$res = $_builder.create<LLVM::MatrixMultiplyOp>(
$_location, $_resultType, $lhs, $rhs,
$_int_attr($lhs_rows), $_int_attr($lhs_columns), $_int_attr($rhs_columns));
}];
}
/// Create a llvm.matrix.transpose call, transposing a `rows` x `columns` 2-D
/// `matrix`, as specified in the LLVM MatrixBuilder.
def LLVM_MatrixTransposeOp : LLVM_OneResultIntrOp<"matrix.transpose"> {
let arguments = (ins LLVM_AnyVector:$matrix, I32Attr:$rows, I32Attr:$columns);
let results = (outs LLVM_AnyVector:$res);
let builders = [LLVM_OneResultOpBuilder];
let assemblyFormat = "$matrix attr-dict `:` type($matrix) `into` type($res)";
string llvmBuilder = [{
llvm::MatrixBuilder mb(builder);
$res = mb.CreateMatrixTranspose(
$matrix, $rows, $columns);
}];
string mlirBuilder = [{
$res = $_builder.create<LLVM::MatrixTransposeOp>(
$_location, $_resultType, $matrix,
$_int_attr($rows), $_int_attr($columns));
}];
}
//
// LLVM masked operations.
//
/// Create a llvm.get.active.lane.mask to set a mask up to a given position.
def LLVM_GetActiveLaneMaskOp
: LLVM_OneResultIntrOp<"get.active.lane.mask", [0], [0], [Pure]> {
let arguments = (ins AnySignlessInteger:$base, AnySignlessInteger:$n);
let assemblyFormat = "$base `,` $n attr-dict `:` "
"type($base) `,` type($n) `to` type($res)";
}
/// Create a call to Masked Load intrinsic.
def LLVM_MaskedLoadOp : LLVM_OneResultIntrOp<"masked.load"> {
let arguments = (ins LLVM_AnyPointer:$data, LLVM_VectorOf<I1>:$mask,
Variadic<LLVM_AnyVector>:$pass_thru, I32Attr:$alignment);
let results = (outs LLVM_AnyVector:$res);
let assemblyFormat =
"operands attr-dict `:` functional-type(operands, results)";
string llvmBuilder = [{
$res = $pass_thru.empty() ? builder.CreateMaskedLoad(
$_resultType, $data, llvm::Align($alignment), $mask) :
builder.CreateMaskedLoad(
$_resultType, $data, llvm::Align($alignment), $mask, $pass_thru[0]);
}];
string mlirBuilder = [{
$res = $_builder.create<LLVM::MaskedLoadOp>($_location,
$_resultType, $data, $mask, $pass_thru, $_int_attr($alignment));
}];
list<int> llvmArgIndices = [0, 2, 3, 1];
}
/// Create a call to Masked Store intrinsic.
def LLVM_MaskedStoreOp : LLVM_ZeroResultIntrOp<"masked.store"> {
let arguments = (ins LLVM_AnyVector:$value, LLVM_AnyPointer:$data,
LLVM_VectorOf<I1>:$mask, I32Attr:$alignment);
let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder];
let assemblyFormat = "$value `,` $data `,` $mask attr-dict `:` "
"type($value) `,` type($mask) `into` qualified(type($data))";
string llvmBuilder = [{
builder.CreateMaskedStore(
$value, $data, llvm::Align($alignment), $mask);
}];
string mlirBuilder = [{
$_op = $_builder.create<LLVM::MaskedStoreOp>($_location,
$value, $data, $mask, $_int_attr($alignment));
}];
list<int> llvmArgIndices = [0, 1, 3, 2];
}
/// Create a call to Masked Gather intrinsic.
def LLVM_masked_gather : LLVM_OneResultIntrOp<"masked.gather"> {
let arguments = (ins LLVM_VectorOf<LLVM_AnyPointer>:$ptrs,
LLVM_VectorOf<I1>:$mask, Variadic<LLVM_AnyVector>:$pass_thru,
I32Attr:$alignment);
let results = (outs LLVM_AnyVector:$res);
let builders = [LLVM_OneResultOpBuilder];
let assemblyFormat =
"operands attr-dict `:` functional-type(operands, results)";
string llvmBuilder = [{
$res = $pass_thru.empty() ? builder.CreateMaskedGather(
$_resultType, $ptrs, llvm::Align($alignment), $mask) :
builder.CreateMaskedGather(
$_resultType, $ptrs, llvm::Align($alignment), $mask, $pass_thru[0]);
}];
string mlirBuilder = [{
$res = $_builder.create<LLVM::masked_gather>($_location,
$_resultType, $ptrs, $mask, $pass_thru, $_int_attr($alignment));
}];
list<int> llvmArgIndices = [0, 2, 3, 1];
}
/// Create a call to Masked Scatter intrinsic.
def LLVM_masked_scatter : LLVM_ZeroResultIntrOp<"masked.scatter"> {
let arguments = (ins LLVM_AnyVector:$value, LLVM_VectorOf<LLVM_AnyPointer>:$ptrs,
LLVM_VectorOf<I1>:$mask, I32Attr:$alignment);
let builders = [LLVM_VoidResultTypeOpBuilder, LLVM_ZeroResultOpBuilder];
let assemblyFormat = "$value `,` $ptrs `,` $mask attr-dict `:` "
"type($value) `,` type($mask) `into` type($ptrs)";
string llvmBuilder = [{
builder.CreateMaskedScatter(
$value, $ptrs, llvm::Align($alignment), $mask);
}];
string mlirBuilder = [{
$_op = $_builder.create<LLVM::masked_scatter>($_location,
$value, $ptrs, $mask, $_int_attr($alignment));
}];
list<int> llvmArgIndices = [0, 1, 3, 2];
}
/// Create a call to Masked Expand Load intrinsic.
def LLVM_masked_expandload : LLVM_IntrOp<"masked.expandload", [0], [], [], 1> {
let arguments = (ins LLVM_AnyPointer, LLVM_VectorOf<I1>, LLVM_AnyVector);
}
/// Create a call to Masked Compress Store intrinsic.
def LLVM_masked_compressstore
: LLVM_IntrOp<"masked.compressstore", [], [0], [], 0> {
let arguments = (ins LLVM_AnyVector, LLVM_AnyPointer, LLVM_VectorOf<I1>);
}
//
// Annotate intrinsics.
//
def LLVM_VarAnnotation
: LLVM_ZeroResultIntrOp<"var.annotation", [0, 1],
[AllTypesMatch<["annotation", "fileName", "attr"]>]> {
let arguments = (ins LLVM_AnyPointer:$val,
LLVM_AnyPointer:$annotation,
LLVM_AnyPointer:$fileName,
I32:$line,
LLVM_AnyPointer:$attr);
}
def LLVM_PtrAnnotation
: LLVM_OneResultIntrOp<"ptr.annotation", [0], [2],
[AllTypesMatch<["res", "ptr"]>,
AllTypesMatch<["annotation", "fileName", "attr"]>]> {
let arguments = (ins LLVM_AnyPointer:$ptr,
LLVM_AnyPointer:$annotation,
LLVM_AnyPointer:$fileName,
I32:$line,
LLVM_AnyPointer:$attr);
let results = (outs LLVM_AnyPointer:$res);
}
def LLVM_Annotation
: LLVM_OneResultIntrOp<"annotation", [0], [2],
[AllTypesMatch<["res", "integer"]>,
AllTypesMatch<["annotation", "fileName"]>]> {
let arguments = (ins AnySignlessInteger:$integer,
LLVM_AnyPointer:$annotation,
LLVM_AnyPointer:$fileName,
I32:$line);
let results = (outs AnySignlessInteger:$res);
}
//
// Trap intrinsics.
//
def LLVM_Trap : LLVM_ZeroResultIntrOp<"trap">;
def LLVM_DebugTrap : LLVM_ZeroResultIntrOp<"debugtrap">;
def LLVM_UBSanTrap : LLVM_ZeroResultIntrOp<"ubsantrap",
/*overloadedOperands=*/[], /*traits=*/[],
/*requiresAccessGroup=*/0, /*requiresAliasAnalysis=*/0,
/*immArgPositions=*/[0], /*immArgAttrNames=*/["failureKind"]> {
let arguments = (ins I8Attr:$failureKind);
}
/// Create a call to vscale intrinsic.
def LLVM_vscale : LLVM_IntrOp<"vscale", [0], [], [], 1>;
/// Create a call to stepvector intrinsic.
def LLVM_StepVectorOp
: LLVM_IntrOp<"experimental.stepvector", [0], [], [Pure], 1> {
let arguments = (ins);
let results = (outs LLVM_VectorOf<AnySignlessInteger>:$res);
let assemblyFormat = "attr-dict `:` type($res)";
}
/// Create a call to vector.insert intrinsic
def LLVM_vector_insert
: LLVM_OneResultIntrOp<"vector.insert",
/*overloadedResults=*/[0], /*overloadedOperands=*/[1],
/*traits=*/[Pure, AllTypesMatch<["dstvec", "res"]>,
PredOpTrait<"vectors are not bigger than 2^17 bits.", And<[
CPred<"getSrcVectorBitWidth() <= 131072">,
CPred<"getDstVectorBitWidth() <= 131072">
]>>,
PredOpTrait<"it is not inserting scalable into fixed-length vectors.",
CPred<"!isScalableVectorType($srcvec.getType()) || "
"isScalableVectorType($dstvec.getType())">>],
/*requiresFastmath=*/0,
/*immArgPositions=*/[2], /*immArgAttrNames=*/["pos"]> {
let arguments = (ins LLVM_AnyVector:$dstvec, LLVM_AnyVector:$srcvec,
I64Attr:$pos);
let results = (outs LLVM_AnyVector:$res);
let assemblyFormat = "$srcvec `,` $dstvec `[` $pos `]` attr-dict `:` "
"type($srcvec) `into` type($res)";
let extraClassDeclaration = [{
uint64_t getVectorBitWidth(Type vector) {
return getVectorNumElements(vector).getKnownMinValue() *
getVectorElementType(vector).getIntOrFloatBitWidth();
}
uint64_t getSrcVectorBitWidth() {
return getVectorBitWidth(getSrcvec().getType());
}
uint64_t getDstVectorBitWidth() {
return getVectorBitWidth(getDstvec().getType());
}
}];
}
/// Create a call to vector.extract intrinsic
def LLVM_vector_extract
: LLVM_OneResultIntrOp<"vector.extract",
/*overloadedResults=*/[0], /*overloadedOperands=*/[0],
/*traits=*/[Pure,
PredOpTrait<"vectors are not bigger than 2^17 bits.", And<[
CPred<"getSrcVectorBitWidth() <= 131072">,
CPred<"getResVectorBitWidth() <= 131072">
]>>,
PredOpTrait<"it is not extracting scalable from fixed-length vectors.",
CPred<"!isScalableVectorType($res.getType()) || "
"isScalableVectorType($srcvec.getType())">>],
/*requiresFastmath=*/0,
/*immArgPositions=*/[1], /*immArgAttrNames=*/["pos"]> {
let arguments = (ins LLVM_AnyVector:$srcvec, I64Attr:$pos);
let results = (outs LLVM_AnyVector:$res);
let assemblyFormat = "$srcvec `[` $pos `]` attr-dict `:` "
"type($res) `from` type($srcvec)";
let extraClassDeclaration = [{
uint64_t getVectorBitWidth(Type vector) {
return getVectorNumElements(vector).getKnownMinValue() *
getVectorElementType(vector).getIntOrFloatBitWidth();
}
uint64_t getSrcVectorBitWidth() {
return getVectorBitWidth(getSrcvec().getType());
}
uint64_t getResVectorBitWidth() {
return getVectorBitWidth(getRes().getType());
}
}];
}
def LLVM_experimental_vector_interleave2
: LLVM_OneResultIntrOp<"experimental.vector.interleave2",
/*overloadedResults=*/[0], /*overloadedOperands=*/[],
/*traits=*/[
Pure, AllTypesMatch<["vec1", "vec2"]>,
PredOpTrait<
"result has twice as many elements as 'vec1'",
And<[CPred<"getVectorNumElements($res.getType()) == "
"getVectorNumElements($vec1.getType()) * 2">,
CPred<"getVectorElementType($vec1.getType()) == "
"getVectorElementType($res.getType())">]>>,
]>,
Arguments<(ins LLVM_AnyVector:$vec1, LLVM_AnyVector:$vec2)>;
//
// LLVM Vector Predication operations.
//
class LLVM_VPBinaryBase<string mnem, Type element>
: LLVM_OneResultIntrOp<"vp." # mnem, [0], [], [Pure]>,
Arguments<(ins LLVM_VectorOf<element>:$lhs, LLVM_VectorOf<element>:$rhs,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
class LLVM_VPBinaryI<string mnem> : LLVM_VPBinaryBase<mnem, AnySignlessInteger>;
class LLVM_VPBinaryF<string mnem> : LLVM_VPBinaryBase<mnem, AnyFloat>;
class LLVM_VPUnaryBase<string mnem, Type element>
: LLVM_OneResultIntrOp<"vp." # mnem, [0], [], [Pure]>,
Arguments<(ins LLVM_VectorOf<element>:$op,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
class LLVM_VPUnaryF<string mnem> : LLVM_VPUnaryBase<mnem, AnyFloat>;
class LLVM_VPTernaryBase<string mnem, Type element>
: LLVM_OneResultIntrOp<"vp." # mnem, [0], [], [Pure]>,
Arguments<(ins LLVM_VectorOf<element>:$op1, LLVM_VectorOf<element>:$op2,
LLVM_VectorOf<element>:$op3, LLVM_VectorOf<I1>:$mask,
I32:$evl)>;
class LLVM_VPTernaryF<string mnem> : LLVM_VPTernaryBase<mnem, AnyFloat>;
class LLVM_VPReductionBase<string mnem, Type element>
: LLVM_OneResultIntrOp<"vp.reduce." # mnem, [], [1], [Pure]>,
Arguments<(ins element:$satrt_value, LLVM_VectorOf<element>:$val,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
class LLVM_VPReductionI<string mnem> : LLVM_VPReductionBase<mnem, AnySignlessInteger>;
class LLVM_VPReductionF<string mnem> : LLVM_VPReductionBase<mnem, AnyFloat>;
class LLVM_VPSelectBase<string mnem>
: LLVM_OneResultIntrOp<"vp." # mnem, [], [1], [Pure]>,
Arguments<(ins LLVM_VectorOf<I1>:$cond, LLVM_AnyVector:$true_val,
LLVM_AnyVector:$false_val, I32:$evl)>;
class LLVM_VPCastBase<string mnem, Type element>
: LLVM_OneResultIntrOp<"vp." # mnem, [0], [0], [Pure]>,
Arguments<(ins LLVM_VectorOf<element>:$src,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
class LLVM_VPCastI<string mnem> : LLVM_VPCastBase<mnem, AnySignlessInteger>;
class LLVM_VPCastF<string mnem> : LLVM_VPCastBase<mnem, AnyFloat>;
class LLVM_VPCastPtr<string mnem> : LLVM_VPCastBase<mnem, LLVM_AnyPointer>;
// Integer Binary
def LLVM_VPAddOp : LLVM_VPBinaryI<"add">;
def LLVM_VPSubOp : LLVM_VPBinaryI<"sub">;
def LLVM_VPMulOp : LLVM_VPBinaryI<"mul">;
def LLVM_VPSDivOp : LLVM_VPBinaryI<"sdiv">;
def LLVM_VPUDivOp : LLVM_VPBinaryI<"udiv">;
def LLVM_VPSRemOp : LLVM_VPBinaryI<"srem">;
def LLVM_VPURemOp : LLVM_VPBinaryI<"urem">;
def LLVM_VPAShrOp : LLVM_VPBinaryI<"ashr">;
def LLVM_VPLShrOp : LLVM_VPBinaryI<"lshr">;
def LLVM_VPShlOp : LLVM_VPBinaryI<"shl">;
def LLVM_VPOrOp : LLVM_VPBinaryI<"or">;
def LLVM_VPAndOp : LLVM_VPBinaryI<"and">;
def LLVM_VPXorOp : LLVM_VPBinaryI<"xor">;
// Float Binary
def LLVM_VPFAddOp : LLVM_VPBinaryF<"fadd">;
def LLVM_VPFSubOp : LLVM_VPBinaryF<"fsub">;
def LLVM_VPFMulOp : LLVM_VPBinaryF<"fmul">;
def LLVM_VPFDivOp : LLVM_VPBinaryF<"fdiv">;
def LLVM_VPFRemOp : LLVM_VPBinaryF<"frem">;
// Float Unary
def LLVM_VPFNegOp : LLVM_VPUnaryF<"fneg">;
// Float Ternary
def LLVM_VPFMulAddOp : LLVM_VPTernaryF<"fmuladd">;
def LLVM_VPFmaOp : LLVM_VPTernaryF<"fma">;
// Integer Reduction
def LLVM_VPReduceAddOp : LLVM_VPReductionI<"add">;
def LLVM_VPReduceMulOp : LLVM_VPReductionI<"mul">;
def LLVM_VPReduceAndOp : LLVM_VPReductionI<"and">;
def LLVM_VPReduceOrOp : LLVM_VPReductionI<"or">;
def LLVM_VPReduceXorOp : LLVM_VPReductionI<"xor">;
def LLVM_VPReduceSMaxOp : LLVM_VPReductionI<"smax">;
def LLVM_VPReduceSMinOp : LLVM_VPReductionI<"smin">;
def LLVM_VPReduceUMaxOp : LLVM_VPReductionI<"umax">;
def LLVM_VPReduceUMinOp : LLVM_VPReductionI<"umin">;
// Float Reduction
def LLVM_VPReduceFAddOp : LLVM_VPReductionF<"fadd">;
def LLVM_VPReduceFMulOp : LLVM_VPReductionF<"fmul">;
def LLVM_VPReduceFMaxOp : LLVM_VPReductionF<"fmax">;
def LLVM_VPReduceFMinOp : LLVM_VPReductionF<"fmin">;
def LLVM_VPSelectMinOp : LLVM_VPSelectBase<"select">;
def LLVM_VPMergeMinOp : LLVM_VPSelectBase<"merge">;
// Load/store
def LLVM_VPLoadOp
: LLVM_OneResultIntrOp<"vp.load", [0], [0], []>,
Arguments<(ins LLVM_AnyPointer:$ptr,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
def LLVM_VPStoreOp
: LLVM_ZeroResultIntrOp<"vp.store", [0, 1], []>,
Arguments<(ins LLVM_AnyVector:$val,
LLVM_AnyPointer:$ptr,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
// Strided load/store
def LLVM_VPStridedLoadOp
: LLVM_OneResultIntrOp<"experimental.vp.strided.load", [0], [0, 1], []>,
Arguments<(ins LLVM_AnyPointer:$ptr, AnySignlessInteger:$stride,
LLVM_VectorOf<I1>:$mask, I32:$evl)>;
def LLVM_VPStridedStoreOp
: LLVM_ZeroResultIntrOp<"experimental.vp.strided.store",[0, 1, 2], []>,
Arguments<(ins LLVM_AnyVector:$val, LLVM_AnyPointer:$ptr,
AnySignlessInteger:$stride, LLVM_VectorOf<I1>:$mask, I32:$evl)>;
def LLVM_VPTruncOp : LLVM_VPCastI<"trunc">;
def LLVM_VPZExtOp : LLVM_VPCastI<"zext">;
def LLVM_VPSExtOp : LLVM_VPCastI<"sext">;
def LLVM_VPFPTruncOp : LLVM_VPCastF<"fptrunc">;
def LLVM_VPFPExtOp : LLVM_VPCastF<"fpext">;
def LLVM_VPFPToUIOp : LLVM_VPCastF<"fptoui">;
def LLVM_VPFPToSIOp : LLVM_VPCastF<"fptosi">;
def LLVM_VPUIToFPOp : LLVM_VPCastI<"uitofp">;
def LLVM_VPSIToFPOp : LLVM_VPCastI<"sitofp">;
def LLVM_VPPtrToIntOp : LLVM_VPCastPtr<"ptrtoint">;
def LLVM_VPIntToPtrOp : LLVM_VPCastI<"inttoptr">;
#endif // LLVM_INTRINSIC_OP