Do you mind creating a PR to
https://github.com/riscv/riscv-elf-psabi-doc/pull/ to start the
discussion? I believe this should be documented somewhere since it
should be consistent between LLVM and GCC.

On Mon, Nov 4, 2024 at 2:26 PM Zhijin Zeng <zhijin.z...@spacemit.com> wrote:
>
> I can't find the vector function name mangling of risc-v, so in order to
> support TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN,
> TARGET_SIMD_CLONE_ADJUST and TARGET_SIMD_CLONE_USABLE, I add risc-v
> vector function mangling rules as follow:
>
>      _ZGV<x>N<y>v<v...>_<func_name>
>
>      'x' is the LMUL, if the LMUL is 1/2/4/8 and 'x' is 1/2/4/8.
>      'y' is the count of elements also 'simdlen' in gcc.
>      'v...' depends on the number of parameter, there are as many 'v'
> characters as there are parameters.
>      'func_name' is the scalar function name.
>
> Maybe it's incorrect or incomplete, but I think it's worhting
> discussing. And combined with the glibc patch, we can use libmvec in risc-v.
>
> glibc patch:
> https://inbox.sourceware.org/libc-alpha/af3aceaa-dcf1-4fa6-ad7e-a7fd7444a...@spacemit.com/
>
>
> Thanks,
>
> Zhijin
>
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 0b3b2c4cba9..d181aae4ac7 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
>
>   #define INCLUDE_MEMORY
>   #define INCLUDE_STRING
> +#include <cmath>
>   #include "config.h"
>   #include "system.h"
>   #include "coretypes.h"
> @@ -34,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "insn-config.h"
>   #include "insn-attr.h"
>   #include "recog.h"
> +#include "cgraph.h"
>   #include "output.h"
>   #include "alias.h"
>   #include "tree.h"
> @@ -5787,7 +5789,9 @@ riscv_vector_type_p (const_tree type)
>   {
>     /* Currently, only builtin scalable vector type is allowed, in the
> future,
>        more vector types may be allowed, such as GNU vector type, etc.  */
> -  return riscv_vector::builtin_type_p (type);
> +  if (!type)
> +    return false;
> +  return riscv_vector::builtin_type_p (type) || VECTOR_TYPE_P (type);
>   }
>
>   static unsigned int
> @@ -12695,6 +12699,231 @@
> riscv_stack_clash_protection_alloca_probe_range (void)
>     return STACK_CLASH_CALLER_GUARD;
>   }
>
> +/* Return true for types that could be supported as SIMD return or
> +   argument types.  */
> +
> +static bool
> +supported_simd_type (tree t)
> +{
> +  if (SCALAR_FLOAT_TYPE_P (t) || INTEGRAL_TYPE_P (t))
> +    {
> +      HOST_WIDE_INT s = tree_to_shwi (TYPE_SIZE_UNIT (t));
> +      return s == 1 || s == 2 || s == 4 || s == 8;
> +    }
> +  return false;
> +}
> +
> +static unsigned
> +lane_size (cgraph_simd_clone_arg_type clone_arg_type, tree type)
> +{
> +  gcc_assert (clone_arg_type != SIMD_CLONE_ARG_TYPE_MASK);
> +
> +  if (INTEGRAL_TYPE_P (type)
> +      || SCALAR_FLOAT_TYPE_P (type))
> +    switch (TYPE_PRECISION (type) / BITS_PER_UNIT)
> +      {
> +      default:
> +       break;
> +      case 1:
> +      case 2:
> +      case 4:
> +      case 8:
> +       return TYPE_PRECISION (type);
> +      }
> +  gcc_unreachable ();
> +}
> +
> +/* Implement TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN.  */
> +
> +static int
> +riscv_simd_clone_compute_vecsize_and_simdlen (struct cgraph_node *node,
> +                                       struct cgraph_simd_clone *clonei,
> +                                       tree base_type ATTRIBUTE_UNUSED,
> +                                       int num, bool explicit_p)
> +{
> +  tree t, ret_type;
> +  unsigned int elt_bit = 0;
> +  unsigned HOST_WIDE_INT const_simdlen;
> +
> +  if (!TARGET_VECTOR)
> +    return 0;
> +
> +  if (maybe_ne (clonei->simdlen, 0U)
> +      && clonei->simdlen.is_constant (&const_simdlen)
> +      && (const_simdlen < 2
> +         || const_simdlen > 1024
> +         || (const_simdlen & (const_simdlen - 1)) != 0))
> +    {
> +      if (explicit_p)
> +       warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                   "unsupported simdlen %wd", const_simdlen);
> +      return 0;
> +    }
> +
> +  ret_type = TREE_TYPE (TREE_TYPE (node->decl));
> +  if (TREE_CODE (ret_type) != VOID_TYPE
> +      && !supported_simd_type (ret_type))
> +    {
> +      if (!explicit_p)
> +       ;
> +      else if (COMPLEX_FLOAT_TYPE_P (ret_type))
> +       warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                   "GCC does not currently support return type %qT "
> +                   "for simd", ret_type);
> +      else
> +       warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                   "unsupported return type %qT for simd",
> +                   ret_type);
> +      return 0;
> +    }
> +
> +  auto_vec<std::pair <tree, unsigned int>> vec_elts (clonei->nargs + 1);
> +  if (TREE_CODE (ret_type) != VOID_TYPE)
> +    {
> +      elt_bit = lane_size (SIMD_CLONE_ARG_TYPE_VECTOR, ret_type);
> +      vec_elts.safe_push (std::make_pair (ret_type, elt_bit));
> +    }
> +
> +  int i;
> +  tree type_arg_types = TYPE_ARG_TYPES (TREE_TYPE (node->decl));
> +  bool decl_arg_p = (node->definition || type_arg_types == NULL_TREE);
> +  for (t = (decl_arg_p ? DECL_ARGUMENTS (node->decl) : type_arg_types),
> i = 0;
> +       t && t != void_list_node; t = TREE_CHAIN (t), i++)
> +    {
> +      tree arg_type = decl_arg_p ? TREE_TYPE (t) : TREE_VALUE (t);
> +      if (clonei->args[i].arg_type != SIMD_CLONE_ARG_TYPE_UNIFORM
> +         && !supported_simd_type (arg_type))
> +       {
> +         if (!explicit_p)
> +           ;
> +         else if (COMPLEX_FLOAT_TYPE_P (ret_type))
> +           warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                       "GCC does not currently support argument type %qT "
> +                       "for simd", arg_type);
> +         else
> +           warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                       "unsupported argument type %qT for simd",
> +                       arg_type);
> +         return 0;
> +       }
> +      unsigned lane_bits = lane_size (clonei->args[i].arg_type, arg_type);
> +      if (clonei->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
> +       vec_elts.safe_push (std::make_pair (arg_type, lane_bits));
> +      if (!elt_bit)
> +       elt_bit = lane_bits;
> +      if (elt_bit != lane_bits)
> +       return 0;
> +    }
> +
> +  if (!elt_bit)
> +    return 0;
> +
> +  clonei->vecsize_mangle = 'n';
> +  clonei->mask_mode = VOIDmode;
> +  poly_uint64 simdlen;
> +  auto_vec<poly_uint64> simdlens (2);
> +
> +  clonei->vecsize_int = 0;
> +  clonei->vecsize_float = 0;
> +
> +  if ((unsigned int)TARGET_MIN_VLEN <= elt_bit)
> +    return 0;
> +
> +  /* Keep track of the possible simdlens the clones of this function
> can have,
> +     and check them later to see if we support them.  */
> +  if (known_eq (clonei->simdlen, 0U))
> +    {
> +      if (TARGET_MAX_LMUL >= RVV_M1)
> +       simdlens.safe_push (
> +           exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M1), elt_bit));
> +      if (TARGET_MAX_LMUL >= RVV_M2)
> +       simdlens.safe_push (
> +           exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M2), elt_bit));
> +      if (TARGET_MAX_LMUL >= RVV_M4)
> +       simdlens.safe_push (
> +           exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M4), elt_bit));
> +      if (TARGET_MAX_LMUL >= RVV_M8)
> +       simdlens.safe_push (
> +           exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M8), elt_bit));
> +    }
> +  else
> +    simdlens.safe_push (clonei->simdlen);
> +
> +  unsigned j = 0;
> +  while (j < simdlens.length ())
> +    {
> +      bool remove_simdlen = false;
> +      for (auto elt : vec_elts)
> +       if (known_gt (simdlens[j] * elt.second,
> +           TARGET_MIN_VLEN * TARGET_MAX_LMUL))
> +         {
> +           /* Don't issue a warning for every simdclone when there is no
> +              specific simdlen clause.  */
> +           if (explicit_p && maybe_ne (clonei->simdlen, 0U))
> +             warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                         "GCC does not currently support simdlen %wd for "
> +                         "type %qT",
> +                         constant_lower_bound (simdlens[j]), elt.first);
> +           remove_simdlen = true;
> +           break;
> +         }
> +      if (remove_simdlen)
> +       simdlens.ordered_remove (j);
> +      else
> +       j++;
> +    }
> +
> +  int count = simdlens.length ();
> +  if (count == 0)
> +    {
> +      if (explicit_p && known_eq (clonei->simdlen, 0U))
> +       {
> +         /* Warn the user if we can't generate any simdclone.  */
> +         //simdlen = exact_div (TARGET_MIN_VLEN * LMUL, elt_bit);
> +         warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
> +                     "GCC does not currently support a simdclone with
> simdlens"
> +                     " %wd and %wd for these types.",
> +                     constant_lower_bound (simdlen),
> +                     constant_lower_bound (simdlen*2));
> +       }
> +      return 0;
> +    }
> +
> +  gcc_assert (num < count);
> +  clonei->vecsize_mangle = std::exp2 (num) + '0';
> +  clonei->simdlen = simdlens[num];
> +  return count;
> +}
> +
> +/* Implement TARGET_SIMD_CLONE_ADJUST.  */
> +
> +static void
> +riscv_simd_clone_adjust (struct cgraph_node *node)
> +{
> +  tree t = TREE_TYPE (node->decl);
> +  TYPE_ATTRIBUTES (t) = make_attribute ("riscv_vector_cc", "default",
> +                                       TYPE_ATTRIBUTES (t));
> +}
> +
> +/* Implement TARGET_SIMD_CLONE_USABLE.  */
> +
> +static int
> +riscv_simd_clone_usable (struct cgraph_node *node)
> +{
> +  switch (node->simdclone->vecsize_mangle)
> +    {
> +    case '1':
> +    case '2':
> +    case '4':
> +    case '8':
> +      if (!TARGET_VECTOR)
> +       return -1;
> +      return 0;
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
>   /* Initialize the GCC target structure.  */
>   #undef TARGET_ASM_ALIGNED_HI_OP
>   #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
> @@ -13060,6 +13289,16 @@ riscv_stack_clash_protection_alloca_probe_range
> (void)
>   #undef TARGET_C_MODE_FOR_FLOATING_TYPE
>   #define TARGET_C_MODE_FOR_FLOATING_TYPE riscv_c_mode_for_floating_type
>
> +#undef TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN
> +#define TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN \
> +  riscv_simd_clone_compute_vecsize_and_simdlen
> +
> +#undef TARGET_SIMD_CLONE_ADJUST
> +#define TARGET_SIMD_CLONE_ADJUST riscv_simd_clone_adjust
> +
> +#undef TARGET_SIMD_CLONE_USABLE
> +#define TARGET_SIMD_CLONE_USABLE riscv_simd_clone_usable
> +
>   struct gcc_target targetm = TARGET_INITIALIZER;
>
>   #include "gt-riscv.h"
> --
> 2.25.1
>
> This message and any attachment are confidential and may be privileged or 
> otherwise protected from disclosure. If you are not an intended recipient of 
> this message, please delete it and any attachment from your system and notify 
> the sender immediately by reply e-mail. Unintended recipients should not use, 
> copy, disclose or take any action based on this message or any information 
> contained in this message. Emails cannot be guaranteed to be secure or error 
> free as they can be intercepted, amended, lost or destroyed, and you should 
> take full responsibility for security checking.
>
> 本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。

Reply via email to