diff mbox series

RISC-V: Add an experimental vector calling convention

Message ID 20230625124040.2335529-1-lehua.ding@rivai.ai
State New
Headers show
Series RISC-V: Add an experimental vector calling convention | expand

Commit Message

Lehua Ding June 25, 2023, 12:40 p.m. UTC
This patch adds an experimental vector calling convention proposal that the
user can enable with --param=riscv-vector-abi option. The details of this
proposal can be viewed at this link: 
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 . Please help me
to review this proposal, thank you very much.

Currently, all RVV type arguments and return value are passed by reference.
This patch allows arguments and return value to be passed through vector
registers. Suppose there is a function as follows, then a is passed through v1,
b is passed through v8-v15, c is passed through v4-v7, d is passed through
v2-v3, m is passed through v0, and the return value is returned through v2-v3.

vint8m2_t
foo (vint8m1_t a, vint8m8_t b, vint8m4_t c, vint8m2_t d, vint8m1_t e,
     vbool1_t m);


The rules are described as follows (extract from the proposal):

======

The hardware vector calling convention adds 1 argument register for vector mask
type argument and 31 argument registers for vector data and tuple type argument
which are v0 and v1-v31, respectively. v0 is used for the first vector mask
type argument and the vector mask type return value, the rest of the mask type
arguments are treated as vector data type arguments. v1-v31 are also used for
the vector data and tuple type return value.

Vector data type arguments have properties LMUL and NREGS, the current LMUL can
be 1/8, 1/4, 1/2, 1, 2, 4, 8, the current NREGS can be 1, 2, 4, 8. For
arguments with LMUL less than 1, their LMUL is treated as 1. The LMUL of the
vector mask type argument is treated as 1. The NREGS property means the number
of registers needed for this argument. For vector data type, NREGS is 1 when
LMUL is less than 1, otherwise NREGS is equal to LMUL. If it is possible to
find NREGS unused continuous vector register set starting from v1 and its first
register is LMUL-aligned, use these registers to pass the argument. Otherwise,
the argument is passed by reference.

vector tuple type arguments have the same LMUL and NREGS properties as the
vector data type, but also have the NF property. NREGS equals NF multiplied by
LMUL, but cannot exceed 8. The process of finding the argument registers is the
same as for the vector data type.

======

Because the RVV type field is currently not allowed in struct, the
implementation of this part of using vector registers to pass struct arguments
is not included in the current patch, although I have implemented it.

For functions that use vecotr registers to pass arguments and return value,
the .variant_cc directive needs to be added to distinguish them from functions
that follow the standard calling convention.

Best,
Lehua

gcc/ChangeLog:

	* config/riscv/riscv-protos.h (riscv_declare_function_name): New hook implementation.
	(riscv_asm_output_alias): Ditto.
	(riscv_asm_output_external): Ditto.
	(builtin_type_p): New helper function.
	* config/riscv/riscv-vector-builtins.cc (builtin_type_p): Ditto.
	* config/riscv/riscv.cc (struct riscv_arg_info): New field.
	(riscv_init_cumulative_args): Init variant_cc field.
	(riscv_hard_regno_nregs): Add prototype function.
	(riscv_get_vector_arg): Add function to handler RVV type.
	(riscv_get_arg_info): Call riscv_get_vector_arg.
	(riscv_function_arg_advance): Handler vector arguments.
	(riscv_pass_by_reference): Ditto.
	(riscv_v_abi): Add function return V ABI.
	(riscv_return_value_is_vector_type_p): Ditto.
	(riscv_arguments_is_vector_type_p): Ditto.
	(riscv_fntype_abi): New hook implementation.
	(riscv_asm_output_variant_cc): New helper function.
	(riscv_declare_function_name): New hook implementation.
	(riscv_asm_output_alias): New hook implementation.
	(riscv_asm_output_external): New hook implementation.
	(TARGET_FNTYPE_ABI): Ditto.
	* config/riscv/riscv.h (GCC_RISCV_H): #include <stdbool.h>
	(MAX_ARGS_IN_VECTOR_REGISTERS): Helper macro.
	(MAX_ARGS_IN_MASK_REGISTERS): Ditto.
	(V_ARG_FIRST): Ditto.
	(V_ARG_LAST): Ditto.
	(enum riscv_cc): New help enum.
	(ASM_DECLARE_FUNCTION_NAME): New hook implementation.
	(ASM_OUTPUT_DEF_FROM_DECLS): Ditto.
	(ASM_OUTPUT_EXTERNAL): Ditto.
	* config/riscv/riscv.opt: New option --param=riscv-vector-abi .

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/abi-call-args-1-run.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-1.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-2-run.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-2.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-3-run.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-3.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-4-run.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-args-4.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-error-1.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-return-run.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-return.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-variant-cc.c: New test.
	* gcc.target/riscv/rvv/base/abi-call-variant_cc.c: New test.

---
 gcc/config/riscv/riscv-protos.h               |   4 +
 gcc/config/riscv/riscv-vector-builtins.cc     |  10 +
 gcc/config/riscv/riscv.cc                     | 300 ++++++++++++++++--
 gcc/config/riscv/riscv.h                      |  36 +++
 gcc/config/riscv/riscv.opt                    |   5 +
 .../riscv/rvv/base/abi-call-args-1-run.c      | 127 ++++++++
 .../riscv/rvv/base/abi-call-args-1.c          | 197 ++++++++++++
 .../riscv/rvv/base/abi-call-args-2-run.c      |  34 ++
 .../riscv/rvv/base/abi-call-args-2.c          |  27 ++
 .../riscv/rvv/base/abi-call-args-3-run.c      | 280 ++++++++++++++++
 .../riscv/rvv/base/abi-call-args-3.c          | 117 +++++++
 .../riscv/rvv/base/abi-call-args-4-run.c      | 125 ++++++++
 .../riscv/rvv/base/abi-call-args-4.c          | 111 +++++++
 .../riscv/rvv/base/abi-call-error-1.c         |  11 +
 .../riscv/rvv/base/abi-call-return-run.c      | 127 ++++++++
 .../riscv/rvv/base/abi-call-return.c          | 197 ++++++++++++
 .../riscv/rvv/base/abi-call-variant-cc.c      |  39 +++
 .../riscv/rvv/base/abi-call-variant_cc.c      |  39 +++
 18 files changed, 1760 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c

Comments

钟居哲 June 25, 2023, 2:03 p.m. UTC | #1
Thanks for doing this.

A couple comments here:

1. 
-riscv_init_cumulative_args (CUMULATIVE_ARGS *cum,
-			    tree fntype ATTRIBUTE_UNUSED,
-			    rtx libname ATTRIBUTE_UNUSED,
-			    tree fndecl,
+riscv_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
+			    rtx libname ATTRIBUTE_UNUSED, tree fndecl,
 			    int caller ATTRIBUTE_UNUSED)
