@@ -221,6 +221,7 @@ enum avl_type
/* Routines implemented in riscv-vector-builtins.cc. */
void init_builtins (void);
const char *mangle_builtin_type (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,
@@ -3961,6 +3961,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
@@ -170,6 +170,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
@@ -3887,6 +3899,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
@@ -3897,12 +3914,106 @@ 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
+ infomation. */
+ 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 = (arg_reg_start + LMUL - 1) & -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;
+ /* Check there are NREGS continuous unused registers are not
+ allocated. */
+ 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,
@@ -3924,11 +4035,10 @@ 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 vector abi disabled(without --param=riscv-vector-abi option) 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)
@@ -3992,6 +4102,19 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
gregno, TYPE_MODE (fields[1].type),
fields[1].offset);
}
+
+ /* Implementing an experimental vector calling convention, the proposal
+ can be viewed at 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)
+ {
+ /* 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. */
@@ -4038,12 +4161,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. */
@@ -4105,20 +4244,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;
@@ -4176,6 +4318,67 @@ 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)
+{
+ 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
@@ -8279,6 +8482,9 @@ riscv_preferred_else_value (unsigned, tree, unsigned int nops, tree *ops)
#undef TARGET_PREFERRED_ELSE_VALUE
#define TARGET_PREFERRED_ELSE_VALUE riscv_preferred_else_value
+#undef TARGET_FNTYPE_ABI
+#define TARGET_FNTYPE_ABI riscv_fntype_abi
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-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 <stdbool.h>
#include "config/riscv/riscv-opts.h"
/* Target CPU builtins. */
@@ -643,6 +644,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)
@@ -650,6 +654,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 : \
@@ -671,7 +677,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;
@@ -679,6 +697,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
@@ -301,3 +301,8 @@ Enum(riscv_autovec_lmul) String(m8) Value(RVV_M8)
-param=riscv-autovec-lmul=
Target RejectNegative Joined Enum(riscv_autovec_lmul) Var(riscv_autovec_lmul) Init(RVV_M1)
-param=riscv-autovec-lmul=<string> 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.
new file mode 100644
@@ -0,0 +1,127 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-1.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#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)
+}
new file mode 100644
@@ -0,0 +1,197 @@
+/* { dg-do compile } */
+/* { dg-options "-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)
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-2.c } */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#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;
+}
new file mode 100644
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+
+#include <stdarg.h>
+#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]+} } } */
new file mode 100644
@@ -0,0 +1,260 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-3.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#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;
+}
new file mode 100644
@@ -0,0 +1,116 @@
+/* { dg-do compile } */
+/* { dg-options "-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;
+}
new file mode 100644
@@ -0,0 +1,145 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-4.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#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;
+}
new file mode 100644
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-options "-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;
+}
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "--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" } */
+}
new file mode 100644
@@ -0,0 +1,127 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-return.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#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)
+}
new file mode 100644
@@ -0,0 +1,197 @@
+/* { dg-do compile } */
+/* { dg-options "-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)