diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 722139b0628d6..22fd2b3a95260 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -366,6 +366,7 @@ enum avl_type void init_builtins (void); const char *mangle_builtin_type (const_tree); tree lookup_vector_type_attribute (const_tree); +bool builtin_type_p (const_tree); #ifdef GCC_TARGET_H bool verify_type_context (location_t, type_context_kind, const_tree, bool); bool expand_vec_perm_const (machine_mode, machine_mode, rtx, rtx, rtx, diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 6be99f7b68e1a..c2767713d1f41 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -3992,6 +3992,16 @@ mangle_builtin_type (const_tree type) return NULL; } +/* Return true if TYPE is a built-in RVV type defined by the ABI. */ +bool +builtin_type_p (const_tree type) +{ + if (!type) + return false; + + return lookup_vector_type_attribute (type); +} + /* Initialize all compiler built-ins related to RVV that should be defined at start-up. */ void diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 0e782f07659b4..cff53392a6d87 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -202,6 +202,18 @@ struct riscv_arg_info { /* The offset of the first register used, provided num_fprs is nonzero. */ unsigned int fpr_offset; + + /* The number of vector registers allocated to this argument. */ + unsigned int num_vrs; + + /* The offset of the first register used, provided num_vrs is nonzero. */ + unsigned int vr_offset; + + /* The number of mask registers allocated to this argument. */ + unsigned int num_mrs; + + /* The offset of the first register used, provided num_mrs is nonzero. */ + unsigned int mr_offset; }; /* One stage in a constant building sequence. These sequences have @@ -4413,6 +4425,11 @@ riscv_init_cumulative_args (CUMULATIVE_ARGS *cum, { memset (cum, 0, sizeof (*cum)); + if (fntype) + cum->variant_cc = (riscv_cc) fntype_abi (fntype).id (); + else + cum->variant_cc = RISCV_CC_BASE; + if (fndecl) { const tree_function_decl &fn @@ -4423,12 +4440,105 @@ riscv_init_cumulative_args (CUMULATIVE_ARGS *cum, } } -/* Fill INFO with information about a single argument, and return an - RTL pattern to pass or return the argument. CUM is the cumulative - state for earlier arguments. MODE is the mode of this argument and - TYPE is its type (if known). NAMED is true if this is a named - (fixed) argument rather than a variable one. RETURN_P is true if - returning the argument, or false if passing the argument. */ +/* Return true if TYPE is a vector type that can be passed in vector registers. + */ + +static bool +riscv_vector_type_p (const_tree type) +{ + /* Currently, only builtin scalabler 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); +} + +static unsigned int +riscv_hard_regno_nregs (unsigned int regno, machine_mode mode); + +/* Subroutine of riscv_get_arg_info. */ + +static rtx +riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, + machine_mode mode, bool return_p) +{ + gcc_assert (riscv_v_ext_mode_p (mode)); + + info->mr_offset = cum->num_mrs; + if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) + { + /* For scalable mask return value. */ + if (return_p) + return gen_rtx_REG (mode, V_REG_FIRST); + + /* For the first scalable mask argument. */ + if (info->mr_offset < MAX_ARGS_IN_MASK_REGISTERS) + { + info->num_mrs = 1; + return gen_rtx_REG (mode, V_REG_FIRST); + } + else + { + /* Rest scalable mask arguments are treated as scalable data + arguments. */ + } + } + + /* The number and alignment of vector registers need for this scalable vector + argument. When the mode size is less than a full vector, we use 1 vector + register to pass. Just call TARGET_HARD_REGNO_NREGS for the number + information. */ + int nregs = riscv_hard_regno_nregs (V_ARG_FIRST, mode); + int LMUL = riscv_v_ext_tuple_mode_p (mode) + ? nregs / riscv_vector::get_nf (mode) + : nregs; + int arg_reg_start = V_ARG_FIRST - V_REG_FIRST; + 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) + return gen_rtx_REG (mode, aligned_reg_start + V_REG_FIRST); + + /* Iterate through the USED_VRS array to find vector register groups that have + not been allocated and the first register is aligned with LMUL. */ + for (int i = aligned_reg_start; i + nregs - 1 <= arg_reg_end; i += LMUL) + { + /* The index in USED_VRS array. */ + int idx = i - arg_reg_start; + /* Find the first register unused. */ + if (!cum->used_vrs[idx]) + { + bool find_set = true; + /* Ensure there are NREGS continuous unused registers. */ + for (int j = 1; j < nregs; j++) + if (cum->used_vrs[idx + j]) + { + find_set = false; + /* Update I to the last aligned register which + cannot be used and the next iteration will add + LMUL step to I. */ + i += (j / LMUL) * LMUL; + break; + } + + if (find_set) + { + info->num_vrs = nregs; + info->vr_offset = idx; + return gen_rtx_REG (mode, i + V_REG_FIRST); + } + } + } + + return NULL_RTX; +} + +/* 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 + through the stack or . CUM is the cumulative state for earlier arguments. + MODE is the mode of this argument and TYPE is its type (if known). NAMED is + true if this is a named (fixed) argument rather than a variable one. RETURN_P + is true if returning the argument, or false if passing the argument. */ static rtx riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, @@ -4450,11 +4560,9 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, riscv_pass_in_vector_p (type); } - /* All current vector arguments and return values are passed through the - function stack. Ideally, we should either warn the user not to use an RVV - vector type as function argument or support a calling convention - with better performance. */ - if (riscv_v_ext_mode_p (mode)) + /* When disable vector_abi or scalable vector argument is anonymous, this + argument is passed by reference. */ + if (riscv_v_ext_mode_p (mode) && (!riscv_vector_abi || !named)) return NULL_RTX; if (named) @@ -4518,6 +4626,10 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, gregno, TYPE_MODE (fields[1].type), fields[1].offset); } + + /* For scalable vector argument. */ + if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode)) + return riscv_get_vector_arg (info, cum, mode, return_p); } /* Work out the size of the argument. */ @@ -4564,12 +4676,28 @@ riscv_function_arg_advance (cumulative_args_t cum_v, riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); + /* Set the corresponding register in USED_VRS to used status. */ + for (unsigned int i = 0; i < info.num_vrs; i++) + { + gcc_assert (!cum->used_vrs[info.vr_offset + i]); + cum->used_vrs[info.vr_offset + i] = true; + } + + if ((info.num_vrs > 0 || info.num_mrs > 0) && cum->variant_cc != RISCV_CC_V) + { + error ("RVV type %qT cannot be passed to an unprototyped function", + arg.type); + /* Avoid repeating the message */ + cum->variant_cc = RISCV_CC_V; + } + /* Advance the register count. This has the effect of setting num_gprs to MAX_ARGS_IN_REGISTERS if a doubleword-aligned argument required us to skip the final GPR and pass the whole argument on the stack. */ cum->num_fprs = info.fpr_offset + info.num_fprs; cum->num_gprs = info.gpr_offset + info.num_gprs; + cum->num_mrs = info.mr_offset + info.num_mrs; } /* Implement TARGET_ARG_PARTIAL_BYTES. */ @@ -4631,20 +4759,23 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); /* ??? std_gimplify_va_arg_expr passes NULL for cum. Fortunately, we - never pass variadic arguments in floating-point registers, so we can - avoid the call to riscv_get_arg_info in this case. */ + never pass variadic arguments in floating-point and vector registers, + so we can avoid the call to riscv_get_arg_info in this case. */ if (cum != NULL) { /* Don't pass by reference if we can use a floating-point register. */ riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); if (info.num_fprs) return false; + + /* Don't pass by reference if we can use vector register groups. */ + if (info.num_vrs > 0 || info.num_mrs > 0) + return false; } - /* All current vector arguments and return values are passed through the - function stack. Ideally, we should either warn the user not to use an RVV - vector type as function argument or support a calling convention - with better performance. */ + /* When vector abi disabled(without --param=riscv-vector-abi option) or + scalable vector argument is anonymous or cannot be passed through vector + registers, this argument is passed by reference. */ if (riscv_v_ext_mode_p (arg.mode)) return true; @@ -4702,6 +4833,73 @@ riscv_setup_incoming_varargs (cumulative_args_t cum, cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD; } +/* Return the descriptor of the Standard Vector Calling Convention Variant. */ + +static const predefined_function_abi & +riscv_v_abi () +{ + predefined_function_abi &v_abi = function_abis[RISCV_CC_V]; + if (!v_abi.initialized_p ()) + { + HARD_REG_SET full_reg_clobbers + = default_function_abi.full_reg_clobbers (); + /* Callee-saved vector registers: v1-v7, v24-v31. */ + for (int regno = V_REG_FIRST + 1; regno <= V_REG_FIRST + 7; regno += 1) + 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); + } + return v_abi; +} + +/* Return true if a function with type FNTYPE returns its value in + RISC-V V registers. */ + +static bool +riscv_return_value_is_vector_type_p (const_tree fntype) +{ + tree return_type = TREE_TYPE (fntype); + + return riscv_vector_type_p (return_type); +} + +/* Return true if a function with type FNTYPE takes arguments in + RISC-V V registers. */ + +static bool +riscv_arguments_is_vector_type_p (const_tree fntype) +{ + for (tree chain = TYPE_ARG_TYPES (fntype); chain && chain != void_list_node; + chain = TREE_CHAIN (chain)) + { + tree arg_type = TREE_VALUE (chain); + if (riscv_vector_type_p (arg_type)) + return true; + } + + return false; +} + +/* Implement TARGET_FNTYPE_ABI. */ + +static const predefined_function_abi & +riscv_fntype_abi (const_tree fntype) +{ + /* Implementing an experimental vector calling convention, the proposal + can be viewed at the bellow link: + https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 + + You can enable this feature via the `--param=riscv-vector-abi` compiler + option. */ + if (riscv_vector_abi + && (riscv_return_value_is_vector_type_p (fntype) + || riscv_arguments_is_vector_type_p (fntype))) + return riscv_v_abi (); + + return default_function_abi; +} + /* Handle an attribute requiring a FUNCTION_DECL; arguments as in struct attribute_spec.handler. */ static tree @@ -9159,6 +9357,8 @@ riscv_vectorize_create_costs (vec_info *vinfo, bool costing_for_scalar) #define TARGET_FUNCTION_ARG_ADVANCE riscv_function_arg_advance #undef TARGET_FUNCTION_ARG_BOUNDARY #define TARGET_FUNCTION_ARG_BOUNDARY riscv_function_arg_boundary +#undef TARGET_FNTYPE_ABI +#define TARGET_FNTYPE_ABI riscv_fntype_abi #undef TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS #define TARGET_SHRINK_WRAP_GET_SEPARATE_COMPONENTS \ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 265ed1b98ec16..1f9cbcfbe4fc5 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_RISCV_H #define GCC_RISCV_H +#include #include "config/riscv/riscv-opts.h" /* Target CPU builtins. */ @@ -666,6 +667,9 @@ enum reg_class #define MAX_ARGS_IN_REGISTERS (riscv_abi == ABI_ILP32E ? 6 : 8) +#define MAX_ARGS_IN_VECTOR_REGISTERS (16) +#define MAX_ARGS_IN_MASK_REGISTERS (1) + /* Symbolic macros for the first/last argument registers. */ #define GP_ARG_FIRST (GP_REG_FIRST + 10) @@ -673,6 +677,8 @@ enum reg_class #define GP_TEMP_FIRST (GP_REG_FIRST + 5) #define FP_ARG_FIRST (FP_REG_FIRST + 10) #define FP_ARG_LAST (FP_ARG_FIRST + MAX_ARGS_IN_REGISTERS - 1) +#define V_ARG_FIRST (V_REG_FIRST + 8) +#define V_ARG_LAST (V_ARG_FIRST + MAX_ARGS_IN_VECTOR_REGISTERS - 1) #define CALLEE_SAVED_REG_NUMBER(REGNO) \ ((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 : \ @@ -696,7 +702,19 @@ enum reg_class (IN_RANGE ((N), GP_ARG_FIRST, GP_ARG_LAST) \ || (UNITS_PER_FP_ARG && IN_RANGE ((N), FP_ARG_FIRST, FP_ARG_LAST))) +/* Define the standard RISC-V calling convention and variants. */ + +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. */ + RISCV_CC_UNKNOWN +}; + typedef struct { + /* The calling convention that current function used. */ + enum riscv_cc variant_cc; + /* Number of integer registers used so far, up to MAX_ARGS_IN_REGISTERS. */ unsigned int num_gprs; @@ -704,6 +722,13 @@ typedef struct { unsigned int num_fprs; int rvv_psabi_warning; + + /* Number of mask registers used so far, up to MAX_ARGS_IN_MASK_REGISTERS. */ + unsigned int num_mrs; + + /* The used state of args in vector registers, true for used by prev arg, + initial to false. */ + bool used_vrs[MAX_ARGS_IN_VECTOR_REGISTERS]; } CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 8d2e8ff2bf4d9..c62a2bf32d282 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -317,3 +317,8 @@ Enum(riscv_autovec_lmul) String(dynamic) Value(RVV_DYNAMIC) -param=riscv-autovec-lmul= Target RejectNegative Joined Enum(riscv_autovec_lmul) Var(riscv_autovec_lmul) Init(RVV_M1) -param=riscv-autovec-lmul= Set the RVV LMUL of auto-vectorization in the RISC-V port. + +-param=riscv-vector-abi +Target Undocumented Bool Var(riscv_vector_abi) Init(0) +Enable the use of vector registers for function arguments and return value. +This is an experimental switch and may be subject to change in the future. diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c new file mode 100644 index 0000000000000..060d09ef9e35e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c @@ -0,0 +1,127 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-additional-sources abi-call-args-1.c } */ + +#include +#include +#include +#include +#include "riscv_vector.h" + +#define FOO_(TYPE) void foo_##TYPE (TYPE val, TYPE *out); + +FOO_ (vbool1_t) +FOO_ (vbool2_t) +FOO_ (vbool4_t) +FOO_ (vbool8_t) +FOO_ (vbool16_t) +FOO_ (vbool32_t) +FOO_ (vbool64_t) +FOO_ (vint8mf8_t) +FOO_ (vint8mf4_t) +FOO_ (vint8mf2_t) +FOO_ (vint8m1_t) +FOO_ (vint8m2_t) +FOO_ (vint8m4_t) +FOO_ (vint8m8_t) +FOO_ (vint8m1x5_t) +FOO_ (vint8m1x8_t) +FOO_ (vint8m2x3_t) +FOO_ (vint8m2x4_t) +FOO_ (vint8m4x2_t) + +bool +check_mask (int8_t *test_data, int8_t *golden_data, size_t vl) +{ + size_t i = 0; + for (; i + 8 <= vl; i += 8) + { + if (test_data[i / 8] != golden_data[i / 8]) + { + printf ("mask diff %lu: %d, %d\n", i / 8, test_data[i / 8], + golden_data[i / 8]); + return false; + } + } + if (vl % 8 != 0) + { + if ((test_data[i / 8] << (8 - (vl % 8))) + != (golden_data[i / 8] << (8 - (vl % 8)))) + { + printf ("mask tail diff %lu, tail %d: %d, %d\n", i / 8, vl % 8, + test_data[i / 8], golden_data[i / 8]); + return false; + } + } + return true; +} + +bool +check_data (int8_t *test_data, int8_t *golden_data, size_t vl) +{ + for (size_t i = 0; i < vl; i += 1) + { + if (test_data[i] != golden_data[i]) + { + printf ("data diff %lu: %d, %d\n", i, test_data[i], golden_data[i]); + return false; + } + } + return true; +} + +#define INIT_DATA \ + size_t vlmax_e8m8 = __riscv_vsetvlmax_e8m8 (); \ + int8_t golden_data[vlmax_e8m8]; \ + memset (golden_data, 0, vlmax_e8m8 * sizeof (int8_t)); \ + int8_t test_data[vlmax_e8m8]; \ + memset (test_data, 0, vlmax_e8m8 * sizeof (int8_t)); \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + golden_data[i] = vlmax_e8m8 - 1; + +#define FOO_MASK(TYPE, VL) \ + { \ + INIT_DATA \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + test_data[i] = 0; \ + TYPE val = *(TYPE *) golden_data; \ + foo_##TYPE (val, (TYPE *) test_data); \ + if (!check_mask (test_data, golden_data, VL)) \ + abort (); \ + } + +#define FOO_DATA(TYPE, VL) \ + { \ + INIT_DATA \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + test_data[i] = 0; \ + TYPE val = *(TYPE *) golden_data; \ + foo_##TYPE (val, (TYPE *) test_data); \ + if (!check_data (test_data, golden_data, VL)) \ + abort (); \ + } + +int +main () +{ + size_t vlmax = __riscv_vsetvlmax_e8mf8 (); + FOO_MASK (vbool1_t, vlmax * 64) + FOO_MASK (vbool2_t, vlmax * 32) + FOO_MASK (vbool4_t, vlmax * 16) + FOO_MASK (vbool8_t, vlmax * 8) + FOO_MASK (vbool16_t, vlmax * 4) + FOO_MASK (vbool32_t, vlmax * 2) + FOO_MASK (vbool64_t, vlmax) + FOO_DATA (vint8mf8_t, vlmax) + FOO_DATA (vint8mf4_t, vlmax * 2) + FOO_DATA (vint8mf2_t, vlmax * 4) + FOO_DATA (vint8m1_t, vlmax * 8) + FOO_DATA (vint8m2_t, vlmax * 16) + FOO_DATA (vint8m4_t, vlmax * 32) + FOO_DATA (vint8m8_t, vlmax * 64) + FOO_DATA (vint8m1x5_t, vlmax * 8 * 5) + FOO_DATA (vint8m1x8_t, vlmax * 8 * 8) + FOO_DATA (vint8m2x3_t, vlmax * 16 * 3) + FOO_DATA (vint8m2x4_t, vlmax * 16 * 4) + FOO_DATA (vint8m4x2_t, vlmax * 32 * 2) +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c new file mode 100644 index 0000000000000..067e61303b1b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c @@ -0,0 +1,197 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +#define FOO_(TYPE) \ + void foo_##TYPE (TYPE val, TYPE *out) \ + { \ + *out = val; \ + } + +/* Test the first vector mask type argument */ + +/* +** foo_vbool1_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool1_t) + +/* +** foo_vbool2_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool2_t) + +/* +** foo_vbool4_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool4_t) + +/* +** foo_vbool8_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool8_t) + +/* +** foo_vbool16_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool16_t) + +/* +** foo_vbool32_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool32_t) + +/* +** foo_vbool64_t: +** ... +** vsm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool64_t) + +/* Test the first vector data type argument */ + +/* +** foo_vint8mf8_t: +** ... +** vse8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8mf8_t) + +/* +** foo_vint8mf4_t: +** ... +** vse8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8mf4_t) + +/* +** foo_vint8mf2_t: +** ... +** vse8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8mf2_t) + +/* +** foo_vint8m1_t: +** vs1r\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m1_t) + +/* +** foo_vint8m2_t: +** vs2r\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m2_t) + +/* +** foo_vint8m4_t: +** vs4r\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m4_t) + +/* +** foo_vint8m8_t: +** vs8r\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m8_t) + +/* +** foo_vint8m1x5_t: +** ... +** vs1r\.v\tv8,0\(a0\) +** ... +** vs1r\.v\tv9,0\(a\d+\) +** ... +** vs1r\.v\tv10,0\(a\d+\) +** ... +** vs1r\.v\tv11,0\(a\d+\) +** ... +** vs1r\.v\tv12,0\(a\d+\) +** ... +*/ +FOO_ (vint8m1x5_t) + +/* +** foo_vint8m1x8_t: +** ... +** vs1r\.v\tv8,0\(a0\) +** ... +** vs1r\.v\tv9,0\(a\d+\) +** ... +** vs1r\.v\tv10,0\(a\d+\) +** ... +** vs1r\.v\tv11,0\(a\d+\) +** ... +** vs1r\.v\tv12,0\(a\d+\) +** ... +** vs1r\.v\tv13,0\(a\d+\) +** ... +** vs1r\.v\tv14,0\(a\d+\) +** ... +** vs1r\.v\tv15,0\(a\d+\) +** ... +*/ +FOO_ (vint8m1x8_t) + +/* +** foo_vint8m2x3_t: +** ... +** vs2r\.v\tv8,0\(a0\) +** ... +** vs2r\.v\tv10,0\(a\d+\) +** ... +** vs2r\.v\tv12,0\(a\d+\) +** ... +*/ +FOO_ (vint8m2x3_t) + +/* +** foo_vint8m2x4_t: +** ... +** vs2r\.v\tv8,0\(a0\) +** ... +** vs2r\.v\tv10,0\(a\d+\) +** ... +** vs2r\.v\tv12,0\(a\d+\) +** ... +** vs2r\.v\tv14,0\(a\d+\) +** ... +*/ +FOO_ (vint8m2x4_t) + +/* +** foo_vint8m4x2_t: +** ... +** vs4r\.v\tv8,0\(a0\) +** ... +** vs4r\.v\tv12,0\(a\d+\) +** ... +*/ +FOO_ (vint8m4x2_t) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c new file mode 100644 index 0000000000000..9808e4107579e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c @@ -0,0 +1,34 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-additional-sources abi-call-args-2.c } */ + +#include +#include +#include "riscv_vector.h" + +int8_t +va_callee (int count, ...); + +bool __attribute__ ((noinline)) va_caller () +{ + size_t vlmax = __riscv_vsetvlmax_e8m1 (); + vint8m1_t a1 = __riscv_vmv_v_x_i8m1 (1, vlmax); + vint8m1_t a2 = __riscv_vmv_v_x_i8m1 (2, vlmax); + vint8m1_t a3 = __riscv_vmv_v_x_i8m1 (3, vlmax); + vint8m1_t a4 = __riscv_vmv_v_x_i8m1 (4, vlmax); + vint8m1_t a5 = __riscv_vmv_v_x_i8m1 (5, vlmax); + vint8m1_t a6 = __riscv_vmv_v_x_i8m1 (6, vlmax); + vint8m1_t a7 = __riscv_vmv_v_x_i8m1 (7, vlmax); + vint8m1_t a8 = __riscv_vmv_v_x_i8m1 (8, vlmax); + int8_t sum = va_callee (8, a1, a2, a3, a4, a5, a6, a7, a8); + + return sum == (int8_t) vlmax * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8); +} + +int +main () +{ + if (va_caller ()) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c new file mode 100644 index 0000000000000..3aed245454f98 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O1 --param=riscv-vector-abi -Wno-psabi" } */ + +#include +#include "riscv_vector.h" + +int8_t +va_callee (int count, ...) +{ + size_t vlmax = __riscv_vsetvlmax_e8m1 (); + vint8m1_t sum = __riscv_vmv_v_x_i8m1 (0, vlmax); + va_list ap; + va_start (ap, count); + for (int i = count; i > 0; i--) + { + vint8m1_t arg = va_arg (ap, vint8m1_t); + sum = __riscv_vredsum_vs_i8m1_i8m1 (arg, sum, vlmax); + } + va_end (ap); + return __riscv_vmv_x_s_i8m1_i8 (sum); +} + +/* Make sure the variadic arguments is not passed through the vector register. + */ +/* { dg-final { scan-assembler-not {vs[0-9]+r} } } */ +/* { dg-final { scan-assembler-not {vsm} } } */ +/* { dg-final { scan-assembler-not {vse[0-9]+} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c new file mode 100644 index 0000000000000..8eb1ea2f31cc0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c @@ -0,0 +1,260 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-additional-sources abi-call-args-3.c } */ + +#include +#include +#include +#include +#include "riscv_vector.h" + +#define INIT_DATA \ + size_t vlmax_e8m8 = __riscv_vsetvlmax_e8m8 (); \ + int8_t golden_data[vlmax_e8m8]; \ + memset (golden_data, 0, vlmax_e8m8 * sizeof (int8_t)); \ + int8_t test_data[vlmax_e8m8]; \ + memset (test_data, 0, vlmax_e8m8 * sizeof (int8_t)); \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + golden_data[i] = vlmax_e8m8 - 1; \ + int8_t dummy_data[vlmax_e8m8]; \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + dummy_data[i] = -1; + +bool +check_mask (int8_t *test_data, int8_t *golden_data, size_t vl) +{ + size_t i = 0; + for (; i + 8 <= vl; i += 8) + { + if (test_data[i / 8] != golden_data[i / 8]) + { + printf ("mask diff %lu: %d, %d\n", i / 8, test_data[i / 8], + golden_data[i / 8]); + return false; + } + } + if (vl % 8 != 0) + { + if ((test_data[i / 8] << (8 - (vl % 8))) + != (golden_data[i / 8] << (8 - (vl % 8)))) + { + printf ("mask tail diff %lu, tail %d: %d, %d\n", i / 8, vl % 8, + test_data[i / 8], golden_data[i / 8]); + return false; + } + } + return true; +} + +bool +check_data (int8_t *test_data, int8_t *golden_data, size_t vl) +{ + for (size_t i = 0; i < vl; i += 1) + { + if (test_data[i] != golden_data[i]) + { + printf ("data diff %lu: %d, %d\n", i, test_data[i], golden_data[i]); + return false; + } + } + return true; +} + +void +foo1 (vbool1_t a, vbool2_t b, vbool4_t c, vbool2_t *out_b); +void +check_foo1 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vbool1_t a = *(vbool1_t *) dummy_data; + vbool2_t b = *(vbool2_t *) golden_data; + vbool4_t c = *(vbool4_t *) dummy_data; + foo1 (a, b, c, (vbool2_t *) test_data); + if (!check_mask (test_data, golden_data, vlmax_e8mf8 * 32)) + abort (); +} + +void +foo2 (vbool1_t a, vbool2_t b, vbool4_t c, vbool8_t d, vbool16_t e, vbool32_t f, + vbool64_t g, vbool64_t *out_g); +void +check_foo2 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vbool1_t a = *(vbool1_t *) dummy_data; + vbool2_t b = *(vbool2_t *) dummy_data; + vbool4_t c = *(vbool4_t *) dummy_data; + vbool8_t d = *(vbool8_t *) dummy_data; + vbool16_t e = *(vbool16_t *) dummy_data; + vbool32_t f = *(vbool32_t *) dummy_data; + vbool64_t g = *(vbool64_t *) golden_data; + foo2 (a, b, c, d, e, f, g, (vbool64_t *) test_data); + if (!check_mask (test_data, golden_data, vlmax_e8mf8)) + abort (); +} + +void +foo3 (vbool1_t a, vint8m4_t b, vbool2_t c, vbool2_t *out_c); +void +check_foo3 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vbool1_t a = *(vbool1_t *) dummy_data; + vint8m4_t b = *(vint8m4_t *) dummy_data; + vbool2_t c = *(vbool2_t *) golden_data; + foo3 (a, b, c, (vbool2_t *) test_data); + if (!check_mask (test_data, golden_data, vlmax_e8mf8 * 32)) + abort (); +} + +void +foo4 (vbool1_t a, vint8m4_t b, vbool2_t c, vint8m8_t d, vint8m8_t *out_d); +void +check_foo4 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vbool1_t a = *(vbool1_t *) dummy_data; + vint8m4_t b = *(vint8m4_t *) dummy_data; + vbool2_t c = *(vbool2_t *) dummy_data; + vint8m8_t d = *(vint8m8_t *) golden_data; + foo4 (a, b, c, d, (vint8m8_t *) test_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 64)) + abort (); +} + +void +foo5 (vbool1_t a, vint8m8_t b, vint8m8_t c, vint8m4_t d, vint8m4_t *out_d); +void +check_foo5 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vbool1_t a = *(vbool1_t *) dummy_data; + vint8m8_t b = *(vint8m8_t *) dummy_data; + vint8m8_t c = *(vint8m8_t *) dummy_data; + vint8m4_t d = *(vint8m4_t *) golden_data; + foo5 (a, b, c, d, (vint8m4_t *) test_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 32)) + abort (); +} + +void +foo6 (vint8m1_t a, vint8m8_t b, vint8m4_t c, vint8m2_t d, vint8m1_t e, + vint8m1_t *out_a, vint8m8_t *out_b, vint8m4_t *out_c, vint8m2_t *out_d, + vint8m1_t *out_e); +void +check_foo6 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vint8m1_t a = *(vint8m1_t *) golden_data; + vint8m8_t b = *(vint8m8_t *) golden_data; + vint8m4_t c = *(vint8m4_t *) golden_data; + vint8m2_t d = *(vint8m2_t *) golden_data; + vint8m1_t e = *(vint8m1_t *) golden_data; + foo6 (a, b, c, d, e, (vint8m1_t *) test_data, (vint8m8_t *) dummy_data, + (vint8m4_t *) dummy_data, (vint8m2_t *) dummy_data, + (vint8m1_t *) dummy_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 8)) + abort (); + + foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) test_data, + (vint8m4_t *) dummy_data, (vint8m2_t *) dummy_data, + (vint8m1_t *) dummy_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 64)) + abort (); + + foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) dummy_data, + (vint8m4_t *) test_data, (vint8m2_t *) dummy_data, + (vint8m1_t *) dummy_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 32)) + abort (); + + foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) dummy_data, + (vint8m4_t *) dummy_data, (vint8m2_t *) test_data, + (vint8m1_t *) dummy_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 16)) + abort (); + + foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) dummy_data, + (vint8m4_t *) dummy_data, (vint8m2_t *) dummy_data, + (vint8m1_t *) test_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 8)) + abort (); +} + +void +foo7 (vint8m1_t a1, vint8m1_t a2, vint8m1_t a3, vint8m1_t a4, vint8m1_t a5, + vint8m1_t a6, vint8m1_t a7, vint8m1_t a8, vint8m1_t a9, vint8m1_t a10, + vint8m1_t a11, vint8m1_t a12, vint8m1_t a13, vint8m1_t a14, vint8m1_t a15, + vint8m1_t a16, vint8m1_t a17, vint8m1_t *out_a17); +void +check_foo7 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vint8m1_t a1 = *(vint8m1_t *) dummy_data; + vint8m1_t a2 = *(vint8m1_t *) dummy_data; + vint8m1_t a3 = *(vint8m1_t *) dummy_data; + vint8m1_t a4 = *(vint8m1_t *) dummy_data; + vint8m1_t a5 = *(vint8m1_t *) dummy_data; + vint8m1_t a6 = *(vint8m1_t *) dummy_data; + vint8m1_t a7 = *(vint8m1_t *) dummy_data; + vint8m1_t a8 = *(vint8m1_t *) dummy_data; + vint8m1_t a9 = *(vint8m1_t *) dummy_data; + vint8m1_t a10 = *(vint8m1_t *) dummy_data; + vint8m1_t a11 = *(vint8m1_t *) dummy_data; + vint8m1_t a12 = *(vint8m1_t *) dummy_data; + vint8m1_t a13 = *(vint8m1_t *) dummy_data; + vint8m1_t a14 = *(vint8m1_t *) dummy_data; + vint8m1_t a15 = *(vint8m1_t *) dummy_data; + vint8m1_t a16 = *(vint8m1_t *) dummy_data; + vint8m1_t a17 = *(vint8m1_t *) golden_data; + foo7 (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, + a17, (vint8m1_t *) test_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 8)) + abort (); +} + +void +foo8 (vint8m8_t a1, vint8m8_t a2, vint8m8_t a3, + vint8m8_t *out_a3); +void +check_foo8 () +{ + INIT_DATA + + size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 (); + vint8m8_t a1 = *(vint8m8_t *) dummy_data; + vint8m8_t a2 = *(vint8m8_t *) dummy_data; + vint8m8_t a3 = *(vint8m8_t *) golden_data; + + foo8 (a1, a2, a3, (vint8m8_t *) test_data); + if (!check_data (test_data, golden_data, vlmax_e8mf8 * 64)) + abort (); +} + +int +main () +{ + check_foo1 (); + check_foo2 (); + check_foo3 (); + check_foo4 (); + check_foo5 (); + check_foo6 (); + check_foo7 (); + check_foo8 (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c new file mode 100644 index 0000000000000..17d8dace95eae --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c @@ -0,0 +1,116 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +/* Test args order. */ + +/* +** foo1: +** ... +** vsm\.v\tv8,0\(a0\) +** ... +*/ +void +foo1 (vbool1_t a, vbool2_t b, vbool4_t c, vbool2_t *out_b) +{ + *out_b = b; +} + +/* +** foo2: +** ... +** vsm\.v\tv13,0\(a0\) +** ... +*/ +void +foo2 (vbool1_t a, vbool2_t b, vbool4_t c, vbool8_t d, vbool16_t e, vbool32_t f, + vbool64_t g, vbool64_t *out_g) +{ + *out_g = g; +} + +/* +** foo3: +** ... +** vsm\.v\tv12,0\(a0\) +** ... +*/ +void +foo3 (vbool1_t a, vint8m4_t b, vbool2_t c, vbool2_t *out_c) +{ + *out_c = c; +} + +/* +** foo4: +** vs8r\.v\tv16,0\(a0\) +** ... +*/ +void +foo4 (vbool1_t a, vint8m4_t b, vbool2_t c, vint8m8_t d, vint8m8_t *out_d) +{ + *out_d = d; +} + +/* +** foo5: +** vl4re8\.v\tv[0-9]+,0\(a0\) +** ... +** vs4r\.v\tv[0-9]+,0\(a1\) +** ... +*/ +void +foo5 (vbool1_t a, vint8m8_t b, vint8m8_t c, vint8m4_t d, vint8m4_t *out_d) +{ + *out_d = d; +} + +/* +** foo6: +** vs1r\.v\tv8,0\(a0\) +** vs8r\.v\tv16,0\(a1\) +** vs4r\.v\tv12,0\(a2\) +** vs2r\.v\tv10,0\(a3\) +** vs1r\.v\tv9,0\(a4\) +** ... +*/ +void +foo6 (vint8m1_t a, vint8m8_t b, vint8m4_t c, vint8m2_t d, vint8m1_t e, + vint8m1_t *out_a, vint8m8_t *out_b, vint8m4_t *out_c, vint8m2_t *out_d, + vint8m1_t *out_e) +{ + *out_a = a; + *out_b = b; + *out_c = c; + *out_d = d; + *out_e = e; +} + +/* +** foo7: +** vl1re8\.v\tv\d+,0\(a0\) +** vs1r\.v\tv\d+,0\(a1\) +** ... +*/ +void +foo7 (vint8m1_t a1, vint8m1_t a2, vint8m1_t a3, vint8m1_t a4, vint8m1_t a5, + vint8m1_t a6, vint8m1_t a7, vint8m1_t a8, vint8m1_t a9, vint8m1_t a10, + vint8m1_t a11, vint8m1_t a12, vint8m1_t a13, vint8m1_t a14, vint8m1_t a15, + vint8m1_t a16, vint8m1_t a17, vint8m1_t *out_a17) +{ + *out_a17 = a17; +} + +/* +** foo8: +** vl8re8\.v\tv\d+,0\(a0\) +** vs8r\.v\tv\d+,0\(a1\) +** ... +*/ +void +foo8 (vint8m8_t a1, vint8m8_t a2, vint8m8_t a3, vint8m8_t *out_a3) +{ + *out_a3 = a3; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c new file mode 100644 index 0000000000000..84ba9d4ac89d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c @@ -0,0 +1,145 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-additional-sources abi-call-args-4.c } */ + +#include +#include +#include +#include +#include +#include "riscv_vector.h" + +vint64m8_t +foo1 (vint8m1_t a1, vint8m1_t a2, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1, + size_t vl); +vint64m8_t +foo2 (vint8m1_t a1, vint16m2_t b1, vint8m1_t a2, vint32m4_t c1, vint64m8_t d1, + size_t vl); +vint64m8_t +foo3 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint8m1_t a2, vint64m8_t d1, + size_t vl); +vint64m8_t +foo4 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1, vint8m1_t a2, + size_t vl); + +vint8m1x8_t +foo5 (vint8m8_t a1, vint8m1x8_t a2); + +int +main () +{ + size_t vlmax_e8m1 = __riscv_vsetvlmax_e8m1 (); + int8_t a1[vlmax_e8m1], a2[vlmax_e8m1]; + int16_t b1[vlmax_e8m1], b2[vlmax_e8m1]; + int32_t c1[vlmax_e8m1], c2[vlmax_e8m1]; + int64_t d1[vlmax_e8m1], d2[vlmax_e8m1]; + memset (a1, 0, vlmax_e8m1 * sizeof (int8_t)); + memset (a2, 0, vlmax_e8m1 * sizeof (int8_t)); + memset (b1, 0, vlmax_e8m1 * sizeof (int16_t)); + memset (b2, 0, vlmax_e8m1 * sizeof (int16_t)); + memset (c1, 0, vlmax_e8m1 * sizeof (int32_t)); + memset (c2, 0, vlmax_e8m1 * sizeof (int32_t)); + memset (d1, 0, vlmax_e8m1 * sizeof (int64_t)); + memset (d2, 0, vlmax_e8m1 * sizeof (int64_t)); + + for (size_t i = 0; i < vlmax_e8m1; i++) + { + a1[i] = 67 * i; + a2[i] = 83 * i; + b1[i] = 132 * i; + c1[i] = 1928 * i; + d1[i] = 23495 * i; + } + + for (size_t i = 0; i < vlmax_e8m1; i++) + { + b2[i] = a1[i] + a2[i]; + } + for (size_t i = 0; i < vlmax_e8m1; i++) + { + c2[i] = b1[i] - b2[i]; + } + + for (size_t i = 0; i < vlmax_e8m1; i++) + { + d2[i] = c1[i] * c2[i]; + d2[i] = d2[i] & d1[i]; + } + int64_t golden = 0; + for (size_t i = 0; i < vlmax_e8m1; i++) + { + golden += d2[i]; + } + + int64_t test; + + vint64m8_t res1 + = foo1 (*(vint8m1_t *) a1, *(vint8m1_t *) a2, *(vint16m2_t *) b1, + *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1); + test = __riscv_vmv_x_s_i64m1_i64 ( + __riscv_vredsum_vs_i64m8_i64m1 (res1, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1), + vlmax_e8m1)); + + if (test != golden) + { + printf ("foo1: %ld, %ld\n", test, golden); + abort (); + } + + vint64m8_t res2 + = foo2 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint8m1_t *) a2, + *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1); + test = __riscv_vmv_x_s_i64m1_i64 ( + __riscv_vredsum_vs_i64m8_i64m1 (res2, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1), + vlmax_e8m1)); + + if (test != golden) + { + printf ("foo2: %ld, %ld\n", test, golden); + abort (); + } + + vint64m8_t res3 + = foo3 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1, + *(vint8m1_t *) a2, *(vint64m8_t *) d1, vlmax_e8m1); + test = __riscv_vmv_x_s_i64m1_i64 ( + __riscv_vredsum_vs_i64m8_i64m1 (res3, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1), + vlmax_e8m1)); + if (test != golden) + { + printf ("foo3: %ld, %ld\n", test, golden); + abort (); + } + + vint64m8_t res4 + = foo4 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1, + *(vint64m8_t *) d1, *(vint8m1_t *) a2, vlmax_e8m1); + test = __riscv_vmv_x_s_i64m1_i64 ( + __riscv_vredsum_vs_i64m8_i64m1 (res4, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1), + vlmax_e8m1)); + if (test != golden) + { + printf ("foo4: %ld, %ld\n", test, golden); + abort (); + } + + int8_t t1[vlmax_e8m1 * 8]; + int8_t t2[vlmax_e8m1 * 8]; + for (size_t i = 0; i < vlmax_e8m1 * 8; i++) + { + t1[i] = 67 * i; + t2[i] = 83 * i; + } + vint8m1x8_t res5 = foo5 (*(vint8m8_t *) t1, *(vint8m1x8_t *) t2); + int8_t test_arr[vlmax_e8m1 * 8]; + memset (test_arr, 0, vlmax_e8m1 * 8 * sizeof (int8_t)); + *(vint8m1x8_t *) test_arr = res5; + for (size_t i = 0; i < vlmax_e8m1 * 8; i += 1) + if (t2[i] != test_arr[i]) + { + printf ("foo5 %d: %ld, %ld\n", i, test_arr[i], t2[i]); + abort (); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c new file mode 100644 index 0000000000000..9693b0c325f29 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c @@ -0,0 +1,111 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +/* +** foo1: +** ... +** vwadd\.vv\tv\d+,v\d+,v\d+ +** ... +** vwsub\.vv\tv\d+,v\d+,v\d+ +** ... +** vwmul\.vv\tv\d+,v\d+,v\d+ +** ... +** vand\.vv\tv8,v\d+,v\d+ +** ... +*/ +vint64m8_t +foo1 (vint8m1_t a1, vint8m1_t a2, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1, + size_t vl) +{ + vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl); + vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl); + vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl); + return __riscv_vand_vv_i64m8 (d1, d2, vl); +} + +/* +** foo2: +** ... +** vwadd\.vv\tv\d+,v\d+,v\d+ +** ... +** vwsub\.vv\tv\d+,v\d+,v\d+ +** ... +** vwmul\.vv\tv\d+,v\d+,v\d+ +** ... +** vand\.vv\tv8,v\d+,v\d+ +** ... +*/ +vint64m8_t +foo2 (vint8m1_t a1, vint16m2_t b1, vint8m1_t a2, vint32m4_t c1, vint64m8_t d1, + size_t vl) +{ + vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl); + vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl); + vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl); + return __riscv_vand_vv_i64m8 (d1, d2, vl); +} + +/* +** foo3: +** ... +** vwadd\.vv\tv\d+,v\d+,v\d+ +** ... +** vwsub\.vv\tv\d+,v\d+,v\d+ +** ... +** vwmul\.vv\tv\d+,v\d+,v\d+ +** ... +** vand\.vv\tv8,v\d+,v\d+ +** ... +*/ +vint64m8_t +foo3 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint8m1_t a2, vint64m8_t d1, + size_t vl) +{ + vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl); + vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl); + vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl); + return __riscv_vand_vv_i64m8 (d1, d2, vl); +} + +/* +** foo4: +** ... +** vwadd\.vv\tv\d+,v\d+,v\d+ +** ... +** vwsub\.vv\tv\d+,v\d+,v\d+ +** ... +** vwmul\.vv\tv\d+,v\d+,v\d+ +** ... +** vand\.vv\tv8,v\d+,v\d+ +** ... +*/ +vint64m8_t +foo4 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1, vint8m1_t a2, + size_t vl) +{ + vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl); + vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl); + vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl); + return __riscv_vand_vv_i64m8 (d1, d2, vl); +} + +/* +** foo5: +** vmv1r\.v\tv8,v16 +** vmv1r\.v\tv9,v17 +** vmv1r\.v\tv10,v18 +** vmv1r\.v\tv11,v19 +** vmv1r\.v\tv12,v20 +** vmv1r\.v\tv13,v21 +** vmv1r\.v\tv14,v22 +** vmv1r\.v\tv15,v23 +** ... +*/ +vint8m1x8_t +foo5 (vint8m8_t a, vint8m1x8_t b) +{ + return b; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c new file mode 100644 index 0000000000000..8070ca347818d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-vector-abi -Wno-psabi -Wno-implicit-function-declaration" } */ + +#include "riscv_vector.h" + +int +foo (int8_t *in) +{ + vint8m1_t a = *(vint8m1_t *)in; + bar (a); /* { dg-error "RVV type 'vint8m1_t' cannot be passed to an unprototyped function" } */ +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c new file mode 100644 index 0000000000000..539cd02fb772a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c @@ -0,0 +1,127 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-additional-sources abi-call-return.c } */ + +#include +#include +#include +#include +#include "riscv_vector.h" + +#define FOO_(TYPE) TYPE foo_##TYPE (TYPE *out); + +FOO_ (vbool1_t) +FOO_ (vbool2_t) +FOO_ (vbool4_t) +FOO_ (vbool8_t) +FOO_ (vbool16_t) +FOO_ (vbool32_t) +FOO_ (vbool64_t) +FOO_ (vint8mf8_t) +FOO_ (vint8mf4_t) +FOO_ (vint8mf2_t) +FOO_ (vint8m1_t) +FOO_ (vint8m2_t) +FOO_ (vint8m4_t) +FOO_ (vint8m8_t) +FOO_ (vint8m1x5_t) +FOO_ (vint8m1x8_t) +FOO_ (vint8m2x3_t) +FOO_ (vint8m2x4_t) +FOO_ (vint8m4x2_t) + +bool +check_mask (int8_t *test_data, int8_t *golden_data, size_t vl) +{ + size_t i = 0; + for (; i + 8 <= vl; i += 8) + { + if (test_data[i / 8] != golden_data[i / 8]) + { + printf ("mask diff %lu: %d, %d\n", i / 8, test_data[i / 8], + golden_data[i / 8]); + return false; + } + } + if (vl % 8 != 0) + { + if ((test_data[i / 8] << (8 - (vl % 8))) + != (golden_data[i / 8] << (8 - (vl % 8)))) + { + printf ("mask tail diff %lu, tail %d: %d, %d\n", i / 8, vl % 8, + test_data[i / 8], golden_data[i / 8]); + return false; + } + } + return true; +} + +bool +check_data (int8_t *test_data, int8_t *golden_data, size_t vl) +{ + for (size_t i = 0; i < vl; i += 1) + { + if (test_data[i] != golden_data[i]) + { + printf ("data diff %lu: %d, %d\n", i, test_data[i], golden_data[i]); + return false; + } + } + return true; +} + +#define INIT_DATA \ + size_t vlmax_e8m8 = __riscv_vsetvlmax_e8m8 (); \ + int8_t golden_data[vlmax_e8m8]; \ + memset (golden_data, 0, vlmax_e8m8 * sizeof (int8_t)); \ + int8_t test_data[vlmax_e8m8]; \ + memset (test_data, 0, vlmax_e8m8 * sizeof (int8_t)); \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + golden_data[i] = vlmax_e8m8 - 1; + +#define FOO_MASK(TYPE, VL) \ + { \ + INIT_DATA \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + test_data[i] = 0; \ + TYPE val = foo_##TYPE ((TYPE *) golden_data); \ + *(TYPE *) test_data = val; \ + if (!check_mask (test_data, golden_data, VL)) \ + abort (); \ + } + +#define FOO_DATA(TYPE, VL) \ + { \ + INIT_DATA \ + for (size_t i = 0; i < vlmax_e8m8; i += 1) \ + test_data[i] = 0; \ + TYPE val = foo_##TYPE ((TYPE *) golden_data); \ + *(TYPE *) test_data = val; \ + if (!check_data (test_data, golden_data, VL)) \ + abort (); \ + } + +int +main () +{ + size_t vlmax = __riscv_vsetvlmax_e8mf8 (); + FOO_MASK (vbool1_t, vlmax * 64) + FOO_MASK (vbool2_t, vlmax * 32) + FOO_MASK (vbool4_t, vlmax * 16) + FOO_MASK (vbool8_t, vlmax * 8) + FOO_MASK (vbool16_t, vlmax * 4) + FOO_MASK (vbool32_t, vlmax * 2) + FOO_MASK (vbool64_t, vlmax) + FOO_DATA (vint8mf8_t, vlmax) + FOO_DATA (vint8mf4_t, vlmax * 2) + FOO_DATA (vint8mf2_t, vlmax * 4) + FOO_DATA (vint8m1_t, vlmax * 8) + FOO_DATA (vint8m2_t, vlmax * 16) + FOO_DATA (vint8m4_t, vlmax * 32) + FOO_DATA (vint8m8_t, vlmax * 64) + FOO_DATA (vint8m1x5_t, vlmax * 8 * 5) + FOO_DATA (vint8m1x8_t, vlmax * 8 * 8) + FOO_DATA (vint8m2x3_t, vlmax * 16 * 3) + FOO_DATA (vint8m2x4_t, vlmax * 16 * 4) + FOO_DATA (vint8m4x2_t, vlmax * 32 * 2) +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c new file mode 100644 index 0000000000000..a6287e6e9bb13 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c @@ -0,0 +1,197 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv -mabi=lp64d -O1 --param=riscv-vector-abi -Wno-psabi" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "riscv_vector.h" + +#define FOO_(TYPE) \ + TYPE foo_##TYPE (TYPE *out) \ + { \ + return *out; \ + } + +/* Test the first vector mask type argument */ + +/* +** foo_vbool1_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool1_t) + +/* +** foo_vbool2_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool2_t) + +/* +** foo_vbool4_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool4_t) + +/* +** foo_vbool8_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool8_t) + +/* +** foo_vbool16_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool16_t) + +/* +** foo_vbool32_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool32_t) + +/* +** foo_vbool64_t: +** ... +** vlm\.v\tv0,0\(a0\) +** ... +*/ +FOO_ (vbool64_t) + +/* Test the first vector data type argument */ + +/* +** foo_vint8mf8_t: +** ... +** vle8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8mf8_t) + +/* +** foo_vint8mf4_t: +** ... +** vle8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8mf4_t) + +/* +** foo_vint8mf2_t: +** ... +** vle8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8mf2_t) + +/* +** foo_vint8m1_t: +** vl1re8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m1_t) + +/* +** foo_vint8m2_t: +** vl2re8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m2_t) + +/* +** foo_vint8m4_t: +** vl4re8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m4_t) + +/* +** foo_vint8m8_t: +** vl8re8\.v\tv8,0\(a0\) +** ... +*/ +FOO_ (vint8m8_t) + +/* +** foo_vint8m1x5_t: +** ... +** vl1re8\.v\tv8,0\(a0\) +** ... +** vl1re8\.v\tv9,0\(a\d+\) +** ... +** vl1re8\.v\tv10,0\(a\d+\) +** ... +** vl1re8\.v\tv11,0\(a\d+\) +** ... +** vl1re8\.v\tv12,0\(a\d+\) +** ... +*/ +FOO_ (vint8m1x5_t) + +/* +** foo_vint8m1x8_t: +** ... +** vl1re8\.v\tv8,0\(a0\) +** ... +** vl1re8\.v\tv9,0\(a\d+\) +** ... +** vl1re8\.v\tv10,0\(a\d+\) +** ... +** vl1re8\.v\tv11,0\(a\d+\) +** ... +** vl1re8\.v\tv12,0\(a\d+\) +** ... +** vl1re8\.v\tv13,0\(a\d+\) +** ... +** vl1re8\.v\tv14,0\(a\d+\) +** ... +** vl1re8\.v\tv15,0\(a\d+\) +** ... +*/ +FOO_ (vint8m1x8_t) + +/* +** foo_vint8m2x3_t: +** ... +** vl2re8\.v\tv8,0\(a0\) +** ... +** vl2re8\.v\tv10,0\(a\d+\) +** ... +** vl2re8\.v\tv12,0\(a\d+\) +** ... +*/ +FOO_ (vint8m2x3_t) + +/* +** foo_vint8m2x4_t: +** ... +** vl2re8\.v\tv8,0\(a0\) +** ... +** vl2re8\.v\tv10,0\(a\d+\) +** ... +** vl2re8\.v\tv12,0\(a\d+\) +** ... +** vl2re8\.v\tv14,0\(a\d+\) +** ... +*/ +FOO_ (vint8m2x4_t) + +/* +** foo_vint8m4x2_t: +** ... +** vl4re8\.v\tv8,0\(a0\) +** ... +** vl4re8\.v\tv12,0\(a\d+\) +** ... +*/ +FOO_ (vint8m4x2_t)