Do not format here. Recover back the original format.

2.

+  /* When vector abi disabled(without --param=riscv-vector-abi option) or vector
+     argument is variadic, vector argument is passed by reference.  */
+  if (riscv_vector::builtin_type_p (type) && (!riscv_vector_abi || !named))
+    {
+      gcc_assert (riscv_v_ext_mode_p (mode));
+      return NULL_RTX;

It seems that this patch is only enabling vetor ABI for RVV builtin type (for example: vint32m1_t), it's fine.
But using builtin_type_p may not be easily extended in the future.
So I prefer you add a function "riscv_vector_type_p" in riscv.cc and use "riscv_vector_type_p"

static bool
riscv_vector_type_p
{
  /* TODO: We currently only support vector ABI for RVV bultin type(vint32m1_t),
      we will support vector ABI for GNU vectors in the future....*/
  return riscv_vector::builtin_type_p...
}

Since we will need to support Vector ABI for GNU vector, for example:
typedef int v4si __attribute__ ((vector_size (16)));
When compile option: --param=riscv-autovec-preference=fixed-vlmax, TYPE_MODE = VNx4SI
When compile option: --param=riscv-autovec-preference=scalable, TYPE_MODE = V4SI (We will add this mode soon later).
So wrap this into "riscv_vector_type_p" will be easier for us to extend vector ABI for GNU vectors.

3.
+/* 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::builtin_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::builtin_type_p (arg_type))
+	return true;
+    }
+
+  return false;
+}
I prefer riscv_vector::builtin_type_p change to "riscv_vector_type_p", so that we could extend GNU vectors suppor in the future.


4. 
+/* Output the assembly strings we want to add to a function definition.  */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL)                             \
+  riscv_declare_function_name (STR, NAME, DECL)
+
+/* Output assembly strings for alias definition.  */
+#undef ASM_OUTPUT_DEF_FROM_DECLS
+#define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET)                           \
+  riscv_asm_output_alias (STR, DECL, TARGET)
+
+/* Output assembly strings for undefined extern symbols.  */
+#undef ASM_OUTPUT_EXTERNAL
+#define ASM_OUTPUT_EXTERNAL(STR, DECL, NAME)                                   \
+  riscv_asm_output_external (STR, DECL, NAME)

Is it necessary we need these target hook for vector ABI? If yes,  could you demonstrate why you need this in this patch.
If it is a refinement of assembly dump information, I prefer it to be another separate patch.

I'd like to see more comments from Jeff && Robin.

Thanks.


juzhe.zhong@rivai.ai
 
From: Lehua Ding
Date: 2023-06-25 20:40
To: gcc-patches
CC: juzhe.zhong; rdapp.gcc; kito.cheng; palmer; jeffreyalaw; pan2.li
Subject: [PATCH] RISC-V: Add an experimental vector calling convention
This patch adds an experimental vector calling convention proposal that the
user can enable with --param=riscv-vector-abi option. The details of this
proposal can be viewed at this link: 
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 . Please help me
to review this proposal, thank you very much.
 
Currently, all RVV type arguments and return value are passed by reference.
This patch allows arguments and return value to be passed through vector
registers. Suppose there is a function as follows, then a is passed through v1,
b is passed through v8-v15, c is passed through v4-v7, d is passed through
v2-v3, m is passed through v0, and the return value is returned through v2-v3.
 
vint8m2_t
foo (vint8m1_t a, vint8m8_t b, vint8m4_t c, vint8m2_t d, vint8m1_t e,
     vbool1_t m);
 
 
The rules are described as follows (extract from the proposal):
 
======
 
The hardware vector calling convention adds 1 argument register for vector mask
type argument and 31 argument registers for vector data and tuple type argument
which are v0 and v1-v31, respectively. v0 is used for the first vector mask
type argument and the vector mask type return value, the rest of the mask type
arguments are treated as vector data type arguments. v1-v31 are also used for
the vector data and tuple type return value.
 
Vector data type arguments have properties LMUL and NREGS, the current LMUL can
be 1/8, 1/4, 1/2, 1, 2, 4, 8, the current NREGS can be 1, 2, 4, 8. For
arguments with LMUL less than 1, their LMUL is treated as 1. The LMUL of the
vector mask type argument is treated as 1. The NREGS property means the number
of registers needed for this argument. For vector data type, NREGS is 1 when
LMUL is less than 1, otherwise NREGS is equal to LMUL. If it is possible to
find NREGS unused continuous vector register set starting from v1 and its first
register is LMUL-aligned, use these registers to pass the argument. Otherwise,
the argument is passed by reference.
 
vector tuple type arguments have the same LMUL and NREGS properties as the
vector data type, but also have the NF property. NREGS equals NF multiplied by
LMUL, but cannot exceed 8. The process of finding the argument registers is the
same as for the vector data type.
 
======
 
Because the RVV type field is currently not allowed in struct, the
implementation of this part of using vector registers to pass struct arguments
is not included in the current patch, although I have implemented it.
 
For functions that use vecotr registers to pass arguments and return value,
the .variant_cc directive needs to be added to distinguish them from functions
that follow the standard calling convention.
 
Best,
Lehua
 
gcc/ChangeLog:
 
* config/riscv/riscv-protos.h (riscv_declare_function_name): New hook implementation.
(riscv_asm_output_alias): Ditto.
(riscv_asm_output_external): Ditto.
(builtin_type_p): New helper function.
* config/riscv/riscv-vector-builtins.cc (builtin_type_p): Ditto.
* config/riscv/riscv.cc (struct riscv_arg_info): New field.
(riscv_init_cumulative_args): Init variant_cc field.
(riscv_hard_regno_nregs): Add prototype function.
(riscv_get_vector_arg): Add function to handler RVV type.
(riscv_get_arg_info): Call riscv_get_vector_arg.
(riscv_function_arg_advance): Handler vector arguments.
(riscv_pass_by_reference): Ditto.
(riscv_v_abi): Add function return V ABI.
(riscv_return_value_is_vector_type_p): Ditto.
(riscv_arguments_is_vector_type_p): Ditto.
(riscv_fntype_abi): New hook implementation.
(riscv_asm_output_variant_cc): New helper function.
(riscv_declare_function_name): New hook implementation.
(riscv_asm_output_alias): New hook implementation.
(riscv_asm_output_external): New hook implementation.
(TARGET_FNTYPE_ABI): Ditto.
* config/riscv/riscv.h (GCC_RISCV_H): #include <stdbool.h>
(MAX_ARGS_IN_VECTOR_REGISTERS): Helper macro.
(MAX_ARGS_IN_MASK_REGISTERS): Ditto.
(V_ARG_FIRST): Ditto.
(V_ARG_LAST): Ditto.
(enum riscv_cc): New help enum.
(ASM_DECLARE_FUNCTION_NAME): New hook implementation.
(ASM_OUTPUT_DEF_FROM_DECLS): Ditto.
(ASM_OUTPUT_EXTERNAL): Ditto.
* config/riscv/riscv.opt: New option --param=riscv-vector-abi .
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/abi-call-args-1-run.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-1.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-2-run.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-2.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-3-run.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-3.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-4-run.c: New test.
* gcc.target/riscv/rvv/base/abi-call-args-4.c: New test.
* gcc.target/riscv/rvv/base/abi-call-error-1.c: New test.
* gcc.target/riscv/rvv/base/abi-call-return-run.c: New test.
* gcc.target/riscv/rvv/base/abi-call-return.c: New test.
* gcc.target/riscv/rvv/base/abi-call-variant-cc.c: New test.
* gcc.target/riscv/rvv/base/abi-call-variant_cc.c: New test.
 
