llvm/clang/include/clang/Basic/riscv_vector_common.td

//==------ 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", "si", overloaded_name>;

class RVVConvToNarrowingUnsignedBuiltin<string overloaded_name>
    : RVVConvBuiltin<"Uv", "UvFw", "si", 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"]]>;