The RISC-V vector function name mangling specification decorated with OpenMP
has been merged. This patch implements the specification within GCC.

`mangled-vector-name := "_ZGV" <isa> <mask> <len> <parameters> "_" <func-name>`

More details in https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/455

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_vector_type_p):
        (supported_simd_type):
        (lane_size):
        (riscv_simd_clone_compute_vecsize_and_simdlen):
        (riscv_simd_clone_adjust):
        (riscv_simd_clone_usable):
        (TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN):
        (TARGET_SIMD_CLONE_ADJUST):
        (TARGET_SIMD_CLONE_USABLE):

gcc/testsuite/ChangeLog:

        * g++.target/riscv/rvv/autovec/simd-L-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-Ls-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-M-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-R-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-Rs-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-U-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-Us-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-l-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-ls-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-u-vls.C: New test.
        * g++.target/riscv/rvv/autovec/simd-v-vls.C: New test.
        * gcc.target/riscv/rvv/autovec/libmvec-exp-vls.c: New test.
        * gcc.target/riscv/rvv/autovec/libmvec-log-vla.c: New test.
        * gcc.target/riscv/rvv/autovec/libmvec-pow-vla.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 319 +++++++++++++++++-
 .../g++.target/riscv/rvv/autovec/simd-L-vls.C |  19 ++
 .../riscv/rvv/autovec/simd-Ls-vls.C           |  18 +
 .../g++.target/riscv/rvv/autovec/simd-M-vls.C |  18 +
 .../g++.target/riscv/rvv/autovec/simd-R-vls.C |  20 ++
 .../riscv/rvv/autovec/simd-Rs-vls.C           |  19 ++
 .../g++.target/riscv/rvv/autovec/simd-U-vls.C |  18 +
 .../riscv/rvv/autovec/simd-Us-vls.C           |  19 ++
 .../g++.target/riscv/rvv/autovec/simd-l-vls.C |  21 ++
 .../riscv/rvv/autovec/simd-ls-vls.C           |  19 ++
 .../g++.target/riscv/rvv/autovec/simd-u-vls.C |  18 +
 .../g++.target/riscv/rvv/autovec/simd-v-vls.C |  21 ++
 .../riscv/rvv/autovec/libmvec-exp-vls.c       |  38 +++
 .../riscv/rvv/autovec/libmvec-log-vla.c       |  32 ++
 .../riscv/rvv/autovec/libmvec-pow-vla.c       |  20 ++
 15 files changed, 618 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-L-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Ls-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-M-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-R-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Rs-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-U-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Us-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-l-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-ls-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-u-vls.C
 create mode 100644 gcc/testsuite/g++.target/riscv/rvv/autovec/simd-v-vls.C
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-exp-vls.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-log-vla.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-pow-vla.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 251da7c0999..1c5a870b14d 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -35,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"
@@ -6919,7 +6920,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
@@ -14721,6 +14724,310 @@ riscv_bitint_type_info (int n, struct bitint_info 
*info)
   info->extended = bitint_ext_full;
   return true;
 }