---
gcc/config/riscv/riscv-protos.h               |   4 +
gcc/config/riscv/riscv-vector-builtins.cc     |  10 +
gcc/config/riscv/riscv.cc                     | 300 ++++++++++++++++--
gcc/config/riscv/riscv.h                      |  36 +++
gcc/config/riscv/riscv.opt                    |   5 +
.../riscv/rvv/base/abi-call-args-1-run.c      | 127 ++++++++
.../riscv/rvv/base/abi-call-args-1.c          | 197 ++++++++++++
.../riscv/rvv/base/abi-call-args-2-run.c      |  34 ++
.../riscv/rvv/base/abi-call-args-2.c          |  27 ++
.../riscv/rvv/base/abi-call-args-3-run.c      | 280 ++++++++++++++++
.../riscv/rvv/base/abi-call-args-3.c          | 117 +++++++
.../riscv/rvv/base/abi-call-args-4-run.c      | 125 ++++++++
.../riscv/rvv/base/abi-call-args-4.c          | 111 +++++++
.../riscv/rvv/base/abi-call-error-1.c         |  11 +
.../riscv/rvv/base/abi-call-return-run.c      | 127 ++++++++
.../riscv/rvv/base/abi-call-return.c          | 197 ++++++++++++
.../riscv/rvv/base/abi-call-variant-cc.c      |  39 +++
.../riscv/rvv/base/abi-call-variant_cc.c      |  39 +++
18 files changed, 1760 insertions(+), 26 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c
 
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index f052757cede..f7f43937ae4 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -56,6 +56,9 @@ extern bool riscv_split_64bit_move_p (rtx, rtx);
extern void riscv_split_doubleword_move (rtx, rtx);
extern const char *riscv_output_move (rtx, rtx);
extern const char *riscv_output_return ();
+extern void riscv_declare_function_name (FILE *, const char*, tree);
+extern void riscv_asm_output_alias (FILE *, const tree, const tree);
+extern void riscv_asm_output_external (FILE *, const tree, const char*);
#ifdef RTX_CODE
extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx);
@@ -169,6 +172,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 9e6dae98a6d..250caaff7d0 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -3925,6 +3925,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 280aa0b33b9..abeb51543c8 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -189,6 +189,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;
};
/* Information about an address described by riscv_address_type.
@@ -3864,30 +3876,114 @@ riscv_pass_in_vector_p (const_tree type)
    For a library call, FNTYPE is 0.  */
void
-riscv_init_cumulative_args (CUMULATIVE_ARGS *cum,
-     tree fntype ATTRIBUTE_UNUSED,
-     rtx libname ATTRIBUTE_UNUSED,
-     tree fndecl,
+riscv_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
+     rtx libname ATTRIBUTE_UNUSED, tree fndecl,
    int caller ATTRIBUTE_UNUSED)
{
   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
= FUNCTION_DECL_CHECK (fndecl)->function_decl;
       if (fn.built_in_class == NOT_BUILT_IN)
-   cum->rvv_psabi_warning = 1;
+ cum->rvv_psabi_warning = 1;
     }
}
-/* 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.  */
+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 return value of vector mask type.  */
+      if (return_p)
+ return gen_rtx_REG (mode, V_REG_FIRST);
+
+      /* For first argument of vector mask type.  */
+      if (info->mr_offset < MAX_ARGS_IN_MASK_REGISTERS)
+ {
+   info->num_mrs = 1;
+   return gen_rtx_REG (mode, V_REG_FIRST);
+ }
+      else
+ {
+   /* Other vector mask type arguments are treated as vector data type
+      arguments.  */
+ }
+    }
+
+  /* The number and alignment of vector registers need for the vector data type
+     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 reg_align = 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 + reg_align - 1) & -reg_align;
+
+  /* For return value of vector data and tuple type.  */
+  if (return_p)
+    return gen_rtx_REG (mode, aligned_reg_start + V_REG_FIRST);
+
+  /* Iterate through the USED_VRS array to find a continuous unused register set
+     and the first register is aligned with REG_ALIGN.  */
+  for (int i = aligned_reg_start; i + nregs - 1 <= arg_reg_end; i += reg_align)
+    {
+      /* 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 used.  */
+   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
+    REG_ALIGN step to I.  */
+ i += (j / reg_align) * reg_align;
+ 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,
@@ -3909,13 +4005,6 @@ 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))
-    return NULL_RTX;
-
   if (named)
     {
       riscv_aggregate_field fields[2];
@@ -3977,6 +4066,35 @@ 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 scalar argument of vector type.  */
+   if (riscv_vector::builtin_type_p (type))
+     {
+       gcc_assert (riscv_v_ext_mode_p (mode));
+       return riscv_get_vector_arg (info, cum, mode, return_p);
+     }
+
+   /* For simple structs with vector type fields.  */
+   /* Currently there is no support for putting vector type fields inside
+      struct. We will implement the corresponding calling convention when
+      it is supported.  */
+ }
+    }
+
+  /* When vector abi disabled(without --param=riscv-vector-abi option) or vector
+     argument is variadic, vector argument is passed by reference.  */
+  if (riscv_vector::builtin_type_p (type) && (!riscv_vector_abi || !named))
+    {
+      gcc_assert (riscv_v_ext_mode_p (mode));
+      return NULL_RTX;
     }
   /* Work out the size of the argument.  */
@@ -4023,12 +4141,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.  */
@@ -4090,22 +4224,28 @@ 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 a vector register.  */
+      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.  */
-  if (riscv_v_ext_mode_p (arg.mode))
-    return true;
+  /* When vector abi disabled or vector argument is variadic or vector argument
+     cannot be passed through vector registers, the vector argument is passed by
+     reference.  */
+  if (riscv_vector::builtin_type_p (arg.type))
+    {
+      gcc_assert (riscv_v_ext_mode_p (arg.mode));
+      return true;
+    }
   /* Pass by reference if the data do not fit in two integer registers.  */
   return !IN_RANGE (size, 0, 2 * UNITS_PER_WORD);
