blob: e276e4c3c409b294c5fb3116cdfc4f08c4f5b78d [file] [log] [blame]
//==------ riscv_vector_common.td - RISC-V V-ext builtin class ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines RVV builtin base class for RISC-V V-extension.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Instruction definitions
//===----------------------------------------------------------------------===//
// Each record of the class RVVBuiltin defines a collection of builtins (i.e.
// "def vadd : RVVBuiltin" will be used to define things like "vadd_vv_i32m1",
// "vadd_vv_i32m2", etc).
//
// The elements of this collection are defined by an instantiation process the
// range of which is specified by the cross product of the LMUL attribute and
// every element in the attribute TypeRange. By default builtins have LMUL = [1,
// 2, 4, 8, 1/2, 1/4, 1/8] so the process is repeated 7 times. In tablegen we
// use the Log2LMUL [0, 1, 2, 3, -1, -2, -3] to represent the LMUL.
//
// LMUL represents the fact that the types of values used by that builtin are
// values generated by instructions that are executed under that LMUL. However,
// this does not mean the builtin is necessarily lowered into an instruction
// that executes under the specified LMUL. An example where this happens are
// loads and stores of masks. A mask like `vbool8_t` can be generated, for
// instance, by comparing two `__rvv_int8m1_t` (this is LMUL=1) or comparing two
// `__rvv_int16m2_t` (this is LMUL=2). The actual load or store, however, will
// be performed under LMUL=1 because mask registers are not grouped.
//
// TypeRange is a non-empty sequence of basic types:
//
// c: int8_t (i8)
// s: int16_t (i16)
// i: int32_t (i32)
// l: int64_t (i64)
// x: float16_t (half)
// f: float32_t (float)
// d: float64_t (double)
//
// This way, given an LMUL, a record with a TypeRange "sil" will cause the
// definition of 3 builtins. Each type "t" in the TypeRange (in this example
// they are int16_t, int32_t, int64_t) is used as a parameter that drives the
// definition of that particular builtin (for the given LMUL).
//
// During the instantiation, types can be transformed or modified using type
// transformers. Given a type "t" the following primitive type transformers can
// be applied to it to yield another type.
//
// e: type of "t" as is (identity)
// v: computes a vector type whose element type is "t" for the current LMUL
// w: computes a vector type identical to what 'v' computes except for the
// element type which is twice as wide as the element type of 'v'
// q: computes a vector type identical to what 'v' computes except for the
// element type which is four times as wide as the element type of 'v'
// o: computes a vector type identical to what 'v' computes except for the
// element type which is eight times as wide as the element type of 'v'
// m: computes a vector type identical to what 'v' computes except for the
// element type which is bool
// 0: void type, ignores "t"
// z: size_t, ignores "t"
// t: ptrdiff_t, ignores "t"
// u: unsigned long, ignores "t"
// l: long, ignores "t"
//
// So for instance if t is "i", i.e. int, then "e" will yield int again. "v"
// will yield an RVV vector type (assume LMUL=1), so __rvv_int32m1_t.
// Accordingly "w" would yield __rvv_int64m2_t.
//
// A type transformer can be prefixed by other non-primitive type transformers.
//
// P: constructs a pointer to the current type
// C: adds const to the type
// K: requires the integer type to be a constant expression
// U: given an integer type or vector type, computes its unsigned variant
// I: given a vector type, compute the vector type with integer type
// elements of the same width
// F: given a vector type, compute the vector type with floating-point type
// elements of the same width
// S: given a vector type, computes its equivalent one for LMUL=1. This is a
// no-op if the vector was already LMUL=1
// (Log2EEW:Value): Log2EEW value could be 3/4/5/6 (8/16/32/64), given a
// vector type (SEW and LMUL) and EEW (8/16/32/64), computes its
// equivalent integer vector type with EEW and corresponding ELMUL (elmul =
// (eew/sew) * lmul). For example, vector type is __rvv_float16m4
// (SEW=16, LMUL=4) and Log2EEW is 3 (EEW=8), and then equivalent vector
// type is __rvv_uint8m2_t (elmul=(8/16)*4 = 2). Ignore to define a new
// builtins if its equivalent type has illegal lmul.
// (FixedSEW:Value): Given a vector type (SEW and LMUL), and computes another
// vector type which only changed SEW as given value. Ignore to define a new
// builtin if its equivalent type has illegal lmul or the SEW does not changed.
// (SFixedLog2LMUL:Value): Smaller Fixed Log2LMUL. Given a vector type (SEW
// and LMUL), and computes another vector type which only changed LMUL as
// given value. The new LMUL should be smaller than the old one. Ignore to
// define a new builtin if its equivalent type has illegal lmul.
// (LFixedLog2LMUL:Value): Larger Fixed Log2LMUL. Given a vector type (SEW
// and LMUL), and computes another vector type which only changed LMUL as
// given value. The new LMUL should be larger than the old one. Ignore to
// define a new builtin if its equivalent type has illegal lmul.
//
// Following with the example above, if t is "i", then "Ue" will yield unsigned
// int and "Fv" will yield __rvv_float32m1_t (again assuming LMUL=1), Fw would
// yield __rvv_float64m2_t, etc.
//
// Each builtin is then defined by applying each type in TypeRange against the
// sequence of type transformers described in Suffix and Prototype.
//
// The name of the builtin is defined by the Name attribute (which defaults to
// the name of the class) appended (separated with an underscore) the Suffix
// attribute. For instance with Name="foo", Suffix = "v" and TypeRange = "il",
// the builtin generated will be __builtin_rvv_foo_i32m1 and
// __builtin_rvv_foo_i64m1 (under LMUL=1). If Suffix contains more than one
// type transformer (say "vv") each of the types is separated with an
// underscore as in "__builtin_rvv_foo_i32m1_i32m1".
//
// The C/C++ prototype of the builtin is defined by the Prototype attribute.
// Prototype is a non-empty sequence of type transformers, the first of which
// is the return type of the builtin and the rest are the parameters of the
// builtin, in order. For instance if Prototype is "wvv" and TypeRange is "si"
// a first builtin will have type
// __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t) and the second builtin
// will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t) (again
// under LMUL=1).
//
// There are a number of attributes that are used to constraint the number and
// shape of the builtins generated. Refer to the comments below for them.
class PolicyScheme<int val>{
int Value = val;
}
def NonePolicy : PolicyScheme<0>;
def HasPassthruOperand : PolicyScheme<1>;
def HasPolicyOperand : PolicyScheme<2>;
class RVVBuiltin<string suffix, string prototype, string type_range,
string overloaded_suffix = ""> {
// Base name that will be prepended in __builtin_rvv_ and appended the
// computed Suffix.
string Name = NAME;
// If not empty, each instantiated builtin will have this appended after an
// underscore (_). It is instantiated like Prototype.
string Suffix = suffix;
// If empty, default OverloadedName is sub string of `Name` which end of first
// '_'. For example, the default overloaded name is `vadd` for Name `vadd_vv`.
// It's used for describe some special naming cases.
string OverloadedName = "";
// If not empty, each OverloadedName will have this appended after an
// underscore (_). It is instantiated like Prototype.
string OverloadedSuffix = overloaded_suffix;
// The different variants of the builtin, parameterised with a type.
string TypeRange = type_range;
// We use each type described in TypeRange and LMUL with prototype to
// instantiate a specific element of the set of builtins being defined.
// Prototype attribute defines the C/C++ prototype of the builtin. It is a
// non-empty sequence of type transformers, the first of which is the return
// type of the builtin and the rest are the parameters of the builtin, in
// order. For instance if Prototype is "wvv", TypeRange is "si" and LMUL=1, a
// first builtin will have type
// __rvv_int32m2_t (__rvv_int16m1_t, __rvv_int16m1_t), and the second builtin
// will have type __rvv_int64m2_t (__rvv_int32m1_t, __rvv_int32m1_t).
string Prototype = prototype;
// This builtin has a masked form.
bit HasMasked = true;
// If HasMasked, this flag states that this builtin has a maskedoff operand. It
// is always the first operand in builtin and IR intrinsic.
bit HasMaskedOffOperand = true;
// This builtin has a granted vector length parameter.
bit HasVL = true;
// The policy scheme for masked intrinsic IR.
// It could be NonePolicy or HasPolicyOperand.
// HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is
// tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The
// policy operand is located at the last position.
PolicyScheme MaskedPolicyScheme = HasPolicyOperand;
// The policy scheme for unmasked intrinsic IR.
// It could be NonePolicy, HasPassthruOperand or HasPolicyOperand.
// HasPassthruOperand: Has a passthru operand to decide tail policy. If it is
// poison, tail policy is tail agnostic, otherwise policy is tail undisturbed.
// HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail
// undisturbed.
PolicyScheme UnMaskedPolicyScheme = NonePolicy;
// This builtin support tail agnostic and undisturbed policy.
bit HasTailPolicy = true;
// This builtin support mask agnostic and undisturbed policy.
bit HasMaskPolicy = true;
// This builtin prototype with TA or TAMA policy could not support overloading
// API. Other policy intrinsic functions would support overloading API with
// suffix `_tu`, `tumu`, `tuma`, `tamu` and `tama`.
bit SupportOverloading = true;
// This builtin is valid for the given Log2LMULs.
list<int> Log2LMUL = [0, 1, 2, 3, -1, -2, -3];
// Manual code in clang codegen riscv_vector_builtin_cg.inc
code ManualCodegen = [{}];
// When emit the automatic clang codegen, it describes what types we have to use
// to obtain the specific LLVM intrinsic. -1 means the return type, otherwise,
// k >= 0 meaning the k-th operand (counting from zero) of the codegen'd
// parameter of the unmasked version. k can't be the mask operand's position.
list<int> IntrinsicTypes = [];
// If these names are not empty, this is the ID of the LLVM intrinsic
// we want to lower to.
string IRName = NAME;
// If HasMasked, this is the ID of the LLVM intrinsic we want to lower to.
string MaskedIRName = NAME #"_mask";
// Use clang_builtin_alias to save the number of builtins.
bit HasBuiltinAlias = true;
// Features required to enable for this builtin.
list<string> RequiredFeatures = [];
// Number of fields for Load/Store Segment instructions.
int NF = 1;
// Set to true if the builtin is associated with tuple types.
bit IsTuple = false;
// Set to true if the builtin has a parameter that models floating-point
// rounding mode control
bit HasFRMRoundModeOp = false;
}
// This is the code emitted in the header.
class RVVHeader {
code HeaderCode;
}