diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index ac9c4b02f17..4a67297173d 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -227,6 +227,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,
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 528dca7ae85..2f66d99cfc4 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -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
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index e277c138636..aa6b46d7611 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -192,6 +192,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
@@ -4138,6 +4150,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
@@ -4148,12 +4165,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,
@@ -4175,11 +4285,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)
@@ -4243,6 +4351,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.  */
@@ -4289,12 +4401,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.  */
@@ -4356,20 +4484,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;
 
@@ -4427,6 +4558,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
@@ -8667,6 +8865,9 @@ riscv_frame_pointer_required (void)
 #undef TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED riscv_frame_pointer_required
 
+#undef TARGET_FNTYPE_ABI
+#define TARGET_FNTYPE_ABI riscv_fntype_abi
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 643e7ea7330..b24b240dd75 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 <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
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 4dfd8f78ad5..9ef008e43fc 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -305,3 +305,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.
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 00000000000..60407278a5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c
@@ -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)
+}
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 00000000000..40560fccfc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c
@@ -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)
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 00000000000..0cb7f7479ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c
@@ -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;
+}
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 00000000000..6352f2e594a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c
@@ -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]+} } } */
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 00000000000..3b1da236268
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
@@ -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;
+}
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 00000000000..435d61c2c21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
@@ -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;
+}
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 00000000000..f13ab7a8ade
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
@@ -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;
+}
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 00000000000..b1d99dff979
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c
@@ -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;
+}
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 00000000000..fce548303ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c
@@ -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" } */
+}
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 00000000000..7802b2ff667
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c
@@ -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)
+}
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 00000000000..0e0f3fce299
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c
@@ -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)