@@ -4161,6 +4301,62 @@ riscv_setup_incoming_varargs (cumulative_args_t cum,
     cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD;
}
+/* Return the descriptor of the RISC-V V Vector ABI.  */
+
+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 ();
+      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::builtin_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::builtin_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
@@ -6362,6 +6558,55 @@ riscv_issue_rate (void)
   return tune_param->issue_rate;
}
+/* Output .variant_cc for RISCV_CC_V function symbols.  */
+
+static void
+riscv_asm_output_variant_cc (FILE *stream, const tree decl, const char *name)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      riscv_cc cc = (riscv_cc) fndecl_abi (decl).id ();
+      if (cc == RISCV_CC_V)
+ {
+   fprintf (stream, "\t.variant_cc\t");
+   assemble_name (stream, name);
+   fprintf (stream, "\n");
+ }
+    }
+}
+
+/* Implement ASM_DECLARE_FUNCTION_NAME. Output .variant_cc for function
+   defintion.  */
+
+void
+riscv_declare_function_name (FILE *stream, const char *name, tree fndecl)
+{
+  riscv_asm_output_variant_cc (stream, fndecl, name);
+  ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
+  ASM_OUTPUT_LABEL (stream, name);
+}
+
+/* Implement ASM_OUTPUT_DEF_FROM_DECLS. Output .variant_cc for aliases.  */
+
+void
+riscv_asm_output_alias (FILE *stream, const tree decl, const tree target)
+{
+  const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  const char *value = IDENTIFIER_POINTER (target);
+  riscv_asm_output_variant_cc (stream, decl, name);
+  ASM_OUTPUT_DEF (stream, name, value);
+}
+
+/* Implement ASM_OUTPUT_EXTERNAL. Output .variant_pcs for undefined
+   function symbol references.  */
+
+void
+riscv_asm_output_external (FILE *stream, tree decl, const char *name)
+{
+  default_elf_asm_output_external (stream, decl, name);
+  riscv_asm_output_variant_cc (stream, decl, name);
+}
+
/* Auxiliary function to emit RISC-V ELF attribute. */
static void
riscv_emit_attribute ()
@@ -8109,6 +8354,9 @@ riscv_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode,
#undef TARGET_VECTORIZE_VEC_PERM_CONST
#define TARGET_VECTORIZE_VEC_PERM_CONST riscv_vectorize_vec_perm_const
+#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 bfd9b7551bc..37b09f8931e 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 (31)
+#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 + 1)
+#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,15 @@ 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)))
+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 {
+  enum riscv_cc variant_cc;
   /* Number of integer registers used so far, up to MAX_ARGS_IN_REGISTERS. */
   unsigned int num_gprs;
@@ -679,6 +693,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
@@ -990,6 +1011,21 @@ while (0)
#define ASM_COMMENT_START "#"
+/* Output the assembly strings we want to add to a function definition.  */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL)                             \
+  riscv_declare_function_name (STR, NAME, DECL)
+
+/* Output assembly strings for alias definition.  */
+#undef ASM_OUTPUT_DEF_FROM_DECLS
+#define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET)                           \
+  riscv_asm_output_alias (STR, DECL, TARGET)
+
+/* Output assembly strings for undefined extern symbols.  */
+#undef ASM_OUTPUT_EXTERNAL
+#define ASM_OUTPUT_EXTERNAL(STR, DECL, NAME)                                   \
+  riscv_asm_output_external (STR, DECL, NAME)
+
#undef SIZE_TYPE
#define SIZE_TYPE (POINTER_SIZE == 64 ? "long unsigned int" : "unsigned int")
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 63d4710cb15..a74bad46663 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -295,3 +295,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..a37facbd836
--- /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\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf8_t)
+
+/*
+** foo_vint8mf4_t:
+**   ...
+**   vse8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf4_t)
+
+/*
+** foo_vint8mf2_t:
+**   ...
+**   vse8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf2_t)
+
+/*
+** foo_vint8m1_t:
+**   vs1r\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m1_t)
+
+/*
+** foo_vint8m2_t:
+**   vs2r\.v\tv2,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m2_t)
+
+/*
+** foo_vint8m4_t:
+**   vs4r\.v\tv4,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m4_t)
+
+/*
+** foo_vint8m8_t:
+**   vs8r\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m8_t)
+
+/*
+** foo_vint8m1x5_t:
+**   ...
+**   vs1r\.v\tv1,0\(a0\)
+**   ...
+**   vs1r\.v\tv2,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv3,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv5,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x5_t)
+
+/*
+** foo_vint8m1x8_t:
+**   ...
+**   vs1r\.v\tv1,0\(a0\)
+**   ...
+**   vs1r\.v\tv2,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv3,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv5,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv6,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv7,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x8_t)
+
+/*
+** foo_vint8m2x3_t:
+**   ...
+**   vs2r\.v\tv2,0\(a0\)
+**   ...
+**   vs2r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv6,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x3_t)
+
+/*
+** foo_vint8m2x4_t:
+**   ...
+**   vs2r\.v\tv2,0\(a0\)
+**   ...
+**   vs2r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv6,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x4_t)
+
+/*
+** foo_vint8m4x2_t:
+**   ...
+**   vs4r\.v\tv4,0\(a0\)
+**   ...
+**   vs4r\.v\tv8,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..a74addec34f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
@@ -0,0 +1,280 @@
+/* { 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 a18, vint8m1_t a19, vint8m1_t a20,
+      vint8m1_t a21, vint8m1_t a22, vint8m1_t a23, vint8m1_t a24, vint8m1_t a25,
+      vint8m1_t a26, vint8m1_t a27, vint8m1_t a28, vint8m1_t a29, vint8m1_t a30,
+      vint8m1_t a31, vint8m1_t a32, vint8m1_t *out_a32);
+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 *) dummy_data;
+  vint8m1_t a18 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a19 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a20 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a21 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a22 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a23 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a24 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a25 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a26 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a27 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a28 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a29 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a30 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a31 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a32 = *(vint8m1_t *) golden_data;
+  foo7 (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16,
+ a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30,
+ a31, a32, (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 a4,
+      vint8m8_t *out_a4);
+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 *) dummy_data;
+  vint8m8_t a4 = *(vint8m8_t *) golden_data;
+
+  foo8 (a1, a2, a3, a4, (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..34889921798
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
@@ -0,0 +1,117 @@
+/* { 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\tv1,0\(a0\)
+**   ...
+*/
+void
+foo1 (vbool1_t a, vbool2_t b, vbool4_t c, vbool2_t *out_b)
+{
+  *out_b = b;
+}
+
+/*
+** foo2:
+**   ...
+**   vsm\.v\tv6,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\tv1,0\(a0\)
+**   ...
+*/
+void
+foo3 (vbool1_t a, vint8m4_t b, vbool2_t c, vbool2_t *out_c)
+{
+  *out_c = c;
+}
+
+/*
+** foo4:
+**   vs8r\.v\tv8,0\(a0\)
+**   ...
+*/
+void
+foo4 (vbool1_t a, vint8m4_t b, vbool2_t c, vint8m8_t d, vint8m8_t *out_d)
+{
+  *out_d = d;
+}
+
+/*
+** foo5:
+**   vs4r\.v\tv4,0\(a0\)
+**   ...
+*/
+void
+foo5 (vbool1_t a, vint8m8_t b, vint8m8_t c, vint8m4_t d, vint8m4_t *out_d)
+{
+  *out_d = d;
+}
+
+/*
+** foo6:
+**   vs1r\.v\tv1,0\(a0\)
+**   vs8r\.v\tv8,0\(a1\)
+**   vs4r\.v\tv4,0\(a2\)
+**   vs2r\.v\tv2,0\(a3\)
+**   vs1r\.v\tv16,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 a18, vint8m1_t a19, vint8m1_t a20,
+      vint8m1_t a21, vint8m1_t a22, vint8m1_t a23, vint8m1_t a24, vint8m1_t a25,
+      vint8m1_t a26, vint8m1_t a27, vint8m1_t a28, vint8m1_t a29, vint8m1_t a30,
+      vint8m1_t a31, vint8m1_t a32, vint8m1_t *out_a32)
+{
+  *out_a32 = a32;
+}
+
+/*
+** 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 a4, vint8m8_t *out_a4)
+{
+  *out_a4 = a4;
+}
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..6b13fbd619d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
@@ -0,0 +1,125 @@
+/* { 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];
+    }
+
+  vint64m8_t res1
+    = foo1 (*(vint8m1_t *) a1, *(vint8m1_t *) a2, *(vint16m2_t *) b1,
+     *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1);
+  int64_t test1 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res1, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+     vlmax_e8m1));
+
+  if (test1 != golden)
+    abort ();
+
+  vint64m8_t res2
+    = foo2 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint8m1_t *) a2,
+     *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1);
+  int64_t test2 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res2, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+     vlmax_e8m1));
+
+  if (test2 != golden)
+    abort ();
+
+  vint64m8_t res3
+    = foo3 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1,
+     *(vint8m1_t *) a2, *(vint64m8_t *) d1, vlmax_e8m1);
+  int64_t test3 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res3, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+     vlmax_e8m1));
+  if (test3 != golden)
+    abort ();
+
+  vint64m8_t res4
+    = foo4 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1,
+     *(vint64m8_t *) d1, *(vint8m1_t *) a2, vlmax_e8m1);
+  int64_t test4 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res4, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+     vlmax_e8m1));
+  if (test4 != golden)
+    abort ();
+
+  vint8m1x8_t res5 = foo5 (*(vint8m8_t *) a1, *(vint8m1x8_t *) a2);
+  int8_t test[vlmax_e8m1 * 8];
+  memset (test, 0, vlmax_e8m1 * 8 * sizeof (int8_t));
+  *(vint8m1x8_t *) test = res5;
+  for (size_t i = 0; i < vlmax_e8m1 * 8; i += 1)
+    {
+      if (a2[i] != test[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..675f6f2b59b
--- /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+,v1,v2
+**   ...
+**   vwsub\.vv\tv\d+,v4,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v8,v\d+
+**   ...
+**   vand\.vv\tv8,v16,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+,v1,v4
+**   ...
+**   vwsub\.vv\tv\d+,v2,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v8,v\d+
+**   ...
+**   vand\.vv\tv8,v16,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+,v1,v8
+**   ...
+**   vwsub\.vv\tv\d+,v2,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v4,v\d+
+**   ...
+**   vand\.vv\tv8,v16,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+,v1,v16
+**   ...
+**   vwsub\.vv\tv\d+,v2,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v4,v\d+
+**   ...
+**   vand\.vv\tv8,v8,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\tv1,v16
+**   vmv1r\.v\tv2,v17
+**   vmv1r\.v\tv3,v18
+**   vmv1r\.v\tv4,v19
+**   vmv1r\.v\tv5,v20
+**   vmv1r\.v\tv6,v21
+**   vmv1r\.v\tv7,v22
+**   vmv1r\.v\tv8,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..c5981ef56f5
--- /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\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf8_t)
+
+/*
+** foo_vint8mf4_t:
+**   ...
+**   vle8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf4_t)
+
+/*
+** foo_vint8mf2_t:
+**   ...
+**   vle8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf2_t)
+
+/*
+** foo_vint8m1_t:
+**   vl1re8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m1_t)
+
+/*
+** foo_vint8m2_t:
+**   vl2re8\.v\tv2,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m2_t)
+
+/*
+** foo_vint8m4_t:
+**   vl4re8\.v\tv4,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m4_t)
+
+/*
+** foo_vint8m8_t:
+**   vl8re8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m8_t)
+
+/*
+** foo_vint8m1x5_t:
+**   ...
+**   vl1re8\.v\tv1,0\(a0\)
+**   ...
+**   vl1re8\.v\tv2,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv3,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv5,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x5_t)
+
+/*
+** foo_vint8m1x8_t:
+**   ...
+**   vl1re8\.v\tv1,0\(a0\)
+**   ...
+**   vl1re8\.v\tv2,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv3,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv5,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv6,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv7,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x8_t)
+
+/*
+** foo_vint8m2x3_t:
+**   ...
+**   vl2re8\.v\tv2,0\(a0\)
+**   ...
+**   vl2re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv6,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x3_t)
+
+/*
+** foo_vint8m2x4_t:
+**   ...
+**   vl2re8\.v\tv2,0\(a0\)
+**   ...
+**   vl2re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv6,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x4_t)
+
+/*
+** foo_vint8m4x2_t:
+**   ...
+**   vl4re8\.v\tv4,0\(a0\)
+**   ...
+**   vl4re8\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m4x2_t)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c
new file mode 100644
index 00000000000..4e45203f5b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+void
+f_undef1 (vint8m1_t a);
+void
+f_undef2 (vint8m1x8_t a);
+void
+f_undef3 (vbool1_t a);
+vint8m1_t
+f_undef4 ();
+
+void
+bar_real (vint8m1_t a, vint8m1x8_t b, vbool1_t c)
+{
+  f_undef1 (a);
+  f_undef2 (b);
+  f_undef3 (c);
+}
+
+__attribute__ ((alias ("bar_real"))) void
+bar_alias (vint8m1_t a, vint8m1x8_t b, vbool1_t c);
+
+void
+f_1 (vint8m1_t *a, vint8m1x8_t *b, vbool1_t *c)
+{
+  bar_alias (*a, *b, *c);
+  *a = f_undef4 ();
+}
+
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_real} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_alias} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_1} 0 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef1} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef2} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef3} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef4} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c
new file mode 100644
index 00000000000..4e45203f5b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+void
+f_undef1 (vint8m1_t a);
+void
+f_undef2 (vint8m1x8_t a);
+void
+f_undef3 (vbool1_t a);
+vint8m1_t
+f_undef4 ();
+
+void
+bar_real (vint8m1_t a, vint8m1x8_t b, vbool1_t c)
+{
+  f_undef1 (a);
+  f_undef2 (b);
+  f_undef3 (c);
+}
+
+__attribute__ ((alias ("bar_real"))) void
+bar_alias (vint8m1_t a, vint8m1x8_t b, vbool1_t c);
+
+void
+f_1 (vint8m1_t *a, vint8m1x8_t *b, vbool1_t *c)
+{
+  bar_alias (*a, *b, *c);
+  *a = f_undef4 ();
+}
+
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_real} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_alias} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_1} 0 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef1} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef2} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef3} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef4} 1 } } */
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index f052757cede..f7f43937ae4 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -56,6 +56,9 @@  extern bool riscv_split_64bit_move_p (rtx, rtx);
 extern void riscv_split_doubleword_move (rtx, rtx);
 extern const char *riscv_output_move (rtx, rtx);
 extern const char *riscv_output_return ();
