| //==------ 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) |
| // y: bfloat16_t (bfloat16) |
| // |
| // 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" |
| // f: float32, 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. |
| // (SEFixedLog2LMUL:Value): Smaller or Equal 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 or |
| // equal to 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; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Basic classes with automatic codegen. |
| //===----------------------------------------------------------------------===// |
| |
| class RVVOutBuiltin<string suffix, string prototype, string type_range> |
| : RVVBuiltin<suffix, prototype, type_range> { |
| let IntrinsicTypes = [-1]; |
| } |
| |
| class RVVOp0Builtin<string suffix, string prototype, string type_range> |
| : RVVBuiltin<suffix, prototype, type_range> { |
| let IntrinsicTypes = [0]; |
| } |
| |
| class RVVOutOp1Builtin<string suffix, string prototype, string type_range> |
| : RVVBuiltin<suffix, prototype, type_range> { |
| let IntrinsicTypes = [-1, 1]; |
| } |
| |
| class RVVOutOp0Op1Builtin<string suffix, string prototype, string type_range> |
| : RVVBuiltin<suffix, prototype, type_range> { |
| let IntrinsicTypes = [-1, 0, 1]; |
| } |
| |
| multiclass RVVBuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes, |
| list<int> intrinsic_types> { |
| let IRName = intrinsic_name, MaskedIRName = intrinsic_name # "_mask", |
| IntrinsicTypes = intrinsic_types in { |
| foreach s_p = suffixes_prototypes in { |
| let Name = NAME # "_" # s_p[0] in { |
| defvar suffix = s_p[1]; |
| defvar prototype = s_p[2]; |
| def : RVVBuiltin<suffix, prototype, type_range>; |
| } |
| } |
| } |
| } |
| |
| // IntrinsicTypes is output, op0, op1 [-1, 0, 1] |
| multiclass RVVOutOp0Op1BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, |
| [-1, 0, 1]>; |
| |
| multiclass RVVOutBuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [-1]>; |
| |
| multiclass RVVOp0BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [0]>; |
| |
| // IntrinsicTypes is output, op1 [-1, 0] |
| multiclass RVVOutOp0BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [-1, 0]>; |
| |
| // IntrinsicTypes is output, op1 [-1, 1] |
| multiclass RVVOutOp1BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [-1, 1]>; |
| |
| multiclass RVVOp0Op1BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [0, 1]>; |
| |
| multiclass RVVOutOp1Op2BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [-1, 1, 2]>; |
| |
| // IntrinsicTypes is output, op2 [-1, 2] |
| multiclass RVVOutOp2BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> |
| : RVVBuiltinSet<intrinsic_name, type_range, suffixes_prototypes, [-1, 2]>; |
| |
| multiclass RVVSignedBinBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "v", "vvv"], |
| ["vx", "v", "vve"]]>; |
| |
| multiclass RVVSignedBinBuiltinSetRoundingMode |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "v", "vvvu"], |
| ["vx", "v", "vveu"]]>; |
| |
| multiclass RVVUnsignedBinBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "Uv", "UvUvUv"], |
| ["vx", "Uv", "UvUvUe"]]>; |
| |
| multiclass RVVUnsignedBinBuiltinSetRoundingMode |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "Uv", "UvUvUvu"], |
| ["vx", "Uv", "UvUvUeu"]]>; |
| |
| multiclass RVVIntBinBuiltinSet |
| : RVVSignedBinBuiltinSet, |
| RVVUnsignedBinBuiltinSet; |
| |
| multiclass RVVInt64BinBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "l", |
| [["vv", "v", "vvv"], |
| ["vx", "v", "vve"]]>, |
| RVVOutOp1BuiltinSet<NAME, "l", |
| [["vv", "Uv", "UvUvUv"], |
| ["vx", "Uv", "UvUvUe"]]>; |
| |
| multiclass RVVSlideOneBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vx", "v", "vve"], |
| ["vx", "Uv", "UvUvUe"]]>; |
| |
| multiclass RVVSignedShiftBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "v", "vvUv"], |
| ["vx", "v", "vvz"]]>; |
| |
| multiclass RVVSignedShiftBuiltinSetRoundingMode |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "v", "vvUvu"], |
| ["vx", "v", "vvzu"]]>; |
| |
| multiclass RVVUnsignedShiftBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "Uv", "UvUvUv"], |
| ["vx", "Uv", "UvUvz"]]>; |
| |
| multiclass RVVUnsignedShiftBuiltinSetRoundingMode |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "Uv", "UvUvUvu"], |
| ["vx", "Uv", "UvUvzu"]]>; |
| |
| multiclass RVVShiftBuiltinSet |
| : RVVSignedShiftBuiltinSet, |
| RVVUnsignedShiftBuiltinSet; |
| |
| let Log2LMUL = [-3, -2, -1, 0, 1, 2] in { |
| multiclass RVVSignedNShiftBuiltinSet |
| : RVVOutOp0Op1BuiltinSet<NAME, "csil", |
| [["wv", "v", "vwUv"], |
| ["wx", "v", "vwz"]]>; |
| |
| multiclass RVVSignedNShiftBuiltinSetRoundingMode |
| : RVVOutOp0Op1BuiltinSet<NAME, "csil", |
| [["wv", "v", "vwUvu"], |
| ["wx", "v", "vwzu"]]>; |
| |
| multiclass RVVUnsignedNShiftBuiltinSet |
| : RVVOutOp0Op1BuiltinSet<NAME, "csil", |
| [["wv", "Uv", "UvUwUv"], |
| ["wx", "Uv", "UvUwz"]]>; |
| |
| multiclass RVVUnsignedNShiftBuiltinSetRoundingMode |
| : RVVOutOp0Op1BuiltinSet<NAME, "csil", |
| [["wv", "Uv", "UvUwUvu"], |
| ["wx", "Uv", "UvUwzu"]]>; |
| |
| } |
| |
| multiclass RVVCarryinBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vvm", "v", "vvvm"], |
| ["vxm", "v", "vvem"], |
| ["vvm", "Uv", "UvUvUvm"], |
| ["vxm", "Uv", "UvUvUem"]]>; |
| |
| multiclass RVVCarryOutInBuiltinSet<string intrinsic_name> |
| : RVVOp0Op1BuiltinSet<intrinsic_name, "csil", |
| [["vvm", "vm", "mvvm"], |
| ["vxm", "vm", "mvem"], |
| ["vvm", "Uvm", "mUvUvm"], |
| ["vxm", "Uvm", "mUvUem"]]>; |
| |
| multiclass RVVSignedMaskOutBuiltinSet |
| : RVVOp0Op1BuiltinSet<NAME, "csil", |
| [["vv", "vm", "mvv"], |
| ["vx", "vm", "mve"]]>; |
| |
| multiclass RVVUnsignedMaskOutBuiltinSet |
| : RVVOp0Op1BuiltinSet<NAME, "csil", |
| [["vv", "Uvm", "mUvUv"], |
| ["vx", "Uvm", "mUvUe"]]>; |
| |
| multiclass RVVIntMaskOutBuiltinSet |
| : RVVSignedMaskOutBuiltinSet, |
| RVVUnsignedMaskOutBuiltinSet; |
| |
| class RVVIntExt<string intrinsic_name, string suffix, string prototype, |
| string type_range> |
| : RVVBuiltin<suffix, prototype, type_range> { |
| let IRName = intrinsic_name; |
| let MaskedIRName = intrinsic_name # "_mask"; |
| let OverloadedName = NAME; |
| let IntrinsicTypes = [-1, 0]; |
| } |
| |
| let HasMaskedOffOperand = false in { |
| multiclass RVVIntTerBuiltinSet { |
| defm "" : RVVOutOp1BuiltinSet<NAME, "csil", |
| [["vv", "v", "vvvv"], |
| ["vx", "v", "vvev"], |
| ["vv", "Uv", "UvUvUvUv"], |
| ["vx", "Uv", "UvUvUeUv"]]>; |
| } |
| multiclass RVVFloatingTerBuiltinSet { |
| defm "" : RVVOutOp1BuiltinSet<NAME, "xfd", |
| [["vv", "v", "vvvv"], |
| ["vf", "v", "vvev"]]>; |
| } |
| multiclass RVVFloatingTerBuiltinSetRoundingMode { |
| defm "" : RVVOutOp1BuiltinSet<NAME, "xfd", |
| [["vv", "v", "vvvvu"], |
| ["vf", "v", "vvevu"]]>; |
| } |
| } |
| |
| let HasMaskedOffOperand = false, Log2LMUL = [-2, -1, 0, 1, 2] in { |
| multiclass RVVFloatingWidenTerBuiltinSet { |
| defm "" : RVVOutOp1Op2BuiltinSet<NAME, "xf", |
| [["vv", "w", "wwvv"], |
| ["vf", "w", "wwev"]]>; |
| } |
| multiclass RVVFloatingWidenTerBuiltinSetRoundingMode { |
| defm "" : RVVOutOp1Op2BuiltinSet<NAME, "xf", |
| [["vv", "w", "wwvvu"], |
| ["vf", "w", "wwevu"]]>; |
| } |
| } |
| |
| multiclass RVVFloatingBinBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "xfd", |
| [["vv", "v", "vvv"], |
| ["vf", "v", "vve"]]>; |
| |
| multiclass RVVFloatingBinBuiltinSetRoundingMode |
| : RVVOutOp1BuiltinSet<NAME, "xfd", |
| [["vv", "v", "vvvu"], |
| ["vf", "v", "vveu"]]>; |
| |
| multiclass RVVFloatingBinVFBuiltinSet |
| : RVVOutOp1BuiltinSet<NAME, "xfd", |
| [["vf", "v", "vve"]]>; |
| |
| multiclass RVVFloatingBinVFBuiltinSetRoundingMode |
| : RVVOutOp1BuiltinSet<NAME, "xfd", |
| [["vf", "v", "vveu"]]>; |
| |
| multiclass RVVFloatingMaskOutBuiltinSet |
| : RVVOp0Op1BuiltinSet<NAME, "xfd", |
| [["vv", "vm", "mvv"], |
| ["vf", "vm", "mve"]]>; |
| |
| multiclass RVVFloatingMaskOutVFBuiltinSet |
| : RVVOp0Op1BuiltinSet<NAME, "fd", |
| [["vf", "vm", "mve"]]>; |
| |
| multiclass RVVConvBuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> { |
| let Name = intrinsic_name, |
| IRName = intrinsic_name, |
| MaskedIRName = intrinsic_name # "_mask", |
| IntrinsicTypes = [-1, 0] in { |
| foreach s_p = suffixes_prototypes in { |
| defvar suffix = s_p[0]; |
| defvar prototype = s_p[1]; |
| def : RVVBuiltin<suffix, prototype, type_range>; |
| } |
| } |
| } |
| |
| |
| class RVVMaskBinBuiltin : RVVOutBuiltin<"m", "mmm", "c"> { |
| let Name = NAME # "_mm"; |
| let HasMasked = false; |
| } |
| |
| class RVVMaskUnaryBuiltin : RVVOutBuiltin<"m", "mm", "c"> { |
| let Name = NAME # "_m"; |
| } |
| |
| class RVVMaskNullaryBuiltin : RVVOutBuiltin<"m", "m", "c"> { |
| let Name = NAME # "_m"; |
| let HasMasked = false; |
| let SupportOverloading = false; |
| } |
| |
| class RVVMaskOp0Builtin<string prototype> : RVVOp0Builtin<"m", prototype, "c"> { |
| let Name = NAME # "_m"; |
| let HasMaskedOffOperand = false; |
| } |
| |
| let UnMaskedPolicyScheme = HasPolicyOperand, |
| HasMaskedOffOperand = false in { |
| multiclass RVVSlideUpBuiltinSet { |
| defm "" : RVVOutBuiltinSet<NAME, "csilxfd", |
| [["vx","v", "vvvz"]]>; |
| defm "" : RVVOutBuiltinSet<NAME, "csil", |
| [["vx","Uv", "UvUvUvz"]]>; |
| } |
| } |
| |
| let UnMaskedPolicyScheme = HasPassthruOperand, |
| ManualCodegen = [{ |
| if (IsMasked) { |
| std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); |
| if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
| Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); |
| } else { |
| if (PolicyAttrs & RVV_VTA) |
| Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType)); |
| } |
| |
| Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs)); |
| IntrinsicTypes = {ResultType, Ops.back()->getType()}; |
| }] in { |
| multiclass RVVSlideDownBuiltinSet { |
| defm "" : RVVOutBuiltinSet<NAME, "csilxfd", |
| [["vx","v", "vvz"]]>; |
| defm "" : RVVOutBuiltinSet<NAME, "csil", |
| [["vx","Uv", "UvUvz"]]>; |
| } |
| } |
| |
| class RVVFloatingUnaryBuiltin<string builtin_suffix, string ir_suffix, |
| string prototype> |
| : RVVOutBuiltin<ir_suffix, prototype, "xfd"> { |
| let Name = NAME # "_" # builtin_suffix; |
| } |
| |
| class RVVFloatingUnaryVVBuiltin : RVVFloatingUnaryBuiltin<"v", "v", "vv">; |
| |
| class RVVConvBuiltin<string suffix, string prototype, string type_range, |
| string overloaded_name> |
| : RVVBuiltin<suffix, prototype, type_range> { |
| let IntrinsicTypes = [-1, 0]; |
| let OverloadedName = overloaded_name; |
| } |
| |
| class RVVConvToSignedBuiltin<string overloaded_name> |
| : RVVConvBuiltin<"Iv", "Ivv", "xfd", overloaded_name>; |
| |
| class RVVConvToUnsignedBuiltin<string overloaded_name> |
| : RVVConvBuiltin<"Uv", "Uvv", "xfd", overloaded_name>; |
| |
| class RVVConvToWidenSignedBuiltin<string overloaded_name> |
| : RVVConvBuiltin<"Iw", "Iwv", "xf", overloaded_name>; |
| |
| class RVVConvToWidenUnsignedBuiltin<string overloaded_name> |
| : RVVConvBuiltin<"Uw", "Uwv", "xf", overloaded_name>; |
| |
| class RVVConvToNarrowingSignedBuiltin<string overloaded_name> |
| : RVVConvBuiltin<"Iv", "IvFw", "csi", overloaded_name>; |
| |
| class RVVConvToNarrowingUnsignedBuiltin<string overloaded_name> |
| : RVVConvBuiltin<"Uv", "UvFw", "csi", overloaded_name>; |
| |
| let HasMaskedOffOperand = true in { |
| multiclass RVVSignedReductionBuiltin { |
| defm "" : RVVOutOp0BuiltinSet<NAME, "csil", |
| [["vs", "vSv", "SvvSv"]]>; |
| } |
| multiclass RVVUnsignedReductionBuiltin { |
| defm "" : RVVOutOp0BuiltinSet<NAME, "csil", |
| [["vs", "UvUSv", "USvUvUSv"]]>; |
| } |
| multiclass RVVFloatingReductionBuiltin { |
| defm "" : RVVOutOp0BuiltinSet<NAME, "xfd", |
| [["vs", "vSv", "SvvSv"]]>; |
| } |
| multiclass RVVFloatingReductionBuiltinRoundingMode { |
| defm "" : RVVOutOp0BuiltinSet<NAME, "xfd", |
| [["vs", "vSv", "SvvSvu"]]>; |
| } |
| multiclass RVVFloatingWidenReductionBuiltin { |
| defm "" : RVVOutOp0BuiltinSet<NAME, "xf", |
| [["vs", "vSw", "SwvSw"]]>; |
| } |
| multiclass RVVFloatingWidenReductionBuiltinRoundingMode { |
| defm "" : RVVOutOp0BuiltinSet<NAME, "xf", |
| [["vs", "vSw", "SwvSwu"]]>; |
| } |
| } |
| |
| multiclass RVVIntReductionBuiltinSet |
| : RVVSignedReductionBuiltin, |
| RVVUnsignedReductionBuiltin; |
| |
| // For widen operation which has different mangling name. |
| multiclass RVVWidenBuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> { |
| let Log2LMUL = [-3, -2, -1, 0, 1, 2], |
| IRName = intrinsic_name, MaskedIRName = intrinsic_name # "_mask" in { |
| foreach s_p = suffixes_prototypes in { |
| let Name = NAME # "_" # s_p[0], |
| OverloadedName = NAME # "_" # s_p[0] in { |
| defvar suffix = s_p[1]; |
| defvar prototype = s_p[2]; |
| def : RVVOutOp0Op1Builtin<suffix, prototype, type_range>; |
| } |
| } |
| } |
| } |
| |
| // For widen operation with widen operand which has different mangling name. |
| multiclass RVVWidenWOp0BuiltinSet<string intrinsic_name, string type_range, |
| list<list<string>> suffixes_prototypes> { |
| let Log2LMUL = [-3, -2, -1, 0, 1, 2], |
| IRName = intrinsic_name, MaskedIRName = intrinsic_name # "_mask" in { |
| foreach s_p = suffixes_prototypes in { |
| let Name = NAME # "_" # s_p[0], |
| OverloadedName = NAME # "_" # s_p[0] in { |
| defvar suffix = s_p[1]; |
| defvar prototype = s_p[2]; |
| def : RVVOutOp1Builtin<suffix, prototype, type_range>; |
| } |
| } |
| } |
| } |
| |
| multiclass RVVSignedWidenBinBuiltinSet |
| : RVVWidenBuiltinSet<NAME, "csi", |
| [["vv", "w", "wvv"], |
| ["vx", "w", "wve"]]>; |
| |
| multiclass RVVSignedWidenOp0BinBuiltinSet |
| : RVVWidenWOp0BuiltinSet<NAME # "_w", "csi", |
| [["wv", "w", "wwv"], |
| ["wx", "w", "wwe"]]>; |
| |
| multiclass RVVUnsignedWidenBinBuiltinSet |
| : RVVWidenBuiltinSet<NAME, "csi", |
| [["vv", "Uw", "UwUvUv"], |
| ["vx", "Uw", "UwUvUe"]]>; |
| |
| multiclass RVVUnsignedWidenOp0BinBuiltinSet |
| : RVVWidenWOp0BuiltinSet<NAME # "_w", "csi", |
| [["wv", "Uw", "UwUwUv"], |
| ["wx", "Uw", "UwUwUe"]]>; |
| |
| multiclass RVVFloatingWidenBinBuiltinSet |
| : RVVWidenBuiltinSet<NAME, "xf", |
| [["vv", "w", "wvv"], |
| ["vf", "w", "wve"]]>; |
| |
| multiclass RVVFloatingWidenBinBuiltinSetRoundingMode |
| : RVVWidenBuiltinSet<NAME, "xf", |
| [["vv", "w", "wvvu"], |
| ["vf", "w", "wveu"]]>; |
| |
| multiclass RVVFloatingWidenOp0BinBuiltinSet |
| : RVVWidenWOp0BuiltinSet<NAME # "_w", "xf", |
| [["wv", "w", "wwv"], |
| ["wf", "w", "wwe"]]>; |
| |
| multiclass RVVFloatingWidenOp0BinBuiltinSetRoundingMode |
| : RVVWidenWOp0BuiltinSet<NAME # "_w", "xf", |
| [["wv", "w", "wwvu"], |
| ["wf", "w", "wweu"]]>; |