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