+extern void riscv_declare_function_name (FILE *, const char*, tree);
+extern void riscv_asm_output_alias (FILE *, const tree, const tree);
+extern void riscv_asm_output_external (FILE *, const tree, const char*);
 
 #ifdef RTX_CODE
 extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx);
@@ -169,6 +172,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 9e6dae98a6d..250caaff7d0 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -3925,6 +3925,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 280aa0b33b9..abeb51543c8 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -189,6 +189,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;
 };
 
 /* Information about an address described by riscv_address_type.
@@ -3864,30 +3876,114 @@  riscv_pass_in_vector_p (const_tree type)
    For a library call, FNTYPE is 0.  */
 
 void
-riscv_init_cumulative_args (CUMULATIVE_ARGS *cum,
-			    tree fntype ATTRIBUTE_UNUSED,
-			    rtx libname ATTRIBUTE_UNUSED,
-			    tree fndecl,
+riscv_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
+			    rtx libname ATTRIBUTE_UNUSED, tree fndecl,
 			    int caller ATTRIBUTE_UNUSED)
 {
   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
 	= FUNCTION_DECL_CHECK (fndecl)->function_decl;
 
       if (fn.built_in_class == NOT_BUILT_IN)
-	  cum->rvv_psabi_warning = 1;
+	cum->rvv_psabi_warning = 1;
     }
 }
 
