1//==------ riscv_vector_common.td - RISC-V V-ext builtin class ------------===//
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// This file defines RVV builtin base class for RISC-V V-extension.
10//
11//===----------------------------------------------------------------------===//
12
13//===----------------------------------------------------------------------===//
14// Instruction definitions
15//===----------------------------------------------------------------------===//
16// Each record of the class RVVBuiltin defines a collection of builtins (i.e.
17// "def vadd : RVVBuiltin" will be used to define things like "vadd_vv_i32m1",
18// "vadd_vv_i32m2", etc).
19//
20// The elements of this collection are defined by an instantiation process the
21// range of which is specified by the cross product of the LMUL attribute and
22// every element in the attribute TypeRange. By default builtins have LMUL = [1,
23// 2, 4, 8, 1/2, 1/4, 1/8] so the process is repeated 7 times. In tablegen we
24// use the Log2LMUL [0, 1, 2, 3, -1, -2, -3] to represent the LMUL.
25//
26// LMUL represents the fact that the types of values used by that builtin are
27// values generated by instructions that are executed under that LMUL. However,
28// this does not mean the builtin is necessarily lowered into an instruction
29// that executes under the specified LMUL. An example where this happens are
30// loads and stores of masks. A mask like `vbool8_t` can be generated, for
31// instance, by comparing two `__rvv_int8m1_t` (this is LMUL=1) or comparing two
32// `__rvv_int16m2_t` (this is LMUL=2). The actual load or store, however, will
33// be performed under LMUL=1 because mask registers are not grouped.
34//
35// TypeRange is a non-empty sequence of basic types:
36//
37//   c: int8_t (i8)
38//   s: int16_t (i16)
39//   i: int32_t (i32)
40//   l: int64_t (i64)
41//   x: float16_t (half)
42//   f: float32_t (float)
43//   d: float64_t (double)
44//
45// This way, given an LMUL, a record with a TypeRange "sil" will cause the
46// definition of 3 builtins. Each type "t" in the TypeRange (in this example
47// they are int16_t, int32_t, int64_t) is used as a parameter that drives the
48// definition of that particular builtin (for the given LMUL).
49//
50// During the instantiation, types can be transformed or modified using type
51// transformers. Given a type "t" the following primitive type transformers can
52// be applied to it to yield another type.
53//
54//   e: type of "t" as is (identity)
55//   v: computes a vector type whose element type is "t" for the current LMUL
56//   w: computes a vector type identical to what 'v' computes except for the
57//      element type which is twice as wide as the element type of 'v'
58//   q: computes a vector type identical to what 'v' computes except for the
59//      element type which is four times as wide as the element type of 'v'
60//   o: computes a vector type identical to what 'v' computes except for the
61//      element type which is eight times as wide as the element type of 'v'
62//   m: computes a vector type identical to what 'v' computes except for the
63//      element type which is bool
64//   0: void type, ignores "t"
65//   z: size_t, ignores "t"
66//   t: ptrdiff_t, ignores "t"
67//   u: unsigned long, ignores "t"
68//   l: long, ignores "t"
69//
70// So for instance if t is "i", i.e. int, then "e" will yield int again. "v"
71// will yield an RVV vector type (assume LMUL=1), so __rvv_int32m1_t.
72// Accordingly "w" would yield __rvv_int64m2_t.
73//
74// A type transformer can be prefixed by other non-primitive type transformers.
75//
76//   P: constructs a pointer to the current type
77//   C: adds const to the type
78//   K: requires the integer type to be a constant expression
79//   U: given an integer type or vector type, computes its unsigned variant
80//   I: given a vector type, compute the vector type with integer type
81//      elements of the same width
82//   F: given a vector type, compute the vector type with floating-point type
83//      elements of the same width
84//   S: given a vector type, computes its equivalent one for LMUL=1. This is a
85//      no-op if the vector was already LMUL=1
86//   (Log2EEW:Value): Log2EEW value could be 3/4/5/6 (8/16/32/64), given a
87//      vector type (SEW and LMUL) and EEW (8/16/32/64), computes its
88//      equivalent integer vector type with EEW and corresponding ELMUL (elmul =
89//      (eew/sew) * lmul). For example, vector type is __rvv_float16m4
90//      (SEW=16, LMUL=4) and Log2EEW is 3 (EEW=8), and then equivalent vector
91//      type is __rvv_uint8m2_t (elmul=(8/16)*4 = 2). Ignore to define a new
92//      builtins if its equivalent type has illegal lmul.
93//   (FixedSEW:Value): Given a vector type (SEW and LMUL), and computes another
94//      vector type which only changed SEW as given value. Ignore to define a new
95//      builtin if its equivalent type has illegal lmul or the SEW does not changed.
96//   (SFixedLog2LMUL:Value): Smaller Fixed Log2LMUL. Given a vector type (SEW
97//      and LMUL), and computes another vector type which only changed LMUL as
98//      given value. The new LMUL should be smaller than the old one. Ignore to
99//      define a new builtin if its equivalent type has illegal lmul.
100//   (LFixedLog2LMUL:Value): Larger Fixed Log2LMUL. Given a vector type (SEW
101//      and LMUL), and computes another vector type which only changed LMUL as
102//      given value. The new LMUL should be larger than the old one. Ignore to
103//      define a new builtin if its equivalent type has illegal lmul.
104//
105// Following with the example above, if t is "i", then "Ue" will yield unsigned
106// int and "Fv" will yield __rvv_float32m1_t (again assuming LMUL=1), Fw would
107// yield __rvv_float64m2_t, etc.
108//
109// Each builtin is then defined by applying each type in TypeRange against the
110// sequence of type transformers described in Suffix and Prototype.
111//
112// The name of the builtin is defined by the Name attribute (which defaults to
113// the name of the class) appended (separated with an underscore) the Suffix
114// attribute. For instance with Name="foo", Suffix = "v" and TypeRange = "il",
115// the builtin generated will be __builtin_rvv_foo_i32m1 and
116// __builtin_rvv_foo_i64m1 (under LMUL=1). If Suffix contains more than one
117// type transformer (say "vv") each of the types is separated with an
118// underscore as in "__builtin_rvv_foo_i32m1_i32m1".
119//
120// The C/C++ prototype of the builtin is defined by the Prototype attribute.
121// Prototype is a non-empty sequence of type transformers, the first of which
122// is the return type of the builtin and the rest are the parameters of the
123// builtin, in order. For instance if Prototype is "wvv" and TypeRange is "si"
124// a first builtin will have type
125// __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t) and the second builtin
126// will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t) (again
127// under LMUL=1).
128//
129// There are a number of attributes that are used to constraint the number and
130// shape of the builtins generated. Refer to the comments below for them.
131
132class PolicyScheme<int val>{
133  int Value = val;
134}
135def NonePolicy : PolicyScheme<0>;
136def HasPassthruOperand : PolicyScheme<1>;
137def HasPolicyOperand : PolicyScheme<2>;
138
139class RVVBuiltin<string suffix, string prototype, string type_range,
140                 string overloaded_suffix = ""> {
141  // Base name that will be prepended in __builtin_rvv_ and appended the
142  // computed Suffix.
143  string Name = NAME;
144
145  // If not empty, each instantiated builtin will have this appended after an
146  // underscore (_). It is instantiated like Prototype.
147  string Suffix = suffix;
148
149  // If empty, default OverloadedName is sub string of `Name` which end of first
150  // '_'. For example, the default overloaded name  is `vadd` for Name `vadd_vv`.
151  // It's used for describe some special naming cases.
152  string OverloadedName = "";
153
154  // If not empty, each OverloadedName will have this appended after an
155  // underscore (_). It is instantiated like Prototype.
156  string OverloadedSuffix = overloaded_suffix;
157
158  // The different variants of the builtin, parameterised with a type.
159  string TypeRange = type_range;
160
161  // We use each type described in TypeRange and LMUL with prototype to
162  // instantiate a specific element of the set of builtins being defined.
163  // Prototype attribute defines the C/C++ prototype of the builtin. It is a
164  // non-empty sequence of type transformers, the first of which is the return
165  // type of the builtin and the rest are the parameters of the builtin, in
166  // order. For instance if Prototype is "wvv", TypeRange is "si" and LMUL=1, a
167  // first builtin will have type
168  // __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t), and the second builtin
169  // will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t).
170  string Prototype = prototype;
171
172  // This builtin has a masked form.
173  bit HasMasked = true;
174
175  // If HasMasked, this flag states that this builtin has a maskedoff operand. It
176  // is always the first operand in builtin and IR intrinsic.
177  bit HasMaskedOffOperand = true;
178
179  // This builtin has a granted vector length parameter.
180  bit HasVL = true;
181
182  // The policy scheme for masked intrinsic IR.
183  // It could be NonePolicy or HasPolicyOperand.
184  // HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is
185  // tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The
186  // policy operand is located at the last position.
187  PolicyScheme MaskedPolicyScheme = HasPolicyOperand;
188
189  // The policy scheme for unmasked intrinsic IR.
190  // It could be NonePolicy, HasPassthruOperand or HasPolicyOperand.
191  // HasPassthruOperand: Has a passthru operand to decide tail policy. If it is
192  // poison, tail policy is tail agnostic, otherwise policy is tail undisturbed.
193  // HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail
194  // undisturbed.
195  PolicyScheme UnMaskedPolicyScheme = NonePolicy;
196
197  // This builtin support tail agnostic and undisturbed policy.
198  bit HasTailPolicy = true;
199  // This builtin support mask agnostic and undisturbed policy.
200  bit HasMaskPolicy = true;
201
202  // This builtin prototype with TA or TAMA policy could not support overloading
203  // API. Other policy intrinsic functions would support overloading API with
204  // suffix `_tu`, `tumu`, `tuma`, `tamu` and `tama`.
205  bit SupportOverloading = true;
206
207  // This builtin is valid for the given Log2LMULs.
208  list<int> Log2LMUL = [0, 1, 2, 3, -1, -2, -3];
209
210  // Manual code in clang codegen riscv_vector_builtin_cg.inc
211  code ManualCodegen = [{}];
212
213  // When emit the automatic clang codegen, it describes what types we have to use
214  // to obtain the specific LLVM intrinsic. -1 means the return type, otherwise,
215  // k >= 0 meaning the k-th operand (counting from zero) of the codegen'd
216  // parameter of the unmasked version. k can't be the mask operand's position.
217  list<int> IntrinsicTypes = [];
218
219  // If these names are not empty, this is the ID of the LLVM intrinsic
220  // we want to lower to.
221  string IRName = NAME;
222
223  // If HasMasked, this is the ID of the LLVM intrinsic we want to lower to.
224  string MaskedIRName = NAME #"_mask";
225
226  // Use clang_builtin_alias to save the number of builtins.
227  bit HasBuiltinAlias = true;
228
229  // Features required to enable for this builtin.
230  list<string> RequiredFeatures = [];
231
232  // Number of fields for Load/Store Segment instructions.
233  int NF = 1;
234
235  // Set to true if the builtin is associated with tuple types.
236  bit IsTuple = false;
237
238  // Set to true if the builtin has a parameter that models floating-point
239  // rounding mode control
240  bit HasFRMRoundModeOp = false;
241}
242
243// This is the code emitted in the header.
244class RVVHeader {
245  code HeaderCode;
246}
247