diff options
author | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
commit | 6ffe9e53658409f212834330e13564e4952558f6 (patch) | |
tree | 85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang16/include/clang/Basic/arm_mve_defs.td | |
parent | 726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff) | |
download | ydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz |
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang16/include/clang/Basic/arm_mve_defs.td')
-rw-r--r-- | contrib/libs/clang16/include/clang/Basic/arm_mve_defs.td | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/contrib/libs/clang16/include/clang/Basic/arm_mve_defs.td b/contrib/libs/clang16/include/clang/Basic/arm_mve_defs.td new file mode 100644 index 0000000000..1a090c08cc --- /dev/null +++ b/contrib/libs/clang16/include/clang/Basic/arm_mve_defs.td @@ -0,0 +1,601 @@ +//===- arm_mve_defs.td - definitions and infrastructure for arm_mve.td ----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// The definitions in this file are designed to work in close conjunction with +// clang/utils/TableGen/MveEmitter.cpp. Comments in there will probably be +// useful as well. +// +//===----------------------------------------------------------------------===// + +// ----------------------------------------------------------------------------- +// Forward declarations. +class Type; + +// ----------------------------------------------------------------------------- +// Dummy record used as the dag operator for the argument list of an intrinsic. +// +// We store arguments as a dag rather than a list<Type> so that we can give +// each one a name, to be used in codegen. For example, (args Vector:$a, +// Scalar:$b) defines the names $a and $b which the specification of the code +// for that intrinsic can refer to. + +def args; + +// ----------------------------------------------------------------------------- +// Family of nodes for use in the codegen dag for an intrinsic, corresponding +// to function calls that return LLVM IR nodes. +class IRBuilderParam<int index_> { int index = index_; } +class IRBuilderAddrParam<int index_> : IRBuilderParam<index_>; +class IRBuilderIntParam<int index_, string type_> : IRBuilderParam<index_> { + string type = type_; +} +class IRBuilderBase { + // The prefix of the function call, including an open parenthesis. + string prefix; + + // Any parameters that have types that have to be treated specially by the + // Tablegen back end. Generally these will be types other than llvm::Value *, + // although not all other types need special treatment (e.g. llvm::Type *). + list<IRBuilderParam> special_params = []; +} +class IRBuilder<string func> : IRBuilderBase { + // The usual case: a method called on the code gen function's instance of + // llvm::IRBuilder. + let prefix = "Builder." # func # "("; +} +class IRFunction<string func> : IRBuilderBase { + // Some other function that doesn't use the IRBuilder at all. + let prefix = func # "("; +} +class CGHelperFn<string func> : IRBuilderBase { + // A helper function defined in CGBuiltin.cpp, which takes the IRBuilder as + // an argument. + let prefix = func # "(Builder, "; +} +class CGFHelperFn<string func> : IRBuilderBase { + // Like CGHelperFn, but also takes the CodeGenFunction itself. + let prefix = func # "(Builder, this, "; +} +def add: IRBuilder<"CreateAdd">; +def mul: IRBuilder<"CreateMul">; +def not: IRBuilder<"CreateNot">; +def or: IRBuilder<"CreateOr">; +def and: IRBuilder<"CreateAnd">; +def xor: IRBuilder<"CreateXor">; +def sub: IRBuilder<"CreateSub">; +def shl: IRBuilder<"CreateShl">; +def lshr: IRBuilder<"CreateLShr">; +def immshr: CGHelperFn<"MVEImmediateShr"> { + let special_params = [IRBuilderIntParam<1, "unsigned">, + IRBuilderIntParam<2, "bool">]; +} +def fadd: IRBuilder<"CreateFAdd">; +def fmul: IRBuilder<"CreateFMul">; +def fsub: IRBuilder<"CreateFSub">; +def load: IRBuilder<"CreateLoad"> { + let special_params = [IRBuilderAddrParam<0>]; +} +def store: IRBuilder<"CreateStore"> { + let special_params = [IRBuilderAddrParam<1>]; +} +def xval: IRBuilder<"CreateExtractValue"> { + let special_params = [IRBuilderIntParam<1, "unsigned">]; +} +def ielt_const: IRBuilder<"CreateInsertElement"> { + let special_params = [IRBuilderIntParam<2, "uint64_t">]; +} +def ielt_var: IRBuilder<"CreateInsertElement">; +def xelt_var: IRBuilder<"CreateExtractElement">; +def trunc: IRBuilder<"CreateTrunc">; +def bitcast: IRBuilder<"CreateBitCast">; +def vreinterpret: CGFHelperFn<"ARMMVEVectorReinterpret">; +def extend: CGHelperFn<"SignOrZeroExtend"> { + let special_params = [IRBuilderIntParam<2, "bool">]; +} +def zeroinit: IRFunction<"llvm::Constant::getNullValue">; +def int_min: CGHelperFn<"ARMMVEConstantSplat<1,0>">; +def int_max: CGHelperFn<"ARMMVEConstantSplat<0,1>">; +def uint_max: CGHelperFn<"ARMMVEConstantSplat<1,1>">; +def undef: IRFunction<"UndefValue::get">; +def icmp_eq: IRBuilder<"CreateICmpEQ">; +def icmp_ne: IRBuilder<"CreateICmpNE">; +def icmp_ugt: IRBuilder<"CreateICmpUGT">; +def icmp_uge: IRBuilder<"CreateICmpUGE">; +def icmp_ult: IRBuilder<"CreateICmpULT">; +def icmp_ule: IRBuilder<"CreateICmpULE">; +def icmp_sgt: IRBuilder<"CreateICmpSGT">; +def icmp_sge: IRBuilder<"CreateICmpSGE">; +def icmp_slt: IRBuilder<"CreateICmpSLT">; +def icmp_sle: IRBuilder<"CreateICmpSLE">; +def fcmp_eq: IRBuilder<"CreateFCmpOEQ">; +def fcmp_ne: IRBuilder<"CreateFCmpUNE">; // not O: it must return true on NaNs +def fcmp_gt: IRBuilder<"CreateFCmpOGT">; +def fcmp_ge: IRBuilder<"CreateFCmpOGE">; +def fcmp_lt: IRBuilder<"CreateFCmpOLT">; +def fcmp_le: IRBuilder<"CreateFCmpOLE">; +def splat: CGHelperFn<"ARMMVEVectorSplat">; +def select: IRBuilder<"CreateSelect">; +def fneg: IRBuilder<"CreateFNeg">; +def sitofp: IRBuilder<"CreateSIToFP">; +def uitofp: IRBuilder<"CreateUIToFP">; +def fptosi: IRBuilder<"CreateFPToSI">; +def fptoui: IRBuilder<"CreateFPToUI">; +def vrev: CGHelperFn<"ARMMVEVectorElementReverse"> { + let special_params = [IRBuilderIntParam<1, "unsigned">]; +} +def unzip: CGHelperFn<"VectorUnzip"> { + let special_params = [IRBuilderIntParam<1, "bool">]; +} +def zip: CGHelperFn<"VectorZip">; + +// Trivial 'codegen' function that just returns its argument. Useful +// for wrapping up a variable name like $foo into a thing you can pass +// around as type 'dag'. +def id: IRBuilderBase { + // All the other cases of IRBuilderBase use 'prefix' to specify a function + // call, including the open parenthesis. MveEmitter puts the closing paren on + // the end. So if we _just_ specify an open paren with no function name + // before it, then the generated C++ code will simply wrap the input value in + // parentheses, returning it unchanged. + let prefix = "("; +} + +// Helper for making boolean flags in IR +def i1: IRBuilderBase { + let prefix = "llvm::ConstantInt::get(Builder.getInt1Ty(), "; + let special_params = [IRBuilderIntParam<0, "bool">]; +} + +// A node that makes an Address out of a pointer-typed Value, by +// providing an alignment as the second argument. +def address; + +// Another node class you can use in the codegen dag. This one corresponds to +// an IR intrinsic function, which has to be specialized to a particular list +// of types. +class IRIntBase<string name_, list<Type> params_ = [], bit appendKind_ = 0> { + string intname = name_; // base name of the intrinsic + list<Type> params = params_; // list of parameter types + + // If this flag is set, then the IR intrinsic name will get a suffix _s, _u + // or _f depending on whether the main parameter type of the ACLE intrinsic + // being generated is a signed integer, unsigned integer, or float. Mostly + // this is useful for signed vs unsigned integers, because the ACLE + // intrinsics and the source-level integer types distinguish them, but at IR + // level the distinction has moved from the type system into the operations + // and you just have i32 or i16 etc. So when an IR intrinsic has to vary with + // signedness, you set this bit, and then you can still put the signed and + // unsigned versions in the same subclass of Intrinsic, and the Tablegen + // backend will take care of adding _s or _u as appropriate in each instance. + bit appendKind = appendKind_; +} + +// Mostly we'll be using @llvm.arm.mve.* intrinsics, so here's a trivial +// subclass that puts on that prefix. +class IRInt<string name, list<Type> params = [], bit appendKind = 0> + : IRIntBase<"arm_mve_" # name, params, appendKind>; + +// The 'seq' node in a codegen dag specifies a set of IR operations to be +// performed in order. It has the special ability to define extra variable +// names, on top of the ones that refer to the intrinsic's parameters. For +// example: +// +// (seq (foo this, that):$a, +// (bar this, $a):$b +// (add $a, $b)) +// +// defines the name $a to refer to the return value of the 'foo' operation; +// then the 'bar' operation uses $a as one of its arguments, and the return +// value of that is assigned the name $b; finally, $a and $b are added to give +// the return value of the seq construction as a whole. +def seq; + +// Another magic operation is 'unsignedflag', which you give a scalar +// _type_ as an argument, and it expands into 1 for an unsigned type +// and 0 for a signed (or floating) one. +def unsignedflag; + +// 'bitsize' also takes a scalar type, and expands into an integer +// constant giving its size in bits. +def bitsize; + +// If you put CustomCodegen<"foo"> in an intrinsic's codegen field, it +// indicates that the IR generation for that intrinsic is done by handwritten +// C++ and not autogenerated at all. The effect in the MVE builtin codegen +// function is to break out of the main switch and fall through to the +// manual-codegen cases below it, having set the CustomCodeGenType enumerated +// variable to the value given by the 'type' string here. +class CustomCodegen<string type_> { string type = type_; } + +// ----------------------------------------------------------------------------- +// System for building up complex instances of Type from simple ones. + +// ComplexType is used to represent any more complicated type: vectors, +// multivectors, pointers etc. Its dag argument specifies how the type should +// be constructed from simpler types. The operator of the dag will always be an +// instance of ComplexTypeOp, defined below. +class ComplexType<dag spec_>: Type { dag spec = spec_; } + +// Operators you can use in the ComplexType spec dag. These are an intermediate +// layer, interpreted by MveEmitter::getType() in the Tablegen backend, and +// only used in the definitions below. Actual intrinsic definitions in +// arm_mve.td will use the defs defined below here. +class ComplexTypeOp; +def CTO_Parameter: ComplexTypeOp; +def CTO_Vec: ComplexTypeOp; +def CTO_Pred: ComplexTypeOp; +class CTO_Tuple<int n_>: ComplexTypeOp { int n = n_; } +class CTO_Pointer<bit const_>: ComplexTypeOp { bit const = const_; } +def CTO_CopyKind: ComplexTypeOp; +class CTO_ScaleSize<int num_, int denom_>: ComplexTypeOp { + int num = num_; + int denom = denom_; +} + +// ----------------------------------------------------------------------------- +// Instances of Type intended to be used directly in the specification of an +// intrinsic in arm_mve.td. + +// The type Void can be used for the return type of an intrinsic, and as the +// parameter type for intrinsics that aren't actually parameterised by any kind +// of _s32 / _f16 / _u8 suffix. +def Void : Type; + +// A wrapper you can put on an intrinsic's argument type to prevent it from +// being automatically promoted to i32 from a smaller integer type. +class unpromoted<Type t> : Type { Type underlying_type = t; } + +// Primitive types: base class, and an instance for the set of scalar integer +// and floating types that MVE uses. +class PrimitiveType<string kind_, int size_>: Type { + string kind = kind_; + int size = size_; + string nameOverride = ""; +} + +// The type records defined by these foreaches have names like s32, f16, u8. +foreach size = [8, 16, 32, 64] in + foreach kind = ["u", "s"] in + def kind # size: PrimitiveType<kind, size>; +foreach size = [16, 32] in + foreach kind = ["f"] in + def kind # size: PrimitiveType<kind, size>; + +// Sometimes we need to refer to a type by a different name in C, when +// ACLE defines a function parameter to be something like 'unsigned' +// rather than uint32_t. +def uint: PrimitiveType<"u", 32> { let nameOverride = "unsigned"; } +def sint: PrimitiveType<"s", 32> { let nameOverride = "int"; } + +// VecOf<t> expects t to be a scalar, and gives a 128-bit vector of whatever it +// is. +class VecOf<Type t>: ComplexType<(CTO_Vec t)>; + +// NarrowedVecOf<t,v> expects t to be a scalar type, and v to be a vector +// type. It returns a vector type whose element type is t, and whose lane +// count is the same as the lane count of v. (Used as an intermediate value +// type in the IR representation of a widening load: you load a vector of +// small things out of memory, and then zext/sext them into a full 128-bit +// output vector.) +class NarrowedVecOf<Type t, Type v>: ComplexType<(CTO_Vec t, v)>; + +// PredOf expects t to be a scalar, and expands to a predicate vector which +// (logically speaking) has the same number of lanes as VecOf<t> would. +class PredOf<Type t>: ComplexType<(CTO_Pred t)>; + +// Scalar expands to whatever is the main parameter type of the current +// intrinsic. Vector and Predicate expand to the vector and predicate types +// corresponding to that. +def Scalar: ComplexType<(CTO_Parameter)>; +def Vector: VecOf<Scalar>; +def Predicate: PredOf<Scalar>; + +// MultiVector<n> expands to a type containing n instances of Vector. (There's +// no need to define this for a general underlying vector type, since it's only +// used by vld2q and friends, which don't need that generality.) +class MultiVector<int n>: ComplexType<(CTO_Tuple<n> Vector)>; + +// Ptr<t> and CPtr<t> expand to a pointer to t, or a pointer to const t, +// respectively. +class Ptr<Type t>: ComplexType<(CTO_Pointer<0> t)>; +class CPtr<Type t>: ComplexType<(CTO_Pointer<1> t)>; + +// CopyKind<s,k> expects s and k to be scalar types. It returns a scalar type +// whose kind (signed, unsigned or float) matches that of k, and whose size +// matches that of s. +class CopyKind<Type s, Type k>: ComplexType<(CTO_CopyKind s, k)>; + +// DoubleSize<k> expects k to be a scalar type. It returns a scalar type +// whose kind (signed, unsigned or float) matches that of k, and whose size +// is double that of k, if possible. +class DoubleSize<Type k> : ComplexType<(CTO_ScaleSize<2, 1> k)>; +class HalfSize<Type k> : ComplexType<(CTO_ScaleSize<1, 2> k)>; + +// Unsigned<t> expects t to be a scalar type, and expands to the unsigned +// integer scalar of the same size. So it returns u16 if you give it s16 or +// f16 (or u16 itself). Similarly, Signed<t> makes the type signed. +class Unsigned<Type t>: ComplexType<(CTO_CopyKind t, u32)>; +class Signed<Type t>: ComplexType<(CTO_CopyKind t, s32)>; + +// UScalar and UVector expand to the unsigned-integer versions of +// Scalar and Vector. SScalar and SVector are signed-integer versions. +def UScalar: Unsigned<Scalar>; +def UVector: VecOf<UScalar>; +def SScalar: Signed<Scalar>; +def SVector: VecOf<SScalar>; + +// DblVector expands to a vector of scalars of size twice the size of Scalar. +// DblPredicate expands to a predicate corresponding to DblVector +// HalfVector, similarly, expands to a vector of half-sized scalars. And +// UHalfVector is a vector of half-sized _unsigned integers_. +def DblVector: VecOf<DoubleSize<Scalar>>; +def DblPredicate: PredOf<DoubleSize<Scalar>>; +def HalfScalar: HalfSize<Scalar>; +def HalfVector: VecOf<HalfScalar>; +def UHalfScalar: Unsigned<HalfSize<Scalar>>; +def UHalfVector: VecOf<UHalfScalar>; + +// Expands to the 32-bit integer of the same signedness as Scalar. +def Scalar32: CopyKind<u32, Scalar>; +// Expands to the 64-bit integer of the same signedness as Scalar. +def Scalar64: CopyKind<u64, Scalar>; + +// ----------------------------------------------------------------------------- +// Internal definitions for specifying immediate arguments for an intrinsic. + +class ImmediateBounds; +class Immediate<Type type_, ImmediateBounds bounds_>: Type { + Type type = type_; + ImmediateBounds bounds = bounds_; + string extra; + string extraarg; +} +class IB_ConstRange<int lo_, int hi_> : ImmediateBounds { + int lo = lo_; + int hi = hi_; +} +def IB_UEltValue : ImmediateBounds; +def IB_LaneIndex : ImmediateBounds; +class IB_EltBit<int base_, Type type_ = Scalar> : ImmediateBounds { + int base = base_; + Type type = type_; +} +def IB_ExtraArg_LaneSize; + +// ----------------------------------------------------------------------------- +// End-user definitions for immediate arguments. + +// imm_simd and imm_simd_restrictive are used for the immediate operands to +// intrinsics like vmvnq or vorrq. imm_simd_restrictive has to be an 8-bit +// value shifted left by a whole number of bytes; imm_simd_vmvn can also be of +// the form 0xXXFF for some byte value XX. +def imm_simd_restrictive : Immediate<Scalar, IB_UEltValue> { + let extra = "ShiftedByte"; + let extraarg = "!lanesize"; +} +def imm_simd_vmvn : Immediate<Scalar, IB_UEltValue> { + let extra = "ShiftedByteOrXXFF"; + let extraarg = "!lanesize"; +} + +// imm_1toN can take any value from 1 to N inclusive, where N is the number of +// bits in the main parameter type. (E.g. an immediate shift count, in an +// intrinsic that shifts every lane of a vector by the same amount.) +// +// imm_0toNm1 is the same but with the range offset by 1, i.e. 0 to N-1 +// inclusive. +// +// imm_1toHalfN is like imm_1toN, but applied to a half-width type. +// (So if Scalar is s16, for example, it'll give you the range 1 to 8.) +def imm_1toN : Immediate<sint, IB_EltBit<1>>; +def imm_0toNm1 : Immediate<sint, IB_EltBit<0>>; +def imm_1toHalfN : Immediate<sint, IB_EltBit<1, HalfSize<Scalar>>>; + +// imm_lane has to be the index of a vector lane in the main vector type, i.e +// it can range from 0 to (128 / size of scalar)-1 inclusive. (e.g. vgetq_lane) +def imm_lane : Immediate<sint, IB_LaneIndex>; + +// imm_1to32 can be in the range 1 to 32, unconditionally. (e.g. scalar shift +// intrinsics) +def imm_1to32 : Immediate<sint, IB_ConstRange<1, 32>>; + +// imm_1248 can be 1, 2, 4 or 8. (e.g. vidupq) +def imm_1248 : Immediate<sint, IB_ConstRange<1, 8>> { + let extra = "Power2"; +} + +// imm_mem7bit<n> is a valid immediate offset for a load/store intrinsic whose +// memory access size is n bytes (e.g. 1 for vldrb_[whatever], 2 for vldrh, +// ...). The set of valid immediates for these is {-127*n, ..., -1*n, 0*n, 1*n, +// ..., 127*n}. +class imm_mem7bit<int membytes> + : Immediate<sint, IB_ConstRange<!mul(membytes, -127), !mul(membytes, 127)>> { + let extra = !if(!eq(membytes, 1), ?, "Multiple"); + let extraarg = !cast<string>(membytes); +} + +// ----------------------------------------------------------------------------- +// Specification of ways that the full name of an intrinsic can be mapped to +// its shorter polymorphic name. + +class PolymorphicNameType<int nt_, string x_> { + int NumTypeSuffixesToDiscard = nt_; + string ExtraSuffixToDiscard = x_; +} + +// PNT_None: the intrinsic is not polymorphic at all, so its short name is the +// same as its long name. (E.g. scalar shift intrinsics such as uqshl.) +def PNT_None: PolymorphicNameType<0, ?>; + +// PNT_Type: the usual case, in which the polymorphic name is made by dropping +// the type suffix, so it ends up the same as the Tablegen record name. E.g. +// vaddq_u16 -> vaddq. +def PNT_Type: PolymorphicNameType<1, ?>; + +// PNT_2Type: the polymorphic name is made by dropping _two_ type suffixes. +// E.g. vcvtq_f16_u16 -> vcvtq. +def PNT_2Type: PolymorphicNameType<2, ?>; + +// PNT_NType: the polymorphic name is made by dropping an "_n" suffix and a +// type. E.g. vaddq_n_u16 -> vaddq. +def PNT_NType: PolymorphicNameType<1, "n">; + +// PNT_NType: the polymorphic name is made by just dropping an "_n" suffix +// (even if it isn't at the end of the name). E.g. vidupq_n_u16 -> vidupq_u16. +def PNT_N: PolymorphicNameType<0, "n">; + +// PNT_WBType: the polymorphic name is made by dropping an "_wb" suffix and a +// type. E.g. vidupq_m_wb_u16 -> vidupq_m. +def PNT_WBType: PolymorphicNameType<1, "wb">; + +// PNT_WB: the polymorphic name is made by just dropping "_wb". E.g. +// vidupq_wb_u16 -> vidupq_u16. +def PNT_WB: PolymorphicNameType<0, "wb">; + +// ----------------------------------------------------------------------------- +// The main class Intrinsic. Define one of these for each family of ACLE +// intrinsics which are the same apart from some final type suffix (e.g. +// vaddq_{s8,u8,f16,...}. +// +// The record's name plus that type suffix is taken to be the full unambiguous +// name of the function. Its shorter polymorphic name is constructed from that +// in turn, in a way specified by the PolymorphicNameType system above. + +class Intrinsic<Type ret_, dag args_, dag codegen_> { + // List of parameter types to suffix to this intrinsic's name. A separate + // actual ACLE intrinsic will be generated for each of these. Set it to + // [Void] if the intrinsic is not polymorphic at all. + list<Type> params; + + // Return type and arguments for the intrinsic. + Type ret = ret_; + dag args = args_; + + // Specification of how to generate its IR. + dag codegen = codegen_; + + // Default to PNT_Type, which is by far the most common case. + PolymorphicNameType pnt = PNT_Type; + + // A very few intrinsics _only_ have a polymorphic name. + bit polymorphicOnly = 0; + + // True if the builtin has to avoid evaluating its arguments. + bit nonEvaluating = 0; + + // True if the intrinsic needs only the C header part (no codegen, semantic + // checks, etc). Used for redeclaring MVE intrinsics in the arm_cde.h header. + bit headerOnly = 0; + + // Use to override the suffix letter to make e.g.vfooq_p16 + // with an override suffix letter of "p". + string overrideKindLetter = ""; + + // Name of the architecture extension, used in the Clang builtin name + string builtinExtension = "mve"; +} + +// Sometimes you have to use two separate Intrinsic declarations to +// declare intrinsics that are logically the same family (e.g. vaddq, +// because it needs to expand to an Add or FAdd IR node depending on +// type). For that purpose, you can derive from NameOverride to +// specify the intrinsic's base name independently of the Tablegen +// record name. + +class NameOverride<string basename_> { + string basename = basename_; +} + +// A wrapper to define both _m and _x versions of a predicated +// intrinsic. +// +// We provide optional parameters to override the polymorphic name +// types separately for the _m and _x variants, because sometimes they +// polymorph differently (typically because the type of the inactive +// parameter can be used as a disambiguator if it's present). +multiclass IntrinsicMX<Type rettype, dag arguments, dag cg, + bit wantXVariant = 1, + string nameSuffix = "", + PolymorphicNameType pnt_m = PNT_Type, + PolymorphicNameType pnt_x = PNT_Type> { + // The _m variant takes an initial parameter called $inactive, which + // provides the input value of the output register, i.e. all the + // inactive lanes in the predicated operation take their values from + // this. + def : Intrinsic<rettype, !con((args rettype:$inactive), arguments), cg>, + NameOverride<NAME # "_m" # nameSuffix> { + let pnt = pnt_m; + } + + if wantXVariant then { + // The _x variant leaves off that parameter, and simply uses an + // undef value of the same type. + + def : Intrinsic<rettype, arguments, (seq (undef rettype):$inactive, cg)>, + NameOverride<NAME # "_x" # nameSuffix> { + let pnt = pnt_x; + } + } +} + +// Same as above, but with an additional parameter 'basename' which overrides +// the C intrinsic base name +multiclass IntrinsicMXNameOverride<Type rettype, dag arguments, dag cg, + string basename, bit wantXVariant = 1, + string nameSuffix = "", + PolymorphicNameType pnt_m = PNT_Type, + PolymorphicNameType pnt_x = PNT_Type> { + def "_m" # nameSuffix: + Intrinsic<rettype, !con((args rettype:$inactive), arguments), cg>, + NameOverride<basename # "_m" # nameSuffix> { + let pnt = pnt_m; + } + + if wantXVariant then { + def "_x" # nameSuffix: + Intrinsic<rettype, arguments, (seq (undef rettype):$inactive, cg)>, + NameOverride<basename # "_x" # nameSuffix> { + let pnt = pnt_x; + } + } +} + + +// ----------------------------------------------------------------------------- +// Convenience lists of parameter types. 'T' is just a container record, so you +// can define a typical intrinsic with 'let Params = T.Usual', or similar, +// instead of having to repeat a long list every time. + +def T { + list<Type> None = [Void]; + list<Type> Signed = [s8, s16, s32]; + list<Type> Unsigned = [u8, u16, u32]; + list<Type> Int = Signed # Unsigned; + list<Type> Float = [f16, f32]; + list<Type> Usual = Int # Float; + list<Type> Int8 = [s8, u8]; + list<Type> Int16 = [s16, u16]; + list<Type> Int32 = [s32, u32]; + list<Type> Int64 = [s64, u64]; + list<Type> Poly = [u8, u16]; // Actually p8 and p16 + list<Type> All8 = Int8; + list<Type> All16 = Int16 # [f16]; + list<Type> All32 = Int32 # [f32]; + list<Type> All64 = Int64; + list<Type> All = Usual # All64; +} + +// ----------------------------------------------------------------------------- +// Container record for DAG constant values. These constants are used because +// bit/int class/multiclass parameters cannot be used to produce a dag node: +// for example (u32 x) where x is 0 is transformed into (u32 { 0 }) by the +// Tablegen parser. +def V { + dag False = (u32 0); + dag True = (u32 1); +} |