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
