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