Seems I got one fail for pr120436.c, will send v2 for fixing that

On Thu, Oct 9, 2025 at 6:48 PM Kito Cheng <[email protected]> wrote:
>
> This patch implements the standard fixed-length vector calling convention
> variant as specified in the RISC-V ELF psABI document. The implementation
> introduces ABI_VLEN to serve as the minimal VLEN for fixed-length vectors.
>
> For example, int32x8_t is a 256-bit vector type. If ABI_VLEN is 128, it
> will be passed in two vector registers as LMUL 2. If ABI_VLEN is larger
> than 256, it will be passed in one vector register as LMUL 1.
>
> This differs from the minimal VLEN (defined by ZVL*B extension) to ensure
> ABI stability when the program compiles with different VLEN/ZVL*B settings.
>
> Ref: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418
>
> gcc/ChangeLog:
>
>         * config/riscv/riscv.h (enum riscv_cc): Add RISCV_CC_VLS_V_32,
>         RISCV_CC_VLS_V_64, RISCV_CC_VLS_V_128, RISCV_CC_VLS_V_256,
>         RISCV_CC_VLS_V_512, RISCV_CC_VLS_V_1024, RISCV_CC_VLS_V_2048,
>         RISCV_CC_VLS_V_4096, RISCV_CC_VLS_V_8192, RISCV_CC_VLS_V_16384.
>         (CUMULATIVE_ARGS): Add abi_vlen field.
>         * config/riscv/riscv.cc (riscv_handle_rvv_vls_cc_attribute): New
>         function.
>         (riscv_gnu_attributes): Add vls_cc attribute entry.
>         (riscv_attributes): Add riscv_vls_cc attribute entry.
>         (riscv_flatten_aggregate_field): Add vls_p and abi_vlen parameters
>         to handle VLS vector types.
>         (riscv_flatten_aggregate_argument): Update call to
>         riscv_flatten_aggregate_field.
>         (riscv_get_vector_arg): Add vls_p parameter for VLS handling.
>         (riscv_vls_cc_p): New function.
>         (riscv_get_cc_abi_vlen): New function.
>         (riscv_valid_abi_vlen_vls_cc_p): New function.
>         (riscv_get_riscv_cc_by_abi_vlen): New function.
>         (riscv_get_vls_container_type): New function.
>         (riscv_pass_vls_in_vr): New function.
>         (riscv_pass_aggregate_in_vr): New function.
>         (riscv_get_arg_info): Add VLS calling convention handling.
>         (riscv_function_arg_advance): Update for VLS calling convention.
>         (riscv_return_in_memory): Add fntype parameter and initialize
>         cumulative args properly.
>         (riscv_v_abi): Add abi parameter.
>         (riscv_get_vls_cc_attr): New function.
>         (riscv_vls_cc_function_abi): New function.
>         (riscv_fntype_abi): Add VLS calling convention detection.
>         (riscv_asm_output_variant_cc): Update for VLS calling convention.
> ---
>  gcc/config/riscv/riscv.cc | 409 ++++++++++++++++++++++++++++++++++----
>  gcc/config/riscv/riscv.h  |  13 ++
>  2 files changed, 384 insertions(+), 38 deletions(-)
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index a30c9f1dd14..b4a0f61f1d2 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -740,6 +740,7 @@ static tree riscv_handle_fndecl_attribute (tree *, tree, 
> tree, int, bool *);
>  static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *);
>  static tree riscv_handle_rvv_vector_bits_attribute (tree *, tree, tree, int,
>                                                     bool *);
> +static tree riscv_handle_rvv_vls_cc_attribute (tree *, tree, tree, int, bool 
> *);
>
>  /* Defining target-specific uses of __attribute__.  */
>  static const attribute_spec riscv_gnu_attributes[] =
> @@ -763,6 +764,8 @@ static const attribute_spec riscv_gnu_attributes[] =
>      standard vector calling convention variant. Syntax:
>      __attribute__((riscv_vector_cc)). */
>    {"riscv_vector_cc", 0, 0, false, true, true, true, NULL, NULL},
> +  {"riscv_vls_cc", 0, 1, false, true, true, true,
> +   riscv_handle_rvv_vls_cc_attribute, NULL},
>    /* This attribute is used to declare a new type, to appoint the exactly
>       bits size of the type.  For example:
>
> @@ -790,6 +793,8 @@ static const attribute_spec riscv_attributes[] =
>       standard vector calling convention variant. Syntax:
>       [[riscv::vector_cc]]. */
>    {"vector_cc", 0, 0, false, true, true, true, NULL, NULL},
> +  {"vls_cc", 0, 1, false, true, true, true, 
> riscv_handle_rvv_vls_cc_attribute,
> +   NULL},
>    /* This attribute is used to declare a new type, to appoint the exactly
>       bits size of the type.  For example:
>
> @@ -5872,11 +5877,12 @@ typedef struct {
>     floating-point registers.  */
>
>  static int
> -riscv_flatten_aggregate_field (const_tree type,
> -                              riscv_aggregate_field fields[2],
> +riscv_flatten_aggregate_field (const_tree type, riscv_aggregate_field 
> *fields,
>                                int n, HOST_WIDE_INT offset,
> -                              bool ignore_zero_width_bit_field_p)
> +                              bool ignore_zero_width_bit_field_p,
> +                              bool vls_p = false, unsigned abi_vlen = 0)
>  {
> +  int max_aggregate_field = vls_p ? 8 : 2;
>    switch (TREE_CODE (type))
>      {
>      case RECORD_TYPE:
> @@ -5903,9 +5909,9 @@ riscv_flatten_aggregate_field (const_tree type,
>             else
>               {
>                 HOST_WIDE_INT pos = offset + int_byte_position (f);
> -               n = riscv_flatten_aggregate_field (TREE_TYPE (f),
> -                                                  fields, n, pos,
> -                                                  
> ignore_zero_width_bit_field_p);
> +               n = riscv_flatten_aggregate_field (
> +                 TREE_TYPE (f), fields, n, pos, 
> ignore_zero_width_bit_field_p,
> +                 vls_p, abi_vlen);
>               }
>             if (n < 0)
>               return -1;
> @@ -5915,13 +5921,14 @@ riscv_flatten_aggregate_field (const_tree type,
>      case ARRAY_TYPE:
>        {
>         HOST_WIDE_INT n_elts;
> -       riscv_aggregate_field subfields[2];
> +       riscv_aggregate_field subfields[8];
>         tree index = TYPE_DOMAIN (type);
>         tree elt_size = TYPE_SIZE_UNIT (TREE_TYPE (type));
> -       int n_subfields = riscv_flatten_aggregate_field (TREE_TYPE (type),
> -                                                        subfields, 0, offset,
> -                                                        
> ignore_zero_width_bit_field_p);
> -
> +       int n_subfields
> +         = riscv_flatten_aggregate_field (TREE_TYPE (type), subfields, 0,
> +                                          offset,
> +                                          ignore_zero_width_bit_field_p, 
> vls_p,
> +                                          abi_vlen);
>         /* Can't handle incomplete types nor sizes that are not fixed.  */
>         if (n_subfields <= 0
>             || !COMPLETE_TYPE_P (type)
> @@ -5941,7 +5948,7 @@ riscv_flatten_aggregate_field (const_tree type,
>         for (HOST_WIDE_INT i = 0; i < n_elts; i++)
>           for (int j = 0; j < n_subfields; j++)
>             {
> -             if (n >= 2)
> +             if (n >= max_aggregate_field)
>                 return -1;
>
>               fields[n] = subfields[j];
> @@ -5973,18 +5980,36 @@ riscv_flatten_aggregate_field (const_tree type,
>        }
>
>      default:
> -      if (n < 2
> -         && ((SCALAR_FLOAT_TYPE_P (type)
> -              && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= 
> UNITS_PER_FP_ARG)
> -             || (INTEGRAL_TYPE_P (type)
> -                 && GET_MODE_SIZE (TYPE_MODE (type)).to_constant () <= 
> UNITS_PER_WORD)))
> +      poly_uint64 mode_size = GET_MODE_SIZE (TYPE_MODE (type));
> +      if (vls_p)
>         {
> -         fields[n].type = type;
> -         fields[n].offset = offset;
> -         return n + 1;
> +         gcc_assert (abi_vlen != 0);
> +         if (n < max_aggregate_field
> +             && (VECTOR_TYPE_P (type) && mode_size.is_constant ()
> +                 && (mode_size.to_constant () <= abi_vlen * 8)))
> +           {
> +             fields[n].type = type;
> +             fields[n].offset = offset;
> +             return n + 1;
> +           }
> +         else
> +           return -1;
>         }
>        else
> -       return -1;
> +       {
> +         if (n < max_aggregate_field
> +             && ((SCALAR_FLOAT_TYPE_P (type)
> +                  && mode_size.to_constant () <= UNITS_PER_FP_ARG)
> +                 || (INTEGRAL_TYPE_P (type)
> +                     && mode_size.to_constant () <= UNITS_PER_WORD)))
> +           {
> +             fields[n].type = type;
> +             fields[n].offset = offset;
> +             return n + 1;
> +           }
> +         else
> +           return -1;
> +       }
>      }
>  }
>
> @@ -5993,14 +6018,16 @@ riscv_flatten_aggregate_field (const_tree type,
>
>  static int
>  riscv_flatten_aggregate_argument (const_tree type,
> -                                 riscv_aggregate_field fields[2],
> -                                 bool ignore_zero_width_bit_field_p)
> +                                 riscv_aggregate_field *fields,
> +                                 bool ignore_zero_width_bit_field_p,
> +                                 bool vls_p = false, unsigned abi_vlen = 0)
>  {
>    if (!type || TREE_CODE (type) != RECORD_TYPE)
>      return -1;
>
>    return riscv_flatten_aggregate_field (type, fields, 0, 0,
> -                                       ignore_zero_width_bit_field_p);
> +                                       ignore_zero_width_bit_field_p, vls_p,
> +                                       abi_vlen);
>  }
>
>  /* See whether TYPE is a record whose fields should be returned in one or
> @@ -6197,7 +6224,7 @@ riscv_hard_regno_nregs (unsigned int regno, 
> machine_mode mode);
>
>  static rtx
>  riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS 
> *cum,
> -                     machine_mode mode, bool return_p)
> +                     machine_mode mode, bool return_p, bool vls_p = false)
>  {
>    gcc_assert (riscv_v_ext_mode_p (mode));
>
> @@ -6233,8 +6260,9 @@ riscv_get_vector_arg (struct riscv_arg_info *info, 
> const CUMULATIVE_ARGS *cum,
>    int arg_reg_end = V_ARG_LAST - V_REG_FIRST;
>    int aligned_reg_start = ROUND_UP (arg_reg_start, LMUL);
>
> -  /* For scalable data and scalable tuple return value.  */
> -  if (return_p)
> +  /* For scalable data and scalable tuple return value.
> +     For VLS CC, we may pass struct like tuple, so need defer the handling.  
> */
> +  if (return_p && !vls_p)
>      return gen_rtx_REG (mode, aligned_reg_start + V_REG_FIRST);
>
>    /* Iterate through the USED_VRS array to find vector register groups that 
> have
> @@ -6271,6 +6299,224 @@ riscv_get_vector_arg (struct riscv_arg_info *info, 
> const CUMULATIVE_ARGS *cum,
>    return NULL_RTX;
>  }
>
> +
> +#define RISCV_ALL_VALID_ABI_VLEN(F) \
> +  F (32) \
> +  F (64) \
> +  F (128) \
> +  F (256) \
> +  F (512) \
> +  F (1024) \
> +  F (2048) \
> +  F (4096) \
> +  F (8192) \
> +  F (16384)
> +
> +/* Return true if CC is a variant of VLS CC.  */
> +
> +static bool
> +riscv_vls_cc_p (riscv_cc cc)
> +{
> +  switch (cc)
> +    {
> +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \
> +  case RISCV_CC_VLS_V_##ABI_VLEN:
> +    RISCV_ALL_VALID_ABI_VLEN(VLS_CC_ABI_VLEN_CASE)
> +
> +#undef VLS_CC_ABI_VLEN_CASE
> +      return true;
> +    default:
> +      return false;
> +    }
> +}
> +
> +/* Get ABI_VLEN from cc.  */
> +
> +static unsigned int
> +riscv_get_cc_abi_vlen (riscv_cc cc)
> +{
> +  switch (cc)
> +    {
> +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \
> +      case RISCV_CC_VLS_V_##ABI_VLEN: \
> +       return ABI_VLEN;
> +    RISCV_ALL_VALID_ABI_VLEN(VLS_CC_ABI_VLEN_CASE)
> +
> +#undef VLS_CC_ABI_VLEN_CASE
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
> +/* Return true if ABI_VLEN is a valid for VLS_CC.  */
> +
> +static bool
> +riscv_valid_abi_vlen_vls_cc_p (unsigned abi_vlen)
> +{
> +  switch (abi_vlen)
> +    {
> +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \
> +  case ABI_VLEN:
> +    RISCV_ALL_VALID_ABI_VLEN(VLS_CC_ABI_VLEN_CASE)
> +
> +#undef VLS_CC_ABI_VLEN_CASE
> +      return true;
> +    default:
> +      return false;
> +    }
> +}
> +
> +static riscv_cc
> +riscv_get_riscv_cc_by_abi_vlen (unsigned abi_vlen)
> +{
> +  switch (abi_vlen)
> +    {
> +#define VLS_CC_ABI_VLEN_CASE(ABI_VLEN) \
> +      case ABI_VLEN: \
> +       return RISCV_CC_VLS_V_##ABI_VLEN;
> +    RISCV_ALL_VALID_ABI_VLEN(VLS_CC_ABI_VLEN_CASE)
> +
> +#undef VLS_CC_ABI_VLEN_CASE
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
> +/* Get a VLS type has same size as MODE in ABI_VLEN, but element is always
> +   in integer mode.  */
> +
> +static machine_mode
> +riscv_get_vls_container_type (machine_mode mode, unsigned abi_vlen)
> +{
> +  machine_mode element_mode = GET_MODE_INNER (mode);
> +  unsigned int mode_size = GET_MODE_SIZE (mode).to_constant ();
> +  unsigned int lmul = ROUND_UP (mode_size * 8, abi_vlen) / abi_vlen;
> +
> +  /* Always use integer mode to pass to simplify the logic - we allow pass
> +     unsupported vector type in vector register, e.g. float16x4_t even no 
> vector
> +     fp16 support.  */
> +  switch (GET_MODE_SIZE (element_mode).to_constant ())
> +    {
> +    case 1:
> +      element_mode = QImode;
> +      break;
> +    case 2:
> +      element_mode = HImode;
> +      break;
> +    case 4:
> +      element_mode = SImode;
> +      break;
> +    case 8:
> +      element_mode = DImode;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +
> +  scalar_mode smode = as_a<scalar_mode> (element_mode);
> +  return get_lmul_mode (smode, lmul).require ();
> +}
> +
> +/* Pass VLS type argument in vector argument register.  */
> +
> +static rtx
> +riscv_pass_vls_in_vr (struct riscv_arg_info *info, const CUMULATIVE_ARGS 
> *cum,
> +                     machine_mode mode, bool return_p)
> +{
> +  gcc_assert (riscv_v_ext_vls_mode_p (mode));
> +
> +  unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc);
> +  unsigned int mode_size = GET_MODE_SIZE (mode).to_constant ();
> +  unsigned int lmul = ROUND_UP (mode_size * 8, abi_vlen) / abi_vlen;
> +
> +  /* Put into memory if it need more than 8 registers (> LMUL 8).  */
> +  if (lmul > 8)
> +    return NULL_RTX;
> +
> +  machine_mode vla_mode = riscv_get_vls_container_type (mode, abi_vlen);
> +  rtx reg = riscv_get_vector_arg (info, cum, vla_mode,
> +                                 return_p, /* vls_p */ true);
> +
> +  /* Can't get vector register to pass, pass by memory.  */
> +  if (!reg)
> +    return NULL_RTX;
> +
> +  PUT_MODE (reg, mode);
> +
> +  return reg;
> +}
> +
> +/* Pass aggregate with VLS type argument in vector argument registers.  */
> +
> +static rtx
> +riscv_pass_aggregate_in_vr (struct riscv_arg_info *info,
> +                           const CUMULATIVE_ARGS *cum, const_tree type,
> +                           bool return_p)
> +{
> +  riscv_aggregate_field fields[8];
> +  unsigned int abi_vlen = riscv_get_cc_abi_vlen (cum->variant_cc);
> +  int i;
> +  int n = riscv_flatten_aggregate_argument (type, fields, true,
> +                                           /* vls_p */ true, abi_vlen);
> +
> +  if (n == -1)
> +    return NULL_RTX;
> +
> +  /* Check all field has same size.  */
> +  unsigned int mode_size
> +    = GET_MODE_SIZE (TYPE_MODE (fields[0].type)).to_constant ();
> +  for (int i = 1; i < n; i++)
> +    if (GET_MODE_SIZE (TYPE_MODE (fields[i].type)).to_constant () != 
> mode_size)
> +      return NULL_RTX; /* Return NULL_RTX if we cannot find a suitable reg.  
> */
> +
> +  /* Check total size is <= abi_vlen * 8, we use up to 8 vector register to
> +     pass argument.  */
> +  if (mode_size * 8 > abi_vlen)
> +    return NULL_RTX; /* Return NULL_RTX if we cannot find a suitable reg.  */
> +
> +  /* Backup cum->used_vrs since we will defer the update until
> +     riscv_function_arg_advance.  */
> +  CUMULATIVE_ARGS local_cum;
> +  memcpy (&local_cum, cum, sizeof (local_cum));
> +
> +  unsigned num_vrs = 0;
> +
> +  /* Allocate vector registers for the arguments.  */
> +  rtx expr_list[8];
> +  for (i = 0; i < n; i++)
> +    {
> +      machine_mode mode = TYPE_MODE (fields[i].type);
> +      machine_mode vla_mode = riscv_get_vls_container_type (mode, abi_vlen);
> +      /* Use riscv_get_vector_arg with VLA type to simplify the calling
> +        convention implementation.  */
> +      rtx reg
> +       = riscv_get_vector_arg (info, &local_cum, vla_mode,
> +                               return_p, /* vls_p */true);
> +
> +      /* Can't get vector register to pass, pass by memory.  */
> +      if (!reg)
> +       return NULL_RTX;
> +
> +      PUT_MODE (reg, mode);
> +
> +      expr_list[i]
> +       = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (fields[i].offset));
> +
> +      num_vrs += info->num_vrs;
> +
> +      /* Set the corresponding register in USED_VRS to used status.  */
> +      for (unsigned int i = 0; i < info->num_vrs; i++)
> +       {
> +         gcc_assert (!local_cum.used_vrs[info->vr_offset + i]);
> +         local_cum.used_vrs[info->vr_offset + i] = true;
> +       }
> +    }
> +
> +  info->num_vrs = num_vrs;
> +
> +  return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (n, expr_list));
> +}
> +
>  /* Fill INFO with information about a single argument, and return an RTL
>     pattern to pass or return the argument. Return NULL_RTX if argument cannot
>     pass or return in registers, then the argument may be passed by reference 
> or
> @@ -6363,7 +6609,17 @@ riscv_get_arg_info (struct riscv_arg_info *info, const 
> CUMULATIVE_ARGS *cum,
>        if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode))
>         return riscv_get_vector_arg (info, cum, mode, return_p);
>
> -      /* For vls mode aggregated in gpr.  */
> +      if (riscv_vls_cc_p (cum->variant_cc))
> +       {
> +         if (riscv_v_ext_vls_mode_p (mode))
> +           return riscv_pass_vls_in_vr (info, cum, mode, return_p);
> +
> +         rtx ret = riscv_pass_aggregate_in_vr (info, cum, type, return_p);
> +         if (ret)
> +           return ret;
> +       }
> +
> +      /* For vls mode aggregated in gpr (for non-VLS-CC).  */
>        if (riscv_v_ext_vls_mode_p (mode))
>         return riscv_pass_vls_aggregate_in_gpr (info, mode, gpr_base);
>      }
> @@ -6420,7 +6676,8 @@ riscv_function_arg_advance (cumulative_args_t cum_v,
>        cum->used_vrs[info.vr_offset + i] = true;
>      }
>
> -  if ((info.num_vrs > 0 || info.num_mrs > 0) && cum->variant_cc != 
> RISCV_CC_V)
> +  if ((info.num_vrs > 0 || info.num_mrs > 0) && cum->variant_cc != RISCV_CC_V
> +      && !riscv_vls_cc_p (cum->variant_cc))
>      {
>        error ("RVV type %qT cannot be passed to an unprototyped function",
>              arg.type);
> @@ -6532,14 +6789,19 @@ riscv_pass_by_reference (cumulative_args_t cum_v, 
> const function_arg_info &arg)
>  /* Implement TARGET_RETURN_IN_MEMORY.  */
>
>  static bool
> -riscv_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
> +riscv_return_in_memory (const_tree type, const_tree fntype)
>  {
>    CUMULATIVE_ARGS args;
> +
> +  if (fntype)
> +    riscv_init_cumulative_args (&args, fntype, NULL_RTX, NULL_TREE, 0);
> +  else
> +    /* The rules for returning in memory are the same as for passing the
> +       first named argument by reference.  */
> +    memset (&args, 0, sizeof args);
> +
>    cumulative_args_t cum = pack_cumulative_args (&args);
>
> -  /* The rules for returning in memory are the same as for passing the
> -     first named argument by reference.  */
> -  memset (&args, 0, sizeof args);
>    function_arg_info arg (const_cast<tree> (type), /*named=*/true);
>    return riscv_pass_by_reference (cum, arg);
>  }
> @@ -6583,9 +6845,9 @@ riscv_setup_incoming_varargs (cumulative_args_t cum,
>  /* Return the descriptor of the Standard Vector Calling Convention Variant.  
> */
>
>  static const predefined_function_abi &
> -riscv_v_abi ()
> +riscv_v_abi (riscv_cc abi)
>  {
> -  predefined_function_abi &v_abi = function_abis[RISCV_CC_V];
> +  predefined_function_abi &v_abi = function_abis[abi];
>    if (!v_abi.initialized_p ())
>      {
>        HARD_REG_SET full_reg_clobbers
> @@ -6595,7 +6857,7 @@ riscv_v_abi ()
>         CLEAR_HARD_REG_BIT (full_reg_clobbers, regno);
>        for (int regno = V_REG_FIRST + 24; regno <= V_REG_FIRST + 31; regno += 
> 1)
>         CLEAR_HARD_REG_BIT (full_reg_clobbers, regno);
> -      v_abi.initialize (RISCV_CC_V, full_reg_clobbers);
> +      v_abi.initialize (abi, full_reg_clobbers);
>      }
>    return v_abi;
>  }
> @@ -6807,6 +7069,54 @@ riscv_vector_cc_function_p (const_tree fntype)
>    return vector_cc_p;
>  }
>
> +static riscv_cc
> +riscv_get_vls_cc_attr (const_tree args)
> +{
> +  /* Default ABI_VLEN is 128.  */
> +  int abi_vlen = 128;
> +
> +  if (args && TREE_CODE (args) == TREE_LIST)
> +    {
> +      tree vlen_arg = TREE_VALUE (args);
> +      if (vlen_arg && TREE_CODE (vlen_arg) == INTEGER_CST)
> +       abi_vlen = TREE_INT_CST_LOW (vlen_arg);
> +    }
> +
> +  if (!riscv_valid_abi_vlen_vls_cc_p (abi_vlen))
> +    {
> +      error_at (input_location,
> +               "unsupported ABI_VLEN value %d for %qs attribute;"
> +               "ABI_VLEN must be in the range [32, 16384] and must be "
> +               "a power of 2.",
> +               "riscv_vls_cc", abi_vlen);
> +      return RISCV_CC_UNKNOWN;
> +    }
> +
> +  return riscv_get_riscv_cc_by_abi_vlen (abi_vlen);
> +}
> +
> +/* Return true if FUNC is a riscv_vector_cc function.
> +   For more details please reference the below link.
> +   https://github.com/riscv-non-isa/riscv-c-api-doc/pull/67 */
> +static riscv_cc
> +riscv_vls_cc_function_abi (const_tree fntype)
> +{
> +  tree attr = TYPE_ATTRIBUTES (fntype);
> +  bool vls_cc_p = lookup_attribute ("vls_cc", attr) != NULL_TREE
> +                 || lookup_attribute ("riscv_vls_cc", attr) != NULL_TREE;
> +
> +  if (!vls_cc_p)
> +    return RISCV_CC_UNKNOWN;
> +
> +  if (!TARGET_VECTOR)
> +    error_at (input_location,
> +             "function attribute %qs requires the vector ISA extension",
> +             "riscv_vls_cc");
> +
> +  tree args = TREE_VALUE (attr);
> +  return riscv_get_vls_cc_attr (args);
> +}
> +
>  /* Implement TARGET_FNTYPE_ABI.  */
>
>  static const predefined_function_abi &
> @@ -6822,7 +7132,11 @@ riscv_fntype_abi (const_tree fntype)
>    validate_v_abi_p |= riscv_vector_cc_function_p (fntype);
>
>    if (validate_v_abi_p)
> -    return riscv_v_abi ();
> +    return riscv_v_abi (RISCV_CC_V);
> +
> +  riscv_cc abi = riscv_vls_cc_function_abi (fntype);
> +  if (abi != RISCV_CC_UNKNOWN)
> +    return riscv_v_abi (abi);
>
>    return default_function_abi;
>  }
> @@ -6915,6 +7229,25 @@ riscv_handle_type_attribute (tree *node 
> ATTRIBUTE_UNUSED, tree name, tree args,
>    return NULL_TREE;
>  }
>
> +static tree
> +riscv_handle_rvv_vls_cc_attribute (tree *node, tree name, tree args,
> +                                  ATTRIBUTE_UNUSED int flags,
> +                                  bool *no_add_attrs)
> +{
> +  bool vls_cc_p = is_attribute_p ("vls_cc", name)
> +                 || is_attribute_p ("riscv_vls_cc", name);
> +
> +  if (!vls_cc_p)
> +    return NULL_TREE;
> +
> +  riscv_cc cc = riscv_get_vls_cc_attr (args);
> +
> +  if (cc == RISCV_CC_UNKNOWN)
> +    *no_add_attrs = true;
> +
> +  return NULL_TREE;
> +}
> +
>  static tree
>  riscv_handle_rvv_vector_bits_attribute (tree *node, tree name, tree args,
>                                         ATTRIBUTE_UNUSED int flags,
> @@ -11082,7 +11415,7 @@ riscv_asm_output_variant_cc (FILE *stream, const tree 
> decl, const char *name)
>    if (TREE_CODE (decl) == FUNCTION_DECL)
>      {
>        riscv_cc cc = (riscv_cc) fndecl_abi (decl).id ();
> -      if (cc == RISCV_CC_V)
> +      if (cc == RISCV_CC_V || riscv_vls_cc_p (cc))
>         {
>           fprintf (stream, "\t.variant_cc\t");
>           assemble_name (stream, name);
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index 9146571908f..a229928677f 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -779,6 +779,17 @@ enum riscv_cc
>  {
>    RISCV_CC_BASE = 0, /* Base standard RISC-V ABI.  */
>    RISCV_CC_V, /* For functions that pass or return values in V registers.  */
> +  /* For functions that pass or return values in V registers.  */
> +  RISCV_CC_VLS_V_32,
> +  RISCV_CC_VLS_V_64,
> +  RISCV_CC_VLS_V_128,
> +  RISCV_CC_VLS_V_256,
> +  RISCV_CC_VLS_V_512,
> +  RISCV_CC_VLS_V_1024,
> +  RISCV_CC_VLS_V_2048,
> +  RISCV_CC_VLS_V_4096,
> +  RISCV_CC_VLS_V_8192,
> +  RISCV_CC_VLS_V_16384,
>    RISCV_CC_UNKNOWN
>  };
>
> @@ -786,6 +797,8 @@ typedef struct {
>    /* The calling convention that current function used.  */
>    enum riscv_cc variant_cc;
>
> +  unsigned int abi_vlen;
> +
>    /* Number of integer registers used so far, up to MAX_ARGS_IN_REGISTERS. */
>    unsigned int num_gprs;
>
> --
> 2.34.1
>

Reply via email to