1356843Sdim//===- arm_mve_defs.td - definitions and infrastructure for arm_mve.td ----===// 2356843Sdim// 3356843Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4356843Sdim// See https://llvm.org/LICENSE.txt for license information. 5356843Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6356843Sdim// 7356843Sdim//===----------------------------------------------------------------------===// 8356843Sdim// 9356843Sdim// The definitions in this file are designed to work in close conjunction with 10356843Sdim// clang/utils/TableGen/MveEmitter.cpp. Comments in there will probably be 11356843Sdim// useful as well. 12356843Sdim// 13356843Sdim//===----------------------------------------------------------------------===// 14356843Sdim 15356843Sdim// ----------------------------------------------------------------------------- 16356843Sdim// Forward declarations. 17356843Sdimclass Type; 18356843Sdim 19356843Sdim// ----------------------------------------------------------------------------- 20356843Sdim// Dummy record used as the dag operator for the argument list of an intrinsic. 21356843Sdim// 22356843Sdim// We store arguments as a dag rather than a list<Type> so that we can give 23356843Sdim// each one a name, to be used in codegen. For example, (args Vector:$a, 24356843Sdim// Scalar:$b) defines the names $a and $b which the specification of the code 25356843Sdim// for that intrinsic can refer to. 26356843Sdim 27356843Sdimdef args; 28356843Sdim 29356843Sdim// ----------------------------------------------------------------------------- 30356843Sdim// Family of nodes for use in the codegen dag for an intrinsic, corresponding 31356843Sdim// to function calls that return LLVM IR nodes. 32356843Sdimclass IRBuilderParam<int index_> { int index = index_; } 33356843Sdimclass IRBuilderAddrParam<int index_> : IRBuilderParam<index_>; 34356843Sdimclass IRBuilderIntParam<int index_, string type_> : IRBuilderParam<index_> { 35356843Sdim string type = type_; 36356843Sdim} 37356843Sdimclass IRBuilderBase { 38356843Sdim // The prefix of the function call, including an open parenthesis. 39356843Sdim string prefix; 40356843Sdim 41356843Sdim // Any parameters that have types that have to be treated specially by the 42356843Sdim // Tablegen back end. Generally these will be types other than llvm::Value *, 43356843Sdim // although not all other types need special treatment (e.g. llvm::Type *). 44356843Sdim list<IRBuilderParam> special_params = []; 45356843Sdim} 46356843Sdimclass IRBuilder<string func> : IRBuilderBase { 47356843Sdim // The usual case: a method called on the code gen function's instance of 48356843Sdim // llvm::IRBuilder. 49356843Sdim let prefix = "Builder." # func # "("; 50356843Sdim} 51356843Sdimclass IRFunction<string func> : IRBuilderBase { 52356843Sdim // Some other function that doesn't use the IRBuilder at all. 53356843Sdim let prefix = func # "("; 54356843Sdim} 55356843Sdimclass CGHelperFn<string func> : IRBuilderBase { 56356843Sdim // A helper function defined in CGBuiltin.cpp, which takes the IRBuilder as 57356843Sdim // an argument. 58356843Sdim let prefix = func # "(Builder, "; 59356843Sdim} 60356843Sdimdef add: IRBuilder<"CreateAdd">; 61356843Sdimdef mul: IRBuilder<"CreateMul">; 62356843Sdimdef not: IRBuilder<"CreateNot">; 63356843Sdimdef or: IRBuilder<"CreateOr">; 64356843Sdimdef and: IRBuilder<"CreateAnd">; 65356843Sdimdef xor: IRBuilder<"CreateXor">; 66356843Sdimdef sub: IRBuilder<"CreateSub">; 67356843Sdimdef shl: IRBuilder<"CreateShl">; 68356843Sdimdef lshr: IRBuilder<"CreateLShr">; 69356843Sdimdef immshr: CGHelperFn<"MVEImmediateShr"> { 70356843Sdim let special_params = [IRBuilderIntParam<1, "unsigned">, 71356843Sdim IRBuilderIntParam<2, "bool">]; 72356843Sdim} 73356843Sdimdef fadd: IRBuilder<"CreateFAdd">; 74356843Sdimdef fmul: IRBuilder<"CreateFMul">; 75356843Sdimdef fsub: IRBuilder<"CreateFSub">; 76356843Sdimdef load: IRBuilder<"CreateLoad"> { 77356843Sdim let special_params = [IRBuilderAddrParam<0>]; 78356843Sdim} 79356843Sdimdef store: IRBuilder<"CreateStore"> { 80356843Sdim let special_params = [IRBuilderAddrParam<1>]; 81356843Sdim} 82356843Sdimdef xval: IRBuilder<"CreateExtractValue"> { 83356843Sdim let special_params = [IRBuilderIntParam<1, "unsigned">]; 84356843Sdim} 85356843Sdimdef ielt_const: IRBuilder<"CreateInsertElement"> { 86356843Sdim let special_params = [IRBuilderIntParam<2, "uint64_t">]; 87356843Sdim} 88356843Sdimdef ielt_var: IRBuilder<"CreateInsertElement">; 89356843Sdimdef xelt_var: IRBuilder<"CreateExtractElement">; 90356843Sdimdef trunc: IRBuilder<"CreateTrunc">; 91356843Sdimdef bitcast: IRBuilder<"CreateBitCast">; 92356843Sdimdef extend: CGHelperFn<"SignOrZeroExtend"> { 93356843Sdim let special_params = [IRBuilderIntParam<2, "bool">]; 94356843Sdim} 95356843Sdimdef zeroinit: IRFunction<"llvm::Constant::getNullValue">; 96356843Sdimdef undef: IRFunction<"UndefValue::get">; 97356843Sdimdef icmp_eq: IRBuilder<"CreateICmpEQ">; 98356843Sdimdef icmp_ne: IRBuilder<"CreateICmpNE">; 99356843Sdimdef icmp_ugt: IRBuilder<"CreateICmpUGT">; 100356843Sdimdef icmp_uge: IRBuilder<"CreateICmpUGE">; 101356843Sdimdef icmp_ult: IRBuilder<"CreateICmpULT">; 102356843Sdimdef icmp_ule: IRBuilder<"CreateICmpULE">; 103356843Sdimdef icmp_sgt: IRBuilder<"CreateICmpSGT">; 104356843Sdimdef icmp_sge: IRBuilder<"CreateICmpSGE">; 105356843Sdimdef icmp_slt: IRBuilder<"CreateICmpSLT">; 106356843Sdimdef icmp_sle: IRBuilder<"CreateICmpSLE">; 107356843Sdimdef fcmp_eq: IRBuilder<"CreateFCmpOEQ">; 108356843Sdimdef fcmp_ne: IRBuilder<"CreateFCmpUNE">; // not O: it must return true on NaNs 109356843Sdimdef fcmp_gt: IRBuilder<"CreateFCmpOGT">; 110356843Sdimdef fcmp_ge: IRBuilder<"CreateFCmpOGE">; 111356843Sdimdef fcmp_lt: IRBuilder<"CreateFCmpOLT">; 112356843Sdimdef fcmp_le: IRBuilder<"CreateFCmpOLE">; 113356843Sdimdef splat: CGHelperFn<"ARMMVEVectorSplat">; 114356843Sdimdef select: IRBuilder<"CreateSelect">; 115356843Sdim 116356843Sdim// A node that makes an Address out of a pointer-typed Value, by 117356843Sdim// providing an alignment as the second argument. 118356843Sdimdef address; 119356843Sdim 120356843Sdim// Another node class you can use in the codegen dag. This one corresponds to 121356843Sdim// an IR intrinsic function, which has to be specialized to a particular list 122356843Sdim// of types. 123356843Sdimclass IRIntBase<string name_, list<Type> params_ = [], bit appendKind_ = 0> { 124356843Sdim string intname = name_; // base name of the intrinsic 125356843Sdim list<Type> params = params_; // list of parameter types 126356843Sdim 127356843Sdim // If this flag is set, then the IR intrinsic name will get a suffix _s, _u 128356843Sdim // or _f depending on whether the main parameter type of the ACLE intrinsic 129356843Sdim // being generated is a signed integer, unsigned integer, or float. Mostly 130356843Sdim // this is useful for signed vs unsigned integers, because the ACLE 131356843Sdim // intrinsics and the source-level integer types distinguish them, but at IR 132356843Sdim // level the distinction has moved from the type system into the operations 133356843Sdim // and you just have i32 or i16 etc. So when an IR intrinsic has to vary with 134356843Sdim // signedness, you set this bit, and then you can still put the signed and 135356843Sdim // unsigned versions in the same subclass of Intrinsic, and the Tablegen 136356843Sdim // backend will take care of adding _s or _u as appropriate in each instance. 137356843Sdim bit appendKind = appendKind_; 138356843Sdim} 139356843Sdim 140356843Sdim// Mostly we'll be using @llvm.arm.mve.* intrinsics, so here's a trivial 141356843Sdim// subclass that puts on that prefix. 142356843Sdimclass IRInt<string name, list<Type> params = [], bit appendKind = 0> 143356843Sdim : IRIntBase<"arm_mve_" # name, params, appendKind>; 144356843Sdim 145356843Sdim// The 'seq' node in a codegen dag specifies a set of IR operations to be 146356843Sdim// performed in order. It has the special ability to define extra variable 147356843Sdim// names, on top of the ones that refer to the intrinsic's parameters. For 148356843Sdim// example: 149356843Sdim// 150356843Sdim// (seq (foo this, that):$a, 151356843Sdim// (bar this, $a):$b 152356843Sdim// (add $a, $b)) 153356843Sdim// 154356843Sdim// defines the name $a to refer to the return value of the 'foo' operation; 155356843Sdim// then the 'bar' operation uses $a as one of its arguments, and the return 156356843Sdim// value of that is assigned the name $b; finally, $a and $b are added to give 157356843Sdim// the return value of the seq construction as a whole. 158356843Sdimdef seq; 159356843Sdim 160356843Sdim// Another magic operation is 'unsignedflag', which you give a scalar 161356843Sdim// _type_ as an argument, and it expands into 1 for an unsigned type 162356843Sdim// and 0 for a signed (or floating) one. 163356843Sdimdef unsignedflag; 164356843Sdim 165356843Sdim// If you put CustomCodegen<"foo"> in an intrinsic's codegen field, it 166356843Sdim// indicates that the IR generation for that intrinsic is done by handwritten 167356843Sdim// C++ and not autogenerated at all. The effect in the MVE builtin codegen 168356843Sdim// function is to break out of the main switch and fall through to the 169356843Sdim// manual-codegen cases below it, having set the CustomCodeGenType enumerated 170356843Sdim// variable to the value given by the 'type' string here. 171356843Sdimclass CustomCodegen<string type_> { string type = type_; } 172356843Sdim 173356843Sdim// ----------------------------------------------------------------------------- 174356843Sdim// System for building up complex instances of Type from simple ones. 175356843Sdim 176356843Sdim// ComplexType is used to represent any more complicated type: vectors, 177356843Sdim// multivectors, pointers etc. Its dag argument specifies how the type should 178356843Sdim// be constructed from simpler types. The operator of the dag will always be an 179356843Sdim// instance of ComplexTypeOp, defined below. 180356843Sdimclass ComplexType<dag spec_>: Type { dag spec = spec_; } 181356843Sdim 182356843Sdim// Operators you can use in the ComplexType spec dag. These are an intermediate 183356843Sdim// layer, interpreted by MveEmitter::getType() in the Tablegen backend, and 184356843Sdim// only used in the definitions below. Actual intrinsic definitions in 185356843Sdim// arm_mve.td will use the defs defined below here. 186356843Sdimclass ComplexTypeOp; 187356843Sdimdef CTO_Parameter: ComplexTypeOp; 188356843Sdimdef CTO_Vec: ComplexTypeOp; 189356843Sdimdef CTO_Pred: ComplexTypeOp; 190356843Sdimclass CTO_Tuple<int n_>: ComplexTypeOp { int n = n_; } 191356843Sdimclass CTO_Pointer<bit const_>: ComplexTypeOp { bit const = const_; } 192356843Sdimdef CTO_CopyKind: ComplexTypeOp; 193356843Sdimclass CTO_ScaleSize<int num_, int denom_>: ComplexTypeOp { 194356843Sdim int num = num_; 195356843Sdim int denom = denom_; 196356843Sdim} 197356843Sdim 198356843Sdim// ----------------------------------------------------------------------------- 199356843Sdim// Instances of Type intended to be used directly in the specification of an 200356843Sdim// intrinsic in arm_mve.td. 201356843Sdim 202356843Sdim// The type Void can be used for the return type of an intrinsic, and as the 203356843Sdim// parameter type for intrinsics that aren't actually parameterised by any kind 204356843Sdim// of _s32 / _f16 / _u8 suffix. 205356843Sdimdef Void : Type; 206356843Sdim 207356843Sdim// A wrapper you can put on an intrinsic's argument type to prevent it from 208356843Sdim// being automatically promoted to i32 from a smaller integer type. 209356843Sdimclass unpromoted<Type t> : Type { Type underlying_type = t; } 210356843Sdim 211356843Sdim// Primitive types: base class, and an instance for the set of scalar integer 212356843Sdim// and floating types that MVE uses. 213356843Sdimclass PrimitiveType<string kind_, int size_>: Type { 214356843Sdim string kind = kind_; 215356843Sdim int size = size_; 216356843Sdim string nameOverride = ""; 217356843Sdim} 218356843Sdim 219356843Sdim// The type records defined by these foreaches have names like s32, f16, u8. 220356843Sdimforeach size = [8, 16, 32, 64] in 221356843Sdim foreach kind = ["u", "s"] in 222356843Sdim def kind # size: PrimitiveType<kind, size>; 223356843Sdimforeach size = [16, 32] in 224356843Sdim foreach kind = ["f"] in 225356843Sdim def kind # size: PrimitiveType<kind, size>; 226356843Sdim 227356843Sdim// Sometimes we need to refer to a type by a different name in C, when 228356843Sdim// ACLE defines a function parameter to be something like 'unsigned' 229356843Sdim// rather than uint32_t. 230356843Sdimdef uint: PrimitiveType<"u", 32> { let nameOverride = "unsigned"; } 231356843Sdimdef sint: PrimitiveType<"s", 32> { let nameOverride = "int"; } 232356843Sdim 233356843Sdim// VecOf<t> expects t to be a scalar, and gives a 128-bit vector of whatever it 234356843Sdim// is. 235356843Sdimclass VecOf<Type t>: ComplexType<(CTO_Vec t)>; 236356843Sdim 237356843Sdim// NarrowedVecOf<t,v> expects t to be a scalar type, and v to be a vector 238356843Sdim// type. It returns a vector type whose element type is t, and whose lane 239356843Sdim// count is the same as the lane count of v. (Used as an intermediate value 240356843Sdim// type in the IR representation of a widening load: you load a vector of 241356843Sdim// small things out of memory, and then zext/sext them into a full 128-bit 242356843Sdim// output vector.) 243356843Sdimclass NarrowedVecOf<Type t, Type v>: ComplexType<(CTO_Vec t, v)>; 244356843Sdim 245356843Sdim// PredOf expects t to be a scalar, and expands to a predicate vector which 246356843Sdim// (logically speaking) has the same number of lanes as VecOf<t> would. 247356843Sdimclass PredOf<Type t>: ComplexType<(CTO_Pred t)>; 248356843Sdim 249356843Sdim// Scalar expands to whatever is the main parameter type of the current 250356843Sdim// intrinsic. Vector and Predicate expand to the vector and predicate types 251356843Sdim// corresponding to that. 252356843Sdimdef Scalar: ComplexType<(CTO_Parameter)>; 253356843Sdimdef Vector: VecOf<Scalar>; 254356843Sdimdef Predicate: PredOf<Scalar>; 255356843Sdim 256356843Sdim// MultiVector<n> expands to a type containing n instances of Vector. (There's 257356843Sdim// no need to define this for a general underlying vector type, since it's only 258356843Sdim// used by vld2q and friends, which don't need that generality.) 259356843Sdimclass MultiVector<int n>: ComplexType<(CTO_Tuple<n> Vector)>; 260356843Sdim 261356843Sdim// Ptr<t> and CPtr<t> expand to a pointer to t, or a pointer to const t, 262356843Sdim// respectively. 263356843Sdimclass Ptr<Type t>: ComplexType<(CTO_Pointer<0> t)>; 264356843Sdimclass CPtr<Type t>: ComplexType<(CTO_Pointer<1> t)>; 265356843Sdim 266356843Sdim// CopyKind<s,k> expects s and k to be scalar types. It returns a scalar type 267356843Sdim// whose kind (signed, unsigned or float) matches that of k, and whose size 268356843Sdim// matches that of s. 269356843Sdimclass CopyKind<Type s, Type k>: ComplexType<(CTO_CopyKind s, k)>; 270356843Sdim 271356843Sdim// DoubleSize<k> expects k to be a scalar type. It returns a scalar type 272356843Sdim// whose kind (signed, unsigned or float) matches that of k, and whose size 273356843Sdim// is double that of k, if possible. 274356843Sdimclass DoubleSize<Type k> : ComplexType<(CTO_ScaleSize<2, 1> k)>; 275356843Sdimclass HalfSize<Type k> : ComplexType<(CTO_ScaleSize<1, 2> k)>; 276356843Sdim 277356843Sdim// Unsigned<t> expects t to be a scalar type, and expands to the unsigned 278356843Sdim// integer scalar of the same size. So it returns u16 if you give it s16 or 279356843Sdim// f16 (or u16 itself). Similarly, Signed<t> makes the type signed. 280356843Sdimclass Unsigned<Type t>: ComplexType<(CTO_CopyKind t, u32)>; 281356843Sdimclass Signed<Type t>: ComplexType<(CTO_CopyKind t, s32)>; 282356843Sdim 283356843Sdim// UScalar and UVector expand to the unsigned-integer versions of 284356843Sdim// Scalar and Vector. SScalar and SVector are signed-integer versions. 285356843Sdimdef UScalar: Unsigned<Scalar>; 286356843Sdimdef UVector: VecOf<UScalar>; 287356843Sdimdef SScalar: Signed<Scalar>; 288356843Sdimdef SVector: VecOf<SScalar>; 289356843Sdim 290356843Sdim// DblVector expands to a vector of scalars of size twice the size of Scalar. 291356843Sdim// HalfVector, similarly, expands to a vector of half-sized scalars. And 292356843Sdim// UHalfVector is a vector of half-sized _unsigned integers_. 293356843Sdimdef DblVector: VecOf<DoubleSize<Scalar>>; 294356843Sdimdef HalfVector: VecOf<HalfSize<Scalar>>; 295356843Sdimdef UHalfVector: VecOf<Unsigned<HalfSize<Scalar>>>; 296356843Sdim 297356843Sdim// Expands to the 32-bit integer of the same signedness as Scalar. 298356843Sdimdef Scalar32: CopyKind<u32, Scalar>; 299356843Sdim// Expands to the 64-bit integer of the same signedness as Scalar. 300356843Sdimdef Scalar64: CopyKind<u64, Scalar>; 301356843Sdim 302356843Sdim// ----------------------------------------------------------------------------- 303356843Sdim// Internal definitions for specifying immediate arguments for an intrinsic. 304356843Sdim 305356843Sdimclass ImmediateBounds; 306356843Sdimclass Immediate<Type type_, ImmediateBounds bounds_>: Type { 307356843Sdim Type type = type_; 308356843Sdim ImmediateBounds bounds = bounds_; 309356843Sdim string extra; 310356843Sdim string extraarg; 311356843Sdim} 312356843Sdimclass IB_ConstRange<int lo_, int hi_> : ImmediateBounds { 313356843Sdim int lo = lo_; 314356843Sdim int hi = hi_; 315356843Sdim} 316356843Sdimdef IB_UEltValue : ImmediateBounds; 317356843Sdimdef IB_LaneIndex : ImmediateBounds; 318356843Sdimclass IB_EltBit<int base_, Type type_ = Scalar> : ImmediateBounds { 319356843Sdim int base = base_; 320356843Sdim Type type = type_; 321356843Sdim} 322356843Sdim 323356843Sdim// ----------------------------------------------------------------------------- 324356843Sdim// End-user definitions for immediate arguments. 325356843Sdim 326356843Sdim// imm_simd and imm_simd_restrictive are used for the immediate operands to 327356843Sdim// intrinsics like vmvnq or vorrq. imm_simd_restrictive has to be an 8-bit 328356843Sdim// value shifted left by a whole number of bytes; imm_simd_vmvn can also be of 329356843Sdim// the form 0xXXFF for some byte value XX. 330356843Sdimdef imm_simd_restrictive : Immediate<u32, IB_UEltValue> { 331356843Sdim let extra = "ShiftedByte"; 332356843Sdim} 333356843Sdimdef imm_simd_vmvn : Immediate<u32, IB_UEltValue> { 334356843Sdim let extra = "ShiftedByteOrXXFF"; 335356843Sdim} 336356843Sdim 337356843Sdim// imm_1toN can take any value from 1 to N inclusive, where N is the number of 338356843Sdim// bits in the main parameter type. (E.g. an immediate shift count, in an 339356843Sdim// intrinsic that shifts every lane of a vector by the same amount.) 340356843Sdim// 341356843Sdim// imm_0toNm1 is the same but with the range offset by 1, i.e. 0 to N-1 342356843Sdim// inclusive. 343356843Sdim// 344356843Sdim// imm_1toHalfN is like imm_1toN, but applied to a half-width type. 345356843Sdim// (So if Scalar is s16, for example, it'll give you the range 1 to 8.) 346356843Sdimdef imm_1toN : Immediate<sint, IB_EltBit<1>>; 347356843Sdimdef imm_0toNm1 : Immediate<sint, IB_EltBit<0>>; 348356843Sdimdef imm_1toHalfN : Immediate<sint, IB_EltBit<1, HalfSize<Scalar>>>; 349356843Sdim 350356843Sdim// imm_lane has to be the index of a vector lane in the main vector type, i.e 351356843Sdim// it can range from 0 to (128 / size of scalar)-1 inclusive. (e.g. vgetq_lane) 352356843Sdimdef imm_lane : Immediate<sint, IB_LaneIndex>; 353356843Sdim 354356843Sdim// imm_1to32 can be in the range 1 to 32, unconditionally. (e.g. scalar shift 355356843Sdim// intrinsics) 356356843Sdimdef imm_1to32 : Immediate<sint, IB_ConstRange<1, 32>>; 357356843Sdim 358356843Sdim// imm_1248 can be 1, 2, 4 or 8. (e.g. vidupq) 359356843Sdimdef imm_1248 : Immediate<u32, IB_ConstRange<1, 8>> { 360356843Sdim let extra = "Power2"; 361356843Sdim} 362356843Sdim 363356843Sdim// imm_mem7bit<n> is a valid immediate offset for a load/store intrinsic whose 364356843Sdim// memory access size is n bytes (e.g. 1 for vldrb_[whatever], 2 for vldrh, 365356843Sdim// ...). The set of valid immediates for these is {-127*n, ..., -1*n, 0*n, 1*n, 366356843Sdim// ..., 127*n}. 367356843Sdimclass imm_mem7bit<int membytes> 368356843Sdim : Immediate<sint, IB_ConstRange<!mul(membytes, -127), !mul(membytes, 127)>> { 369356843Sdim let extra = !if(!eq(membytes, 1), ?, "Multiple"); 370356843Sdim let extraarg = !cast<string>(membytes); 371356843Sdim} 372356843Sdim 373356843Sdim// ----------------------------------------------------------------------------- 374356843Sdim// Specification of ways that the full name of an intrinsic can be mapped to 375356843Sdim// its shorter polymorphic name. 376356843Sdim 377356843Sdimclass PolymorphicNameType<int nt_, string x_> { 378356843Sdim int NumTypeSuffixesToDiscard = nt_; 379356843Sdim string ExtraSuffixToDiscard = x_; 380356843Sdim} 381356843Sdim 382356843Sdim// PNT_None: the intrinsic is not polymorphic at all, so its short name is the 383356843Sdim// same as its long name. (E.g. scalar shift intrinsics such as uqshl.) 384356843Sdimdef PNT_None: PolymorphicNameType<0, ?>; 385356843Sdim 386356843Sdim// PNT_Type: the usual case, in which the polymorphic name is made by dropping 387356843Sdim// the type suffix, so it ends up the same as the Tablegen record name. E.g. 388356843Sdim// vaddq_u16 -> vaddq. 389356843Sdimdef PNT_Type: PolymorphicNameType<1, ?>; 390356843Sdim 391356843Sdim// PNT_2Type: the polymorphic name is made by dropping _two_ type suffixes. 392356843Sdim// E.g. vcvtq_f16_u16 -> vcvtq. 393356843Sdimdef PNT_2Type: PolymorphicNameType<2, ?>; 394356843Sdim 395356843Sdim// PNT_NType: the polymorphic name is made by dropping an "_n" suffix and a 396356843Sdim// type. E.g. vaddq_n_u16 -> vaddq. 397356843Sdimdef PNT_NType: PolymorphicNameType<1, "n">; 398356843Sdim 399356843Sdim// PNT_NType: the polymorphic name is made by just dropping an "_n" suffix 400356843Sdim// (even if it isn't at the end of the name). E.g. vidupq_n_u16 -> vidupq_u16. 401356843Sdimdef PNT_N: PolymorphicNameType<0, "n">; 402356843Sdim 403356843Sdim// PNT_WBType: the polymorphic name is made by dropping an "_wb" suffix and a 404356843Sdim// type. E.g. vidupq_m_wb_u16 -> vidupq_m. 405356843Sdimdef PNT_WBType: PolymorphicNameType<1, "wb">; 406356843Sdim 407356843Sdim// PNT_WB: the polymorphic name is made by just dropping "_wb". E.g. 408356843Sdim// vidupq_wb_u16 -> vidupq_u16. 409356843Sdimdef PNT_WB: PolymorphicNameType<0, "wb">; 410356843Sdim 411356843Sdim// ----------------------------------------------------------------------------- 412356843Sdim// The main class Intrinsic. Define one of these for each family of ACLE 413356843Sdim// intrinsics which are the same apart from some final type suffix (e.g. 414356843Sdim// vaddq_{s8,u8,f16,...}. 415356843Sdim// 416356843Sdim// The record's name plus that type suffix is taken to be the full unambiguous 417356843Sdim// name of the function. Its shorter polymorphic name is constructed from that 418356843Sdim// in turn, in a way specified by the PolymorphicNameType system above. 419356843Sdim 420356843Sdimclass Intrinsic<Type ret_, dag args_, dag codegen_> { 421356843Sdim // List of parameter types to suffix to this intrinsic's name. A separate 422356843Sdim // actual ACLE intrinsic will be generated for each of these. Set it to 423356843Sdim // [Void] if the intrinsic is not polymorphic at all. 424356843Sdim list<Type> params; 425356843Sdim 426356843Sdim // Return type and arguments for the intrinsic. 427356843Sdim Type ret = ret_; 428356843Sdim dag args = args_; 429356843Sdim 430356843Sdim // Specification of how to generate its IR. 431356843Sdim dag codegen = codegen_; 432356843Sdim 433356843Sdim // Default to PNT_Type, which is by far the most common case. 434356843Sdim PolymorphicNameType pnt = PNT_Type; 435356843Sdim 436356843Sdim // A very few intrinsics _only_ have a polymorphic name. 437356843Sdim bit polymorphicOnly = 0; 438356843Sdim 439356843Sdim // True if the builtin has to avoid evaluating its arguments. 440356843Sdim bit nonEvaluating = 0; 441356843Sdim 442356843Sdim // Use to override the suffix letter to make e.g.vfooq_p16 443356843Sdim // with an override suffix letter of "p". 444356843Sdim string overrideKindLetter = ""; 445356843Sdim} 446356843Sdim 447356843Sdim// Sometimes you have to use two separate Intrinsic declarations to 448356843Sdim// declare intrinsics that are logically the same family (e.g. vaddq, 449356843Sdim// because it needs to expand to an Add or FAdd IR node depending on 450356843Sdim// type). For that purpose, you can derive from NameOverride to 451356843Sdim// specify the intrinsic's base name independently of the Tablegen 452356843Sdim// record name. 453356843Sdim 454356843Sdimclass NameOverride<string basename_> { 455356843Sdim string basename = basename_; 456356843Sdim} 457356843Sdim 458356843Sdim// A wrapper to define both _m and _x versions of a predicated 459356843Sdim// intrinsic. 460356843Sdimmulticlass IntrinsicMX<Type rettype, dag arguments, dag cg, 461356843Sdim int wantXVariant = 1, 462356843Sdim string nameSuffix = "", 463356843Sdim PolymorphicNameType pnt_x = PNT_Type> { 464356843Sdim // The _m variant takes an initial parameter called $inactive, which 465356843Sdim // provides the input value of the output register, i.e. all the 466356843Sdim // inactive lanes in the predicated operation take their values from 467356843Sdim // this. 468356843Sdim def "_m" # nameSuffix: 469356843Sdim Intrinsic<rettype, !con((args rettype:$inactive), arguments), cg>; 470356843Sdim 471356843Sdim foreach unusedVar = !if(!eq(wantXVariant, 1), [1], []<int>) in { 472356843Sdim // The _x variant leaves off that parameter, and simply uses an 473356843Sdim // undef value of the same type. 474356843Sdim def "_x" # nameSuffix: 475356843Sdim Intrinsic<rettype, arguments, (seq (undef rettype):$inactive, cg)> { 476356843Sdim // Allow overriding of the polymorphic name type, because 477356843Sdim // sometimes the _m and _x variants polymorph differently 478356843Sdim // (typically because the type of the inactive parameter can be 479356843Sdim // used as a disambiguator if it's present). 480356843Sdim let pnt = pnt_x; 481356843Sdim } 482356843Sdim } 483356843Sdim} 484356843Sdim 485356843Sdim// ----------------------------------------------------------------------------- 486356843Sdim// Convenience lists of parameter types. 'T' is just a container record, so you 487356843Sdim// can define a typical intrinsic with 'let Params = T.Usual', or similar, 488356843Sdim// instead of having to repeat a long list every time. 489356843Sdim 490356843Sdimdef T { 491356843Sdim list<Type> Signed = [s8, s16, s32]; 492356843Sdim list<Type> Unsigned = [u8, u16, u32]; 493356843Sdim list<Type> Int = Signed # Unsigned; 494356843Sdim list<Type> Float = [f16, f32]; 495356843Sdim list<Type> Usual = Int # Float; 496356843Sdim list<Type> Int8 = [s8, u8]; 497356843Sdim list<Type> Int16 = [s16, u16]; 498356843Sdim list<Type> Int32 = [s32, u32]; 499356843Sdim list<Type> Int64 = [s64, u64]; 500356843Sdim list<Type> Poly = [u8, u16]; // Actually p8 and p16 501356843Sdim list<Type> All8 = Int8; 502356843Sdim list<Type> All16 = Int16 # [f16]; 503356843Sdim list<Type> All32 = Int32 # [f32]; 504356843Sdim list<Type> All64 = Int64; 505356843Sdim list<Type> All = Usual # All64; 506356843Sdim} 507356843Sdim 508356843Sdim// ----------------------------------------------------------------------------- 509356843Sdim// Container record for DAG constant values. These constants are used because 510356843Sdim// bit/int class/multiclass parameters cannot be used to produce a dag node: 511356843Sdim// for example (u32 x) where x is 0 is transformed into (u32 { 0 }) by the 512356843Sdim// Tablegen parser. 513356843Sdimdef V { 514356843Sdim dag False = (u32 0); 515356843Sdim dag True = (u32 1); 516356843Sdim} 517