1//===- arm_mve_defs.td - definitions and infrastructure for arm_mve.td ----===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// The definitions in this file are designed to work in close conjunction with 10// clang/utils/TableGen/MveEmitter.cpp. Comments in there will probably be 11// useful as well. 12// 13//===----------------------------------------------------------------------===// 14 15// ----------------------------------------------------------------------------- 16// Forward declarations. 17class Type; 18 19// ----------------------------------------------------------------------------- 20// Dummy record used as the dag operator for the argument list of an intrinsic. 21// 22// We store arguments as a dag rather than a list<Type> so that we can give 23// each one a name, to be used in codegen. For example, (args Vector:$a, 24// Scalar:$b) defines the names $a and $b which the specification of the code 25// for that intrinsic can refer to. 26 27def args; 28 29// ----------------------------------------------------------------------------- 30// Family of nodes for use in the codegen dag for an intrinsic, corresponding 31// to function calls that return LLVM IR nodes. 32class IRBuilderParam<int index_> { int index = index_; } 33class IRBuilderAddrParam<int index_> : IRBuilderParam<index_>; 34class IRBuilderIntParam<int index_, string type_> : IRBuilderParam<index_> { 35 string type = type_; 36} 37class IRBuilderBase { 38 // The prefix of the function call, including an open parenthesis. 39 string prefix; 40 41 // Any parameters that have types that have to be treated specially by the 42 // Tablegen back end. Generally these will be types other than llvm::Value *, 43 // although not all other types need special treatment (e.g. llvm::Type *). 44 list<IRBuilderParam> special_params = []; 45} 46class IRBuilder<string func> : IRBuilderBase { 47 // The usual case: a method called on the code gen function's instance of 48 // llvm::IRBuilder. 49 let prefix = "Builder." # func # "("; 50} 51class IRFunction<string func> : IRBuilderBase { 52 // Some other function that doesn't use the IRBuilder at all. 53 let prefix = func # "("; 54} 55class CGHelperFn<string func> : IRBuilderBase { 56 // A helper function defined in CGBuiltin.cpp, which takes the IRBuilder as 57 // an argument. 58 let prefix = func # "(Builder, "; 59} 60class CGFHelperFn<string func> : IRBuilderBase { 61 // Like CGHelperFn, but also takes the CodeGenFunction itself. 62 let prefix = func # "(Builder, this, "; 63} 64def add: IRBuilder<"CreateAdd">; 65def mul: IRBuilder<"CreateMul">; 66def not: IRBuilder<"CreateNot">; 67def or: IRBuilder<"CreateOr">; 68def and: IRBuilder<"CreateAnd">; 69def xor: IRBuilder<"CreateXor">; 70def sub: IRBuilder<"CreateSub">; 71def shl: IRBuilder<"CreateShl">; 72def lshr: IRBuilder<"CreateLShr">; 73def immshr: CGHelperFn<"MVEImmediateShr"> { 74 let special_params = [IRBuilderIntParam<1, "unsigned">, 75 IRBuilderIntParam<2, "bool">]; 76} 77def fadd: IRBuilder<"CreateFAdd">; 78def fmul: IRBuilder<"CreateFMul">; 79def fsub: IRBuilder<"CreateFSub">; 80def load: IRBuilder<"CreateLoad"> { 81 let special_params = [IRBuilderAddrParam<0>]; 82} 83def store: IRBuilder<"CreateStore"> { 84 let special_params = [IRBuilderAddrParam<1>]; 85} 86def xval: IRBuilder<"CreateExtractValue"> { 87 let special_params = [IRBuilderIntParam<1, "unsigned">]; 88} 89def ielt_const: IRBuilder<"CreateInsertElement"> { 90 let special_params = [IRBuilderIntParam<2, "uint64_t">]; 91} 92def ielt_var: IRBuilder<"CreateInsertElement">; 93def xelt_var: IRBuilder<"CreateExtractElement">; 94def trunc: IRBuilder<"CreateTrunc">; 95def bitcast: IRBuilder<"CreateBitCast">; 96def vreinterpret: CGFHelperFn<"ARMMVEVectorReinterpret">; 97def extend: CGHelperFn<"SignOrZeroExtend"> { 98 let special_params = [IRBuilderIntParam<2, "bool">]; 99} 100def zeroinit: IRFunction<"llvm::Constant::getNullValue">; 101def int_min: CGHelperFn<"ARMMVEConstantSplat<1,0>">; 102def int_max: CGHelperFn<"ARMMVEConstantSplat<0,1>">; 103def uint_max: CGHelperFn<"ARMMVEConstantSplat<1,1>">; 104def undef: IRFunction<"UndefValue::get">; 105def icmp_eq: IRBuilder<"CreateICmpEQ">; 106def icmp_ne: IRBuilder<"CreateICmpNE">; 107def icmp_ugt: IRBuilder<"CreateICmpUGT">; 108def icmp_uge: IRBuilder<"CreateICmpUGE">; 109def icmp_ult: IRBuilder<"CreateICmpULT">; 110def icmp_ule: IRBuilder<"CreateICmpULE">; 111def icmp_sgt: IRBuilder<"CreateICmpSGT">; 112def icmp_sge: IRBuilder<"CreateICmpSGE">; 113def icmp_slt: IRBuilder<"CreateICmpSLT">; 114def icmp_sle: IRBuilder<"CreateICmpSLE">; 115def fcmp_eq: IRBuilder<"CreateFCmpOEQ">; 116def fcmp_ne: IRBuilder<"CreateFCmpUNE">; // not O: it must return true on NaNs 117def fcmp_gt: IRBuilder<"CreateFCmpOGT">; 118def fcmp_ge: IRBuilder<"CreateFCmpOGE">; 119def fcmp_lt: IRBuilder<"CreateFCmpOLT">; 120def fcmp_le: IRBuilder<"CreateFCmpOLE">; 121def splat: CGHelperFn<"ARMMVEVectorSplat">; 122def select: IRBuilder<"CreateSelect">; 123def fneg: IRBuilder<"CreateFNeg">; 124def sitofp: IRBuilder<"CreateSIToFP">; 125def uitofp: IRBuilder<"CreateUIToFP">; 126def fptosi: IRBuilder<"CreateFPToSI">; 127def fptoui: IRBuilder<"CreateFPToUI">; 128def vrev: CGHelperFn<"ARMMVEVectorElementReverse"> { 129 let special_params = [IRBuilderIntParam<1, "unsigned">]; 130} 131def unzip: CGHelperFn<"VectorUnzip"> { 132 let special_params = [IRBuilderIntParam<1, "bool">]; 133} 134def zip: CGHelperFn<"VectorZip">; 135 136// Trivial 'codegen' function that just returns its argument. Useful 137// for wrapping up a variable name like $foo into a thing you can pass 138// around as type 'dag'. 139def id: IRBuilderBase { 140 // All the other cases of IRBuilderBase use 'prefix' to specify a function 141 // call, including the open parenthesis. MveEmitter puts the closing paren on 142 // the end. So if we _just_ specify an open paren with no function name 143 // before it, then the generated C++ code will simply wrap the input value in 144 // parentheses, returning it unchanged. 145 let prefix = "("; 146} 147 148// Helper for making boolean flags in IR 149def i1: IRBuilderBase { 150 let prefix = "llvm::ConstantInt::get(Builder.getInt1Ty(), "; 151 let special_params = [IRBuilderIntParam<0, "bool">]; 152} 153 154// A node that makes an Address out of a pointer-typed Value, by 155// providing an alignment as the second argument. 156def address; 157 158// Another node class you can use in the codegen dag. This one corresponds to 159// an IR intrinsic function, which has to be specialized to a particular list 160// of types. 161class IRIntBase<string name_, list<Type> params_ = [], bit appendKind_ = 0> { 162 string intname = name_; // base name of the intrinsic 163 list<Type> params = params_; // list of parameter types 164 165 // If this flag is set, then the IR intrinsic name will get a suffix _s, _u 166 // or _f depending on whether the main parameter type of the ACLE intrinsic 167 // being generated is a signed integer, unsigned integer, or float. Mostly 168 // this is useful for signed vs unsigned integers, because the ACLE 169 // intrinsics and the source-level integer types distinguish them, but at IR 170 // level the distinction has moved from the type system into the operations 171 // and you just have i32 or i16 etc. So when an IR intrinsic has to vary with 172 // signedness, you set this bit, and then you can still put the signed and 173 // unsigned versions in the same subclass of Intrinsic, and the Tablegen 174 // backend will take care of adding _s or _u as appropriate in each instance. 175 bit appendKind = appendKind_; 176} 177 178// Mostly we'll be using @llvm.arm.mve.* intrinsics, so here's a trivial 179// subclass that puts on that prefix. 180class IRInt<string name, list<Type> params = [], bit appendKind = 0> 181 : IRIntBase<"arm_mve_" # name, params, appendKind>; 182 183// The 'seq' node in a codegen dag specifies a set of IR operations to be 184// performed in order. It has the special ability to define extra variable 185// names, on top of the ones that refer to the intrinsic's parameters. For 186// example: 187// 188// (seq (foo this, that):$a, 189// (bar this, $a):$b 190// (add $a, $b)) 191// 192// defines the name $a to refer to the return value of the 'foo' operation; 193// then the 'bar' operation uses $a as one of its arguments, and the return 194// value of that is assigned the name $b; finally, $a and $b are added to give 195// the return value of the seq construction as a whole. 196def seq; 197 198// Another magic operation is 'unsignedflag', which you give a scalar 199// _type_ as an argument, and it expands into 1 for an unsigned type 200// and 0 for a signed (or floating) one. 201def unsignedflag; 202 203// 'bitsize' also takes a scalar type, and expands into an integer 204// constant giving its size in bits. 205def bitsize; 206 207// If you put CustomCodegen<"foo"> in an intrinsic's codegen field, it 208// indicates that the IR generation for that intrinsic is done by handwritten 209// C++ and not autogenerated at all. The effect in the MVE builtin codegen 210// function is to break out of the main switch and fall through to the 211// manual-codegen cases below it, having set the CustomCodeGenType enumerated 212// variable to the value given by the 'type' string here. 213class CustomCodegen<string type_> { string type = type_; } 214 215// ----------------------------------------------------------------------------- 216// System for building up complex instances of Type from simple ones. 217 218// ComplexType is used to represent any more complicated type: vectors, 219// multivectors, pointers etc. Its dag argument specifies how the type should 220// be constructed from simpler types. The operator of the dag will always be an 221// instance of ComplexTypeOp, defined below. 222class ComplexType<dag spec_>: Type { dag spec = spec_; } 223 224// Operators you can use in the ComplexType spec dag. These are an intermediate 225// layer, interpreted by MveEmitter::getType() in the Tablegen backend, and 226// only used in the definitions below. Actual intrinsic definitions in 227// arm_mve.td will use the defs defined below here. 228class ComplexTypeOp; 229def CTO_Parameter: ComplexTypeOp; 230def CTO_Vec: ComplexTypeOp; 231def CTO_Pred: ComplexTypeOp; 232class CTO_Tuple<int n_>: ComplexTypeOp { int n = n_; } 233class CTO_Pointer<bit const_>: ComplexTypeOp { bit const = const_; } 234def CTO_CopyKind: ComplexTypeOp; 235class CTO_ScaleSize<int num_, int denom_>: ComplexTypeOp { 236 int num = num_; 237 int denom = denom_; 238} 239 240// ----------------------------------------------------------------------------- 241// Instances of Type intended to be used directly in the specification of an 242// intrinsic in arm_mve.td. 243 244// The type Void can be used for the return type of an intrinsic, and as the 245// parameter type for intrinsics that aren't actually parameterised by any kind 246// of _s32 / _f16 / _u8 suffix. 247def Void : Type; 248 249// A wrapper you can put on an intrinsic's argument type to prevent it from 250// being automatically promoted to i32 from a smaller integer type. 251class unpromoted<Type t> : Type { Type underlying_type = t; } 252 253// Primitive types: base class, and an instance for the set of scalar integer 254// and floating types that MVE uses. 255class PrimitiveType<string kind_, int size_>: Type { 256 string kind = kind_; 257 int size = size_; 258 string nameOverride = ""; 259} 260 261// The type records defined by these foreaches have names like s32, f16, u8. 262foreach size = [8, 16, 32, 64] in 263 foreach kind = ["u", "s"] in 264 def kind # size: PrimitiveType<kind, size>; 265foreach size = [16, 32] in 266 foreach kind = ["f"] in 267 def kind # size: PrimitiveType<kind, size>; 268 269// Sometimes we need to refer to a type by a different name in C, when 270// ACLE defines a function parameter to be something like 'unsigned' 271// rather than uint32_t. 272def uint: PrimitiveType<"u", 32> { let nameOverride = "unsigned"; } 273def sint: PrimitiveType<"s", 32> { let nameOverride = "int"; } 274 275// VecOf<t> expects t to be a scalar, and gives a 128-bit vector of whatever it 276// is. 277class VecOf<Type t>: ComplexType<(CTO_Vec t)>; 278 279// NarrowedVecOf<t,v> expects t to be a scalar type, and v to be a vector 280// type. It returns a vector type whose element type is t, and whose lane 281// count is the same as the lane count of v. (Used as an intermediate value 282// type in the IR representation of a widening load: you load a vector of 283// small things out of memory, and then zext/sext them into a full 128-bit 284// output vector.) 285class NarrowedVecOf<Type t, Type v>: ComplexType<(CTO_Vec t, v)>; 286 287// PredOf expects t to be a scalar, and expands to a predicate vector which 288// (logically speaking) has the same number of lanes as VecOf<t> would. 289class PredOf<Type t>: ComplexType<(CTO_Pred t)>; 290 291// Scalar expands to whatever is the main parameter type of the current 292// intrinsic. Vector and Predicate expand to the vector and predicate types 293// corresponding to that. 294def Scalar: ComplexType<(CTO_Parameter)>; 295def Vector: VecOf<Scalar>; 296def Predicate: PredOf<Scalar>; 297 298// MultiVector<n> expands to a type containing n instances of Vector. (There's 299// no need to define this for a general underlying vector type, since it's only 300// used by vld2q and friends, which don't need that generality.) 301class MultiVector<int n>: ComplexType<(CTO_Tuple<n> Vector)>; 302 303// Ptr<t> and CPtr<t> expand to a pointer to t, or a pointer to const t, 304// respectively. 305class Ptr<Type t>: ComplexType<(CTO_Pointer<0> t)>; 306class CPtr<Type t>: ComplexType<(CTO_Pointer<1> t)>; 307 308// CopyKind<s,k> expects s and k to be scalar types. It returns a scalar type 309// whose kind (signed, unsigned or float) matches that of k, and whose size 310// matches that of s. 311class CopyKind<Type s, Type k>: ComplexType<(CTO_CopyKind s, k)>; 312 313// DoubleSize<k> expects k to be a scalar type. It returns a scalar type 314// whose kind (signed, unsigned or float) matches that of k, and whose size 315// is double that of k, if possible. 316class DoubleSize<Type k> : ComplexType<(CTO_ScaleSize<2, 1> k)>; 317class HalfSize<Type k> : ComplexType<(CTO_ScaleSize<1, 2> k)>; 318 319// Unsigned<t> expects t to be a scalar type, and expands to the unsigned 320// integer scalar of the same size. So it returns u16 if you give it s16 or 321// f16 (or u16 itself). Similarly, Signed<t> makes the type signed. 322class Unsigned<Type t>: ComplexType<(CTO_CopyKind t, u32)>; 323class Signed<Type t>: ComplexType<(CTO_CopyKind t, s32)>; 324 325// UScalar and UVector expand to the unsigned-integer versions of 326// Scalar and Vector. SScalar and SVector are signed-integer versions. 327def UScalar: Unsigned<Scalar>; 328def UVector: VecOf<UScalar>; 329def SScalar: Signed<Scalar>; 330def SVector: VecOf<SScalar>; 331 332// DblVector expands to a vector of scalars of size twice the size of Scalar. 333// DblPredicate expands to a predicate corresponding to DblVector 334// HalfVector, similarly, expands to a vector of half-sized scalars. And 335// UHalfVector is a vector of half-sized _unsigned integers_. 336def DblVector: VecOf<DoubleSize<Scalar>>; 337def DblPredicate: PredOf<DoubleSize<Scalar>>; 338def HalfScalar: HalfSize<Scalar>; 339def HalfVector: VecOf<HalfScalar>; 340def UHalfScalar: Unsigned<HalfSize<Scalar>>; 341def UHalfVector: VecOf<UHalfScalar>; 342 343// Expands to the 32-bit integer of the same signedness as Scalar. 344def Scalar32: CopyKind<u32, Scalar>; 345// Expands to the 64-bit integer of the same signedness as Scalar. 346def Scalar64: CopyKind<u64, Scalar>; 347 348// ----------------------------------------------------------------------------- 349// Internal definitions for specifying immediate arguments for an intrinsic. 350 351class ImmediateBounds; 352class Immediate<Type type_, ImmediateBounds bounds_>: Type { 353 Type type = type_; 354 ImmediateBounds bounds = bounds_; 355 string extra; 356 string extraarg; 357} 358class IB_ConstRange<int lo_, int hi_> : ImmediateBounds { 359 int lo = lo_; 360 int hi = hi_; 361} 362def IB_UEltValue : ImmediateBounds; 363def IB_LaneIndex : ImmediateBounds; 364class IB_EltBit<int base_, Type type_ = Scalar> : ImmediateBounds { 365 int base = base_; 366 Type type = type_; 367} 368def IB_ExtraArg_LaneSize; 369 370// ----------------------------------------------------------------------------- 371// End-user definitions for immediate arguments. 372 373// imm_simd and imm_simd_restrictive are used for the immediate operands to 374// intrinsics like vmvnq or vorrq. imm_simd_restrictive has to be an 8-bit 375// value shifted left by a whole number of bytes; imm_simd_vmvn can also be of 376// the form 0xXXFF for some byte value XX. 377def imm_simd_restrictive : Immediate<Scalar, IB_UEltValue> { 378 let extra = "ShiftedByte"; 379 let extraarg = "!lanesize"; 380} 381def imm_simd_vmvn : Immediate<Scalar, IB_UEltValue> { 382 let extra = "ShiftedByteOrXXFF"; 383 let extraarg = "!lanesize"; 384} 385 386// imm_1toN can take any value from 1 to N inclusive, where N is the number of 387// bits in the main parameter type. (E.g. an immediate shift count, in an 388// intrinsic that shifts every lane of a vector by the same amount.) 389// 390// imm_0toNm1 is the same but with the range offset by 1, i.e. 0 to N-1 391// inclusive. 392// 393// imm_1toHalfN is like imm_1toN, but applied to a half-width type. 394// (So if Scalar is s16, for example, it'll give you the range 1 to 8.) 395def imm_1toN : Immediate<sint, IB_EltBit<1>>; 396def imm_0toNm1 : Immediate<sint, IB_EltBit<0>>; 397def imm_1toHalfN : Immediate<sint, IB_EltBit<1, HalfSize<Scalar>>>; 398 399// imm_lane has to be the index of a vector lane in the main vector type, i.e 400// it can range from 0 to (128 / size of scalar)-1 inclusive. (e.g. vgetq_lane) 401def imm_lane : Immediate<sint, IB_LaneIndex>; 402 403// imm_1to32 can be in the range 1 to 32, unconditionally. (e.g. scalar shift 404// intrinsics) 405def imm_1to32 : Immediate<sint, IB_ConstRange<1, 32>>; 406 407// imm_1248 can be 1, 2, 4 or 8. (e.g. vidupq) 408def imm_1248 : Immediate<sint, IB_ConstRange<1, 8>> { 409 let extra = "Power2"; 410} 411 412// imm_mem7bit<n> is a valid immediate offset for a load/store intrinsic whose 413// memory access size is n bytes (e.g. 1 for vldrb_[whatever], 2 for vldrh, 414// ...). The set of valid immediates for these is {-127*n, ..., -1*n, 0*n, 1*n, 415// ..., 127*n}. 416class imm_mem7bit<int membytes> 417 : Immediate<sint, IB_ConstRange<!mul(membytes, -127), !mul(membytes, 127)>> { 418 let extra = !if(!eq(membytes, 1), ?, "Multiple"); 419 let extraarg = !cast<string>(membytes); 420} 421 422// ----------------------------------------------------------------------------- 423// Specification of ways that the full name of an intrinsic can be mapped to 424// its shorter polymorphic name. 425 426class PolymorphicNameType<int nt_, string x_> { 427 int NumTypeSuffixesToDiscard = nt_; 428 string ExtraSuffixToDiscard = x_; 429} 430 431// PNT_None: the intrinsic is not polymorphic at all, so its short name is the 432// same as its long name. (E.g. scalar shift intrinsics such as uqshl.) 433def PNT_None: PolymorphicNameType<0, ?>; 434 435// PNT_Type: the usual case, in which the polymorphic name is made by dropping 436// the type suffix, so it ends up the same as the Tablegen record name. E.g. 437// vaddq_u16 -> vaddq. 438def PNT_Type: PolymorphicNameType<1, ?>; 439 440// PNT_2Type: the polymorphic name is made by dropping _two_ type suffixes. 441// E.g. vcvtq_f16_u16 -> vcvtq. 442def PNT_2Type: PolymorphicNameType<2, ?>; 443 444// PNT_NType: the polymorphic name is made by dropping an "_n" suffix and a 445// type. E.g. vaddq_n_u16 -> vaddq. 446def PNT_NType: PolymorphicNameType<1, "n">; 447 448// PNT_NType: the polymorphic name is made by just dropping an "_n" suffix 449// (even if it isn't at the end of the name). E.g. vidupq_n_u16 -> vidupq_u16. 450def PNT_N: PolymorphicNameType<0, "n">; 451 452// PNT_WBType: the polymorphic name is made by dropping an "_wb" suffix and a 453// type. E.g. vidupq_m_wb_u16 -> vidupq_m. 454def PNT_WBType: PolymorphicNameType<1, "wb">; 455 456// PNT_WB: the polymorphic name is made by just dropping "_wb". E.g. 457// vidupq_wb_u16 -> vidupq_u16. 458def PNT_WB: PolymorphicNameType<0, "wb">; 459 460// ----------------------------------------------------------------------------- 461// The main class Intrinsic. Define one of these for each family of ACLE 462// intrinsics which are the same apart from some final type suffix (e.g. 463// vaddq_{s8,u8,f16,...}. 464// 465// The record's name plus that type suffix is taken to be the full unambiguous 466// name of the function. Its shorter polymorphic name is constructed from that 467// in turn, in a way specified by the PolymorphicNameType system above. 468 469class Intrinsic<Type ret_, dag args_, dag codegen_> { 470 // List of parameter types to suffix to this intrinsic's name. A separate 471 // actual ACLE intrinsic will be generated for each of these. Set it to 472 // [Void] if the intrinsic is not polymorphic at all. 473 list<Type> params; 474 475 // Return type and arguments for the intrinsic. 476 Type ret = ret_; 477 dag args = args_; 478 479 // Specification of how to generate its IR. 480 dag codegen = codegen_; 481 482 // Default to PNT_Type, which is by far the most common case. 483 PolymorphicNameType pnt = PNT_Type; 484 485 // A very few intrinsics _only_ have a polymorphic name. 486 bit polymorphicOnly = 0; 487 488 // True if the builtin has to avoid evaluating its arguments. 489 bit nonEvaluating = 0; 490 491 // True if the intrinsic needs only the C header part (no codegen, semantic 492 // checks, etc). Used for redeclaring MVE intrinsics in the arm_cde.h header. 493 bit headerOnly = 0; 494 495 // Use to override the suffix letter to make e.g.vfooq_p16 496 // with an override suffix letter of "p". 497 string overrideKindLetter = ""; 498 499 // Name of the architecture extension, used in the Clang builtin name 500 string builtinExtension = "mve"; 501} 502 503// Sometimes you have to use two separate Intrinsic declarations to 504// declare intrinsics that are logically the same family (e.g. vaddq, 505// because it needs to expand to an Add or FAdd IR node depending on 506// type). For that purpose, you can derive from NameOverride to 507// specify the intrinsic's base name independently of the Tablegen 508// record name. 509 510class NameOverride<string basename_> { 511 string basename = basename_; 512} 513 514// A wrapper to define both _m and _x versions of a predicated 515// intrinsic. 516// 517// We provide optional parameters to override the polymorphic name 518// types separately for the _m and _x variants, because sometimes they 519// polymorph differently (typically because the type of the inactive 520// parameter can be used as a disambiguator if it's present). 521multiclass IntrinsicMX<Type rettype, dag arguments, dag cg, 522 bit wantXVariant = 1, 523 string nameSuffix = "", 524 PolymorphicNameType pnt_m = PNT_Type, 525 PolymorphicNameType pnt_x = PNT_Type> { 526 // The _m variant takes an initial parameter called $inactive, which 527 // provides the input value of the output register, i.e. all the 528 // inactive lanes in the predicated operation take their values from 529 // this. 530 def : Intrinsic<rettype, !con((args rettype:$inactive), arguments), cg>, 531 NameOverride<NAME # "_m" # nameSuffix> { 532 let pnt = pnt_m; 533 } 534 535 if wantXVariant then { 536 // The _x variant leaves off that parameter, and simply uses an 537 // undef value of the same type. 538 539 def : Intrinsic<rettype, arguments, (seq (undef rettype):$inactive, cg)>, 540 NameOverride<NAME # "_x" # nameSuffix> { 541 let pnt = pnt_x; 542 } 543 } 544} 545 546// Same as above, but with an additional parameter 'basename' which overrides 547// the C intrinsic base name 548multiclass IntrinsicMXNameOverride<Type rettype, dag arguments, dag cg, 549 string basename, bit wantXVariant = 1, 550 string nameSuffix = "", 551 PolymorphicNameType pnt_m = PNT_Type, 552 PolymorphicNameType pnt_x = PNT_Type> { 553 def "_m" # nameSuffix: 554 Intrinsic<rettype, !con((args rettype:$inactive), arguments), cg>, 555 NameOverride<basename # "_m" # nameSuffix> { 556 let pnt = pnt_m; 557 } 558 559 if wantXVariant then { 560 def "_x" # nameSuffix: 561 Intrinsic<rettype, arguments, (seq (undef rettype):$inactive, cg)>, 562 NameOverride<basename # "_x" # nameSuffix> { 563 let pnt = pnt_x; 564 } 565 } 566} 567 568 569// ----------------------------------------------------------------------------- 570// Convenience lists of parameter types. 'T' is just a container record, so you 571// can define a typical intrinsic with 'let Params = T.Usual', or similar, 572// instead of having to repeat a long list every time. 573 574def T { 575 list<Type> None = [Void]; 576 list<Type> Signed = [s8, s16, s32]; 577 list<Type> Unsigned = [u8, u16, u32]; 578 list<Type> Int = Signed # Unsigned; 579 list<Type> Float = [f16, f32]; 580 list<Type> Usual = Int # Float; 581 list<Type> Int8 = [s8, u8]; 582 list<Type> Int16 = [s16, u16]; 583 list<Type> Int32 = [s32, u32]; 584 list<Type> Int64 = [s64, u64]; 585 list<Type> Poly = [u8, u16]; // Actually p8 and p16 586 list<Type> All8 = Int8; 587 list<Type> All16 = Int16 # [f16]; 588 list<Type> All32 = Int32 # [f32]; 589 list<Type> All64 = Int64; 590 list<Type> All = Usual # All64; 591} 592 593// ----------------------------------------------------------------------------- 594// Container record for DAG constant values. These constants are used because 595// bit/int class/multiclass parameters cannot be used to produce a dag node: 596// for example (u32 x) where x is 0 is transformed into (u32 { 0 }) by the 597// Tablegen parser. 598def V { 599 dag False = (u32 0); 600 dag True = (u32 1); 601} 602