+/* 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) || POINTER_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 (POINTER_TYPE_P (type))
+    switch (clone_arg_type)
+      {
+      default:
+       break;
+      case SIMD_CLONE_ARG_TYPE_UNIFORM:
+      case SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP:
+      case SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP:
+      case SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP:
+      case SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP:
+      case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
+      case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
+       type = TREE_TYPE (type);
+       break;
+      }
+
+
+  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);
+      }
+
+  return POINTER_SIZE;
+}
+
+/* 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 nds_elt_bits;
+  unsigned int wds_elt_bits;
+  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)
+    {
+      nds_elt_bits = lane_size (SIMD_CLONE_ARG_TYPE_VECTOR, ret_type);
+      vec_elts.safe_push (std::make_pair (ret_type, nds_elt_bits));
+      wds_elt_bits = nds_elt_bits;
+    }
+  else
+    {
+      nds_elt_bits = 0;
+      wds_elt_bits = 0;
+    }
+
+  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 (nds_elt_bits > lane_bits)
+       nds_elt_bits = lane_bits;
+      if (wds_elt_bits < lane_bits)
+       wds_elt_bits = lane_bits;
+    }
+
+  if (wds_elt_bits == 0)
+    wds_elt_bits = POINTER_SIZE;
+
+  clonei->vecsize_mangle = 'n';
+  clonei->mask_mode = VOIDmode;
+  poly_uint64 simdlen;
+
+  typedef struct
+    {
+      poly_uint64 len;
+      char mangle;
+    } riscv_clone_info;
+  auto_vec<riscv_clone_info, 3> clones;
+
+  clonei->vecsize_int = 0;
+  clonei->vecsize_float = 0;
+
+  if ((unsigned int)TARGET_MIN_VLEN <= wds_elt_bits)
+    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 && (wds_elt_bits == nds_elt_bits))
+       clones.safe_push (
+           {exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M1),
+                       wds_elt_bits), '1'});
+      if (TARGET_MAX_LMUL >= RVV_M2)
+       clones.safe_push (
+           {exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M2),
+                       wds_elt_bits), '2'});
+      if (TARGET_MAX_LMUL >= RVV_M4)
+       clones.safe_push (
+           {exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M4),
+                       wds_elt_bits), '4'});
+      if (TARGET_MAX_LMUL >= RVV_M8)
+       clones.safe_push (
+           {exact_div (poly_uint64 (TARGET_MIN_VLEN * RVV_M8),
+                       wds_elt_bits), '8'});
+
+      if (prototype_p (TREE_TYPE (node->decl))
+         && !node->definition
+         && rvv_vector_bits != RVV_VECTOR_BITS_ZVL)
+       {
+         if (TARGET_MAX_LMUL >= RVV_M1 && (wds_elt_bits == nds_elt_bits))
+           clones.safe_push (
+               {exact_div (BITS_PER_RISCV_VECTOR, wds_elt_bits), '1'});
+         if (TARGET_MAX_LMUL >= RVV_M2)
+           clones.safe_push (
+               {exact_div (BITS_PER_RISCV_VECTOR, wds_elt_bits), '2'});
+         if (TARGET_MAX_LMUL >= RVV_M4)
+           clones.safe_push (
+               {exact_div (BITS_PER_RISCV_VECTOR, wds_elt_bits), '4'});
+         if (TARGET_MAX_LMUL >= RVV_M8)
+           clones.safe_push (
+               {exact_div (BITS_PER_RISCV_VECTOR, wds_elt_bits), '8'});
+       }
+    }
+  else
+    {
+      if (TARGET_MAX_LMUL >= RVV_M1 && (wds_elt_bits == nds_elt_bits)
+         && maybe_ge (poly_uint64 (TARGET_MIN_VLEN * RVV_M1),
+                      wds_elt_bits * clonei->simdlen))
+       clones.safe_push ({clonei->simdlen, '1'});
+      if (TARGET_MAX_LMUL >= RVV_M2
+         && maybe_ge (poly_uint64 (TARGET_MIN_VLEN * RVV_M2),
+                      wds_elt_bits * clonei->simdlen))
+       clones.safe_push ({clonei->simdlen, '2'});
+      if (TARGET_MAX_LMUL >= RVV_M4
+         && maybe_ge (poly_uint64 (TARGET_MIN_VLEN * RVV_M4),
+                      wds_elt_bits * clonei->simdlen))
+       clones.safe_push ({clonei->simdlen, '4'});
+      if (TARGET_MAX_LMUL >= RVV_M8
+         && maybe_ge (poly_uint64 (TARGET_MIN_VLEN * RVV_M8),
+                      wds_elt_bits * clonei->simdlen))
+       clones.safe_push ({clonei->simdlen, '8'});
+    }
+
+  unsigned j = 0;
+  while (j < clones.length ())
+    {
+      bool remove_simdlen = false;
+      for (auto elt : vec_elts)
+       if (known_gt (clones[j].len * 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 (clones[j].len), elt.first);
+           remove_simdlen = true;
+           break;
+         }
+      if (remove_simdlen)
+       clones.ordered_remove (j);
+      else
+       j++;
+    }
+
+  int count = clones.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->extend_isa_mangle[0] = 'r';
+  clonei->extend_isa_mangle[1] = clones[num].mangle;
+  clonei->extend_isa_mangle[2] = 0;
+  clonei->vecsize_mangle = 'W';
+  clonei->simdlen = clones[num].len;
+  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,
+                        machine_mode vector_mode ATTRIBUTE_UNUSED)
+{
+  if (node->simdclone->vecsize_mangle != 'W')
+    gcc_unreachable ();
+  if (node->simdclone->extend_isa_mangle[0] != 'r')
+    gcc_unreachable ();
+
+  switch (node->simdclone->extend_isa_mangle[1])
+    {
+    case '1':
+    case '2':
+    case '4':
+    case '8':
+    case 'x':
+      if (!TARGET_VECTOR)
+       return -1;
+      return 0;
+    default:
+      gcc_unreachable ();
+    }
+}
 
 /* This parses the version string STR and modifies the feature mask and
    priority required to select those targets.
@@ -16942,6 +17249,16 @@ riscv_memtag_tag_bitsize ()
 #undef TARGET_DOCUMENTATION_NAME
 #define TARGET_DOCUMENTATION_NAME "RISC-V"
 
+#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"
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-L-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-L-vls.C
new file mode 100644
index 00000000000..db0c8f7cf26
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-L-vls.C
@@ -0,0 +1,19 @@
+/* Test vectorization via SIMD clone in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(val(i))
+extern int foo (int& i) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int& i)
+{
+  return i;
+}
+}
+/* VLS mode: VLEN=256.
+   Symbol format: _ZGVr<LMUL>N<simdlen>v_<func>
+   simdlen = (VLEN * LMUL) / elem_bits.
+   The compiler picks one LMUL, so exactly one of the variants appears.
+
+/* { dg-final { scan-assembler {_ZGVr[248]N(8|16|32)L_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Ls-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Ls-vls.C
new file mode 100644
index 00000000000..00333969b0f
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Ls-vls.C
@@ -0,0 +1,18 @@
+/* Test SIMD clone with linear val variable step parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(val(i) : s) uniform(s)
+extern int foo (int& i, int s) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int& i, int s)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   'Ls1' = linear(val(i) : s) with variable step, s is arg index 1.
+   'u' = uniform(s).  */
+/* { dg-final { scan-assembler {_ZGVr[248]N(8|16|32)Ls1u_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-M-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-M-vls.C
new file mode 100644
index 00000000000..655e1402cea
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-M-vls.C
@@ -0,0 +1,18 @@
+/* Test SIMD clone with inbranch (masked) parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd inbranch
+extern int foo (int x) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int x)
+{
+  return x;
+}
+}
+
+/* VLS mode: VLEN=256.
+   foo (int, 32-bit): r1N8 | r2N16 | r4N32 | r8N64
+   'M' = inbranch (masked), 'v' = vector(x).  */
+/* { dg-final { scan-assembler {_ZGVr[1248]M(8|16|32|64)v_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-R-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-R-vls.C
new file mode 100644
index 00000000000..187b607eba5
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-R-vls.C
@@ -0,0 +1,20 @@
+/* Test vectorization via SIMD clone in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(ref(i))
+extern int foo (int& i) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int& i)
+{
+  return i;
+}
+}
+/* VLS mode: VLEN=256.
+   Symbol format: _ZGVr<LMUL>N<simdlen>v_<func>
+   simdlen = (VLEN * LMUL) / elem_bits.
+   The compiler picks one LMUL, so exactly one of the variants appears.
+
+   foo (int, 32-bit):  r1N8 | r2N16 | r4N32 | r8N64  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)R4_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Rs-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Rs-vls.C
new file mode 100644
index 00000000000..3ba560d1d58
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Rs-vls.C
@@ -0,0 +1,19 @@
+/* Test SIMD clone with linear ref variable step parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(ref(i) : s) uniform(s)
+extern int foo (int& i, int s) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int& i, int s)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   foo (int, 32-bit): r1N8 | r2N16 | r4N32 | r8N64
+   'Rs1' = linear(ref(i) : s) with variable step, s is arg index 1.
+   'u' = uniform(s).  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)Rs1u_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-U-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-U-vls.C
new file mode 100644
index 00000000000..b0c1679032f
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-U-vls.C
@@ -0,0 +1,18 @@
+/* Test SIMD clone with linear uval (constant step) parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(uval(i))
+extern int foo (int& i) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int& i)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   foo (int, 32-bit): r1N8 | r2N16 | r4N32 | r8N64
+   'U' = linear(uval(i)) with constant step.  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)U_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Us-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Us-vls.C
new file mode 100644
index 00000000000..884816a329c
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-Us-vls.C
@@ -0,0 +1,19 @@
+/* Test SIMD clone with linear uval variable step parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(uval(i) : s) uniform(s)
+extern int foo (int& i, int s) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int& i, int s)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   foo (int, 32-bit): r1N8 | r2N16 | r4N32 | r8N64
+   'Us1' = linear(uval(i) : s) with variable step, s is arg index 1.
+   'u' = uniform(s).  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)Us1u_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-l-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-l-vls.C
new file mode 100644
index 00000000000..ca94c43a2ca
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-l-vls.C
@@ -0,0 +1,21 @@
+/* Test vectorization via SIMD clone in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(i)
+extern int foo (int i) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int i)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   Symbol format: _ZGVr<LMUL>N<simdlen>v_<func>
+   simdlen = (VLEN * LMUL) / elem_bits.
+   The compiler picks one LMUL, so exactly one of the variants appears.
+
+   foo (int, 32-bit):  r1N8 | r2N16 | r4N32 | r8N64  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)l_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-ls-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-ls-vls.C
new file mode 100644
index 00000000000..7270db1ca3a
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-ls-vls.C
@@ -0,0 +1,19 @@
+/* Test SIMD clone with linear variable step parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch linear(i : s) uniform(s)
+extern int foo (int i, int s) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int i, int s)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   foo (int, 32-bit): r1N8 | r2N16 | r4N32 | r8N64
+   'ls1' = linear(i : s) with variable step, s is arg index 1.
+   'u' = uniform(s).  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)ls1u_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-u-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-u-vls.C
new file mode 100644
index 00000000000..6d6d826e306
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-u-vls.C
@@ -0,0 +1,18 @@
+/* Test SIMD clone with uniform parameter in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch uniform(i)
+extern int foo (int i) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int i)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   foo (int, 32-bit): r1N8 | r2N16 | r4N32 | r8N64
+   'u' = uniform(i).  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)u_foo} } } */
diff --git a/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-v-vls.C 
b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-v-vls.C
new file mode 100644
index 00000000000..4cce160d10c
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/rvv/autovec/simd-v-vls.C
@@ -0,0 +1,21 @@
+/* Test vectorization via SIMD clone in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Wno-deprecated-openmp 
-mrvv-max-lmul=m8 -Ofast -ftree-vectorize -fopenmp-simd -mrvv-vector-bits=zvl" 
} */
+
+extern "C" {
+#pragma omp declare simd notinbranch
+extern int foo (int i) __attribute__ ((__nothrow__ , __leaf__, const));
+
+int foo(int i)
+{
+  return i;
+}
+}
+
+/* VLS mode: VLEN=256.
+   Symbol format: _ZGVr<LMUL>N<simdlen>v_<func>
+   simdlen = (VLEN * LMUL) / elem_bits.
+   The compiler picks one LMUL, so exactly one of the variants appears.
+
+   foo (int, 32-bit):  r1N8 | r2N16 | r4N32 | r8N64  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)v_foo} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-exp-vls.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-exp-vls.c
new file mode 100644
index 00000000000..f04b5fede0e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-exp-vls.c
@@ -0,0 +1,38 @@
+/* Test vectorization of exp() via libmvec SIMD clone in VLS mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -Ofast -ftree-vectorize 
-fopenmp-simd -mrvv-vector-bits=zvl" } */
+
+#pragma omp declare simd notinbranch
+extern double exp (double);
+
+#pragma omp declare simd notinbranch
+extern float expf (float);
+
+#define N 1024
+double __attribute__ ((aligned (32))) a[N], b[N];
+float __attribute__ ((aligned (32))) af[N], bf[N];
+
+void
+vectorized_exp_double (void)
+{
+  for (int i = 0; i < N; i++)
+    a[i] = exp (b[i]);
+}
+
+void
+vectorized_expf (void)
+{
+  for (int i = 0; i < N; i++)
+    af[i] = expf (bf[i]);
+}
+
+/* VLS mode: VLEN=256.
+   Symbol format: _ZGVr<LMUL>N<simdlen>v_<func>
+   simdlen = (VLEN * LMUL) / elem_bits.
+   The compiler picks one LMUL, so exactly one of the variants appears.
+
+   exp (double, 64-bit):  r1N4 | r2N8 | r4N16 | r8N32
+   expf (float, 32-bit):  r1N8 | r2N16 | r4N32 | r8N64  */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(4|8|16|32)v_exp} } } */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(4|8|16|32)v_exp} } } */
+/* { dg-final { scan-assembler {_ZGVr[1248]N(8|16|32|64)v_expf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-log-vla.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-log-vla.c
new file mode 100644
index 00000000000..6c013772299
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-log-vla.c
@@ -0,0 +1,32 @@
+/* Test vectorization of log()/logf() via libmvec SIMD clone in VLA mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -Ofast -ftree-vectorize 
-fopenmp-simd -mrvv-vector-bits=scalable" } */
+
+#pragma omp declare simd notinbranch
+extern double log (double);
+
+#pragma omp declare simd notinbranch
+extern float logf (float);
+
+#define N 1024
+double __attribute__ ((aligned (32))) a[N], b[N];
+float __attribute__ ((aligned (32))) af[N], bf[N];
+
+void
+vectorized_log (void)
+{
+  for (int i = 0; i < N; i++)
+    a[i] = log (b[i]);
+}
+
+void
+vectorized_logf (void)
+{
+  for (int i = 0; i < N; i++)
+    af[i] = logf (bf[i]);
+}
+
+/* VLA mode: scalable vector length, simdlen is 'x'.
+   Compiler picks one LMUL, symbol uses 'x' instead of a fixed simdlen.  */
+/* { dg-final { scan-assembler {_ZGVr[1248]Nxv_log} } } */
+/* { dg-final { scan-assembler {_ZGVr[1248]Nxv_logf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-pow-vla.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-pow-vla.c
new file mode 100644
index 00000000000..e9b7de168da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/libmvec-pow-vla.c
@@ -0,0 +1,20 @@
+/* Test vectorization of pow() via libmvec SIMD clone in VLA mode.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -Ofast -ftree-vectorize 
-fopenmp-simd -mrvv-vector-bits=scalable" } */
+
+#pragma omp declare simd notinbranch
+extern double pow (double, double);
+
+#define N 1024
+double __attribute__ ((aligned (32))) a[N], b[N], c[N];
+
+void
+vectorized_pow (void)
+{
+  for (int i = 0; i < N; i++)
+    a[i] = pow (b[i], c[i]);
+}
+
+/* VLA mode: scalable vector length, simdlen is 'x'.
+   pow has two vector args (vv).  */
+/* { dg-final { scan-assembler {_ZGVr[1248]Nxvv_pow} } } */
-- 
2.25.1

Reply via email to