-/* 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.  */
+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 return value of vector mask type.  */
+      if (return_p)
+	return gen_rtx_REG (mode, V_REG_FIRST);
+
+      /* For first argument of vector mask type.  */
+      if (info->mr_offset < MAX_ARGS_IN_MASK_REGISTERS)
+	{
+	  info->num_mrs = 1;
+	  return gen_rtx_REG (mode, V_REG_FIRST);
+	}
+      else
+	{
+	  /* Other vector mask type arguments are treated as vector data type
+	     arguments.  */
+	}
+    }
+
+  /* The number and alignment of vector registers need for the vector data type
+     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 reg_align = 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 + reg_align - 1) & -reg_align;
+
+  /* For return value of vector data and tuple type.  */
+  if (return_p)
+    return gen_rtx_REG (mode, aligned_reg_start + V_REG_FIRST);
+
+  /* Iterate through the USED_VRS array to find a continuous unused register set
+     and the first register is aligned with REG_ALIGN.  */
+  for (int i = aligned_reg_start; i + nregs - 1 <= arg_reg_end; i += reg_align)
+    {
+      /* 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 used.  */
+	  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
+		   REG_ALIGN step to I.  */
+		i += (j / reg_align) * reg_align;
+		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,
@@ -3909,13 +4005,6 @@  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))
-    return NULL_RTX;
-
   if (named)
     {
       riscv_aggregate_field fields[2];
@@ -3977,6 +4066,35 @@  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 scalar argument of vector type.  */
+	  if (riscv_vector::builtin_type_p (type))
+	    {
+	      gcc_assert (riscv_v_ext_mode_p (mode));
+	      return riscv_get_vector_arg (info, cum, mode, return_p);
+	    }
+
+	  /* For simple structs with vector type fields.  */
+	  /* Currently there is no support for putting vector type fields inside
+	     struct. We will implement the corresponding calling convention when
+	     it is supported.  */
+	}
+    }
+
+  /* When vector abi disabled(without --param=riscv-vector-abi option) or vector
+     argument is variadic, vector argument is passed by reference.  */
+  if (riscv_vector::builtin_type_p (type) && (!riscv_vector_abi || !named))
+    {
+      gcc_assert (riscv_v_ext_mode_p (mode));
+      return NULL_RTX;
     }
 
   /* Work out the size of the argument.  */
@@ -4023,12 +4141,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.  */
@@ -4090,22 +4224,28 @@  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 a vector register.  */
+      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.  */
-  if (riscv_v_ext_mode_p (arg.mode))
-    return true;
+  /* When vector abi disabled or vector argument is variadic or vector argument
+     cannot be passed through vector registers, the vector argument is passed by
+     reference.  */
+  if (riscv_vector::builtin_type_p (arg.type))
+    {
+      gcc_assert (riscv_v_ext_mode_p (arg.mode));
+      return true;
+    }
 
   /* Pass by reference if the data do not fit in two integer registers.  */
   return !IN_RANGE (size, 0, 2 * UNITS_PER_WORD);
@@ -4161,6 +4301,62 @@  riscv_setup_incoming_varargs (cumulative_args_t cum,
     cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD;
 }
 
+/* Return the descriptor of the RISC-V V Vector ABI.  */
+
+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 ();
+      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::builtin_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::builtin_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
@@ -6362,6 +6558,55 @@  riscv_issue_rate (void)
   return tune_param->issue_rate;
 }
 
+/* Output .variant_cc for RISCV_CC_V function symbols.  */
+
+static void
+riscv_asm_output_variant_cc (FILE *stream, const tree decl, const char *name)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      riscv_cc cc = (riscv_cc) fndecl_abi (decl).id ();
+      if (cc == RISCV_CC_V)
+	{
+	  fprintf (stream, "\t.variant_cc\t");
+	  assemble_name (stream, name);
+	  fprintf (stream, "\n");
+	}
+    }
+}
+
+/* Implement ASM_DECLARE_FUNCTION_NAME. Output .variant_cc for function
+   defintion.  */
+
+void
+riscv_declare_function_name (FILE *stream, const char *name, tree fndecl)
+{
+  riscv_asm_output_variant_cc (stream, fndecl, name);
+  ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
+  ASM_OUTPUT_LABEL (stream, name);
+}
+
+/* Implement ASM_OUTPUT_DEF_FROM_DECLS. Output .variant_cc for aliases.  */
+
+void
+riscv_asm_output_alias (FILE *stream, const tree decl, const tree target)
+{
+  const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  const char *value = IDENTIFIER_POINTER (target);
+  riscv_asm_output_variant_cc (stream, decl, name);
+  ASM_OUTPUT_DEF (stream, name, value);
+}
+
+/* Implement ASM_OUTPUT_EXTERNAL. Output .variant_pcs for undefined
+   function symbol references.  */
+
+void
+riscv_asm_output_external (FILE *stream, tree decl, const char *name)
+{
+  default_elf_asm_output_external (stream, decl, name);
+  riscv_asm_output_variant_cc (stream, decl, name);
+}
+
 /* Auxiliary function to emit RISC-V ELF attribute. */
 static void
 riscv_emit_attribute ()
@@ -8109,6 +8354,9 @@  riscv_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode,
 #undef TARGET_VECTORIZE_VEC_PERM_CONST
 #define TARGET_VECTORIZE_VEC_PERM_CONST riscv_vectorize_vec_perm_const
 
+#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 bfd9b7551bc..37b09f8931e 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 (31)
+#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 + 1)
+#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,15 @@  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)))
 
+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 {
+  enum riscv_cc variant_cc;
   /* Number of integer registers used so far, up to MAX_ARGS_IN_REGISTERS. */
   unsigned int num_gprs;
 
@@ -679,6 +693,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
@@ -990,6 +1011,21 @@  while (0)
 
 #define ASM_COMMENT_START "#"
 
+/* Output the assembly strings we want to add to a function definition.  */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL)                             \
+  riscv_declare_function_name (STR, NAME, DECL)
+
+/* Output assembly strings for alias definition.  */
+#undef ASM_OUTPUT_DEF_FROM_DECLS
+#define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET)                           \
+  riscv_asm_output_alias (STR, DECL, TARGET)
+
+/* Output assembly strings for undefined extern symbols.  */
+#undef ASM_OUTPUT_EXTERNAL
+#define ASM_OUTPUT_EXTERNAL(STR, DECL, NAME)                                   \
+  riscv_asm_output_external (STR, DECL, NAME)
+
 #undef SIZE_TYPE
 #define SIZE_TYPE (POINTER_SIZE == 64 ? "long unsigned int" : "unsigned int")
 
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 63d4710cb15..a74bad46663 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -295,3 +295,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..a37facbd836
--- /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\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf8_t)
+
+/*
+** foo_vint8mf4_t:
+**   ...
+**   vse8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf4_t)
+
+/*
+** foo_vint8mf2_t:
+**   ...
+**   vse8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf2_t)
+
+/*
+** foo_vint8m1_t:
+**   vs1r\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m1_t)
+
+/*
+** foo_vint8m2_t:
+**   vs2r\.v\tv2,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m2_t)
+
+/*
+** foo_vint8m4_t:
+**   vs4r\.v\tv4,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m4_t)
+
+/*
+** foo_vint8m8_t:
+**   vs8r\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m8_t)
+
+/*
+** foo_vint8m1x5_t:
+**   ...
+**   vs1r\.v\tv1,0\(a0\)
+**   ...
+**   vs1r\.v\tv2,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv3,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv5,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x5_t)
+
+/*
+** foo_vint8m1x8_t:
+**   ...
+**   vs1r\.v\tv1,0\(a0\)
+**   ...
+**   vs1r\.v\tv2,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv3,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv5,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv6,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv7,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x8_t)
+
+/*
+** foo_vint8m2x3_t:
+**   ...
+**   vs2r\.v\tv2,0\(a0\)
+**   ...
+**   vs2r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv6,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x3_t)
+
+/*
+** foo_vint8m2x4_t:
+**   ...
+**   vs2r\.v\tv2,0\(a0\)
+**   ...
+**   vs2r\.v\tv4,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv6,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x4_t)
+
+/*
+** foo_vint8m4x2_t:
+**   ...
+**   vs4r\.v\tv4,0\(a0\)
+**   ...
+**   vs4r\.v\tv8,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..a74addec34f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
@@ -0,0 +1,280 @@ 
+/* { 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 a18, vint8m1_t a19, vint8m1_t a20,
+      vint8m1_t a21, vint8m1_t a22, vint8m1_t a23, vint8m1_t a24, vint8m1_t a25,
+      vint8m1_t a26, vint8m1_t a27, vint8m1_t a28, vint8m1_t a29, vint8m1_t a30,
+      vint8m1_t a31, vint8m1_t a32, vint8m1_t *out_a32);
+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 *) dummy_data;
+  vint8m1_t a18 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a19 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a20 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a21 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a22 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a23 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a24 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a25 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a26 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a27 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a28 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a29 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a30 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a31 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a32 = *(vint8m1_t *) golden_data;
+  foo7 (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16,
+	a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30,
+	a31, a32, (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 a4,
+      vint8m8_t *out_a4);
+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 *) dummy_data;
+  vint8m8_t a4 = *(vint8m8_t *) golden_data;
+
+  foo8 (a1, a2, a3, a4, (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..34889921798
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
@@ -0,0 +1,117 @@ 
+/* { 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\tv1,0\(a0\)
+**   ...
+*/
+void
+foo1 (vbool1_t a, vbool2_t b, vbool4_t c, vbool2_t *out_b)
+{
+  *out_b = b;
+}
+
+/*
+** foo2:
+**   ...
+**   vsm\.v\tv6,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\tv1,0\(a0\)
+**   ...
+*/
+void
+foo3 (vbool1_t a, vint8m4_t b, vbool2_t c, vbool2_t *out_c)
+{
+  *out_c = c;
+}
+
+/*
+** foo4:
+**   vs8r\.v\tv8,0\(a0\)
+**   ...
+*/
+void
+foo4 (vbool1_t a, vint8m4_t b, vbool2_t c, vint8m8_t d, vint8m8_t *out_d)
+{
+  *out_d = d;
+}
+
+/*
+** foo5:
+**   vs4r\.v\tv4,0\(a0\)
+**   ...
+*/
+void
+foo5 (vbool1_t a, vint8m8_t b, vint8m8_t c, vint8m4_t d, vint8m4_t *out_d)
+{
+  *out_d = d;
+}
+
+/*
+** foo6:
+**   vs1r\.v\tv1,0\(a0\)
+**   vs8r\.v\tv8,0\(a1\)
+**   vs4r\.v\tv4,0\(a2\)
+**   vs2r\.v\tv2,0\(a3\)
+**   vs1r\.v\tv16,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 a18, vint8m1_t a19, vint8m1_t a20,
+      vint8m1_t a21, vint8m1_t a22, vint8m1_t a23, vint8m1_t a24, vint8m1_t a25,
+      vint8m1_t a26, vint8m1_t a27, vint8m1_t a28, vint8m1_t a29, vint8m1_t a30,
+      vint8m1_t a31, vint8m1_t a32, vint8m1_t *out_a32)
+{
+  *out_a32 = a32;
+}
+
+/*
+** 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 a4, vint8m8_t *out_a4)
+{
+  *out_a4 = a4;
+}
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..6b13fbd619d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
@@ -0,0 +1,125 @@ 
+/* { 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];
+    }
+
+  vint64m8_t res1
+    = foo1 (*(vint8m1_t *) a1, *(vint8m1_t *) a2, *(vint16m2_t *) b1,
+	    *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1);
+  int64_t test1 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res1, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+
+  if (test1 != golden)
+    abort ();
+
+  vint64m8_t res2
+    = foo2 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint8m1_t *) a2,
+	    *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1);
+  int64_t test2 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res2, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+
+  if (test2 != golden)
+    abort ();
+
+  vint64m8_t res3
+    = foo3 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1,
+	    *(vint8m1_t *) a2, *(vint64m8_t *) d1, vlmax_e8m1);
+  int64_t test3 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res3, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+  if (test3 != golden)
+    abort ();
+
+  vint64m8_t res4
+    = foo4 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1,
+	    *(vint64m8_t *) d1, *(vint8m1_t *) a2, vlmax_e8m1);
+  int64_t test4 = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res4, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+  if (test4 != golden)
+    abort ();
+
+  vint8m1x8_t res5 = foo5 (*(vint8m8_t *) a1, *(vint8m1x8_t *) a2);
+  int8_t test[vlmax_e8m1 * 8];
+  memset (test, 0, vlmax_e8m1 * 8 * sizeof (int8_t));
+  *(vint8m1x8_t *) test = res5;
+  for (size_t i = 0; i < vlmax_e8m1 * 8; i += 1)
+    {
+      if (a2[i] != test[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..675f6f2b59b
--- /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+,v1,v2
+**   ...
+**   vwsub\.vv\tv\d+,v4,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v8,v\d+
+**   ...
+**   vand\.vv\tv8,v16,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+,v1,v4
+**   ...
+**   vwsub\.vv\tv\d+,v2,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v8,v\d+
+**   ...
+**   vand\.vv\tv8,v16,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+,v1,v8
+**   ...
+**   vwsub\.vv\tv\d+,v2,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v4,v\d+
+**   ...
+**   vand\.vv\tv8,v16,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+,v1,v16
+**   ...
+**   vwsub\.vv\tv\d+,v2,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v4,v\d+
+**   ...
+**   vand\.vv\tv8,v8,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\tv1,v16
+**   vmv1r\.v\tv2,v17
+**   vmv1r\.v\tv3,v18
+**   vmv1r\.v\tv4,v19
+**   vmv1r\.v\tv5,v20
+**   vmv1r\.v\tv6,v21
+**   vmv1r\.v\tv7,v22
+**   vmv1r\.v\tv8,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..c5981ef56f5
--- /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\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf8_t)
+
+/*
+** foo_vint8mf4_t:
+**   ...
+**   vle8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf4_t)
+
+/*
+** foo_vint8mf2_t:
+**   ...
+**   vle8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf2_t)
+
+/*
+** foo_vint8m1_t:
+**   vl1re8\.v\tv1,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m1_t)
+
+/*
+** foo_vint8m2_t:
+**   vl2re8\.v\tv2,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m2_t)
+
+/*
+** foo_vint8m4_t:
+**   vl4re8\.v\tv4,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m4_t)
+
+/*
+** foo_vint8m8_t:
+**   vl8re8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m8_t)
+
+/*
+** foo_vint8m1x5_t:
+**   ...
+**   vl1re8\.v\tv1,0\(a0\)
+**   ...
+**   vl1re8\.v\tv2,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv3,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv5,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x5_t)
+
+/*
+** foo_vint8m1x8_t:
+**   ...
+**   vl1re8\.v\tv1,0\(a0\)
+**   ...
+**   vl1re8\.v\tv2,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv3,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv5,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv6,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv7,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x8_t)
+
+/*
+** foo_vint8m2x3_t:
+**   ...
+**   vl2re8\.v\tv2,0\(a0\)
+**   ...
+**   vl2re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv6,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x3_t)
+
+/*
+** foo_vint8m2x4_t:
+**   ...
+**   vl2re8\.v\tv2,0\(a0\)
+**   ...
+**   vl2re8\.v\tv4,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv6,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x4_t)
+
+/*
+** foo_vint8m4x2_t:
+**   ...
+**   vl4re8\.v\tv4,0\(a0\)
+**   ...
+**   vl4re8\.v\tv8,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m4x2_t)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c
new file mode 100644
index 00000000000..4e45203f5b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant-cc.c
@@ -0,0 +1,39 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+void
+f_undef1 (vint8m1_t a);
+void
+f_undef2 (vint8m1x8_t a);
+void
+f_undef3 (vbool1_t a);
+vint8m1_t
+f_undef4 ();
+
+void
+bar_real (vint8m1_t a, vint8m1x8_t b, vbool1_t c)
+{
+  f_undef1 (a);
+  f_undef2 (b);
+  f_undef3 (c);
+}
+
+__attribute__ ((alias ("bar_real"))) void
+bar_alias (vint8m1_t a, vint8m1x8_t b, vbool1_t c);
+
+void
+f_1 (vint8m1_t *a, vint8m1x8_t *b, vbool1_t *c)
+{
+  bar_alias (*a, *b, *c);
+  *a = f_undef4 ();
+}
+
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_real} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_alias} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_1} 0 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef1} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef2} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef3} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef4} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c
new file mode 100644
index 00000000000..4e45203f5b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc.c
@@ -0,0 +1,39 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+void
+f_undef1 (vint8m1_t a);
+void
+f_undef2 (vint8m1x8_t a);
+void
+f_undef3 (vbool1_t a);
+vint8m1_t
+f_undef4 ();
+
+void
+bar_real (vint8m1_t a, vint8m1x8_t b, vbool1_t c)
+{
+  f_undef1 (a);
+  f_undef2 (b);
+  f_undef3 (c);
+}
+
+__attribute__ ((alias ("bar_real"))) void
+bar_alias (vint8m1_t a, vint8m1x8_t b, vbool1_t c);
+
+void
+f_1 (vint8m1_t *a, vint8m1x8_t *b, vbool1_t *c)
+{
+  bar_alias (*a, *b, *c);
+  *a = f_undef4 ();
+}
+
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_real} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tbar_alias} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_1} 0 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef1} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef2} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef3} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_cc\tf_undef4} 1 } } */