public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH V4 0/3] RISC-V: Add an experimental vector calling convention
@ 2023-08-31 12:26 Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 1/3] RISC-V: Part-1: Select suitable vector registers for vector type args and returns Lehua Ding
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Lehua Ding @ 2023-08-31 12:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, rdapp.gcc, palmer, jeffreyalaw

V4 change: Rebasing.

Hi RISC-V folks,

This patch implement the proposal of RISC-V vector calling convention[1] and
this feature can be enabled by `--param=riscv-vector-abi` option. Currently,
all vector type arguments and return values are pass by reference. With this
patch, these arguments and return values can pass through vector registers.
Currently only vector types defined in the RISC-V Vector Extension Intrinsic Document[2]
are supported. GNU-ext vector types are unsupported for now since the
corresponding proposal was not presented.

The proposal introduce a new calling convention variant, functions which follow
this variant need follow the bellow vector register convention.

| Name    | ABI Mnemonic | Meaning                      | Preserved across calls?
=================================================================================
| v0      |              | Argument register            | No
| v1-v7   |              | Callee-saved registers       | Yes
| v8-v23  |              | Argument registers           | No
| v24-v31 |              | Callee-saved registers       | Yes

If a functions follow this vector calling convention, then the function symbole
must be annotated with .variant_cc directive[3] (used to indicate that it is a
calling convention variant).

This implementation split into three parts, each part corresponds to a sub-patch.

- Part-1: Select suitable vector regsiters for vector type arguments and return
  values according to the proposal.
- Part-2: Allocate frame area for callee-saved vector registers and save/restore
  them in prologue and epilogue.
- Part-3: Generate .variant_cc directive for vector function in assembly code.

[1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389
[2] https://github.com/riscv-non-isa/rvv-intrinsic-doc/blob/master/rvv-intrinsic-rfc.md#type-system
[3] https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md#pseudo-ops

Best,
Lehua

Lehua Ding (3):
  RISC-V: Part-1: Select suitable vector registers for vector type args
    and returns
  RISC-V: Part-2: Save/Restore vector registers which need to be
    preversed
  RISC-V: Part-3: Output .variant_cc directive for vector function

 gcc/config/riscv/riscv-protos.h               |   4 +
 gcc/config/riscv/riscv-sr.cc                  |  12 +-
 gcc/config/riscv/riscv-vector-builtins.cc     |  10 +
 gcc/config/riscv/riscv.cc                     | 477 ++++++++++++++++--
 gcc/config/riscv/riscv.h                      |  40 ++
 gcc/config/riscv/riscv.md                     |  43 +-
 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      | 260 ++++++++++
 .../riscv/rvv/base/abi-call-args-3.c          | 116 +++++
 .../riscv/rvv/base/abi-call-args-4-run.c      | 145 ++++++
 .../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 ++
 .../rvv/base/abi-callee-saved-1-fixed-1.c     |  86 ++++
 .../rvv/base/abi-callee-saved-1-fixed-2.c     |  86 ++++
 .../base/abi-callee-saved-1-save-restore.c    |  85 ++++
 .../riscv/rvv/base/abi-callee-saved-1-zcmp.c  |  85 ++++
 .../riscv/rvv/base/abi-callee-saved-1.c       |  88 ++++
 .../base/abi-callee-saved-2-save-restore.c    | 108 ++++
 .../riscv/rvv/base/abi-callee-saved-2-zcmp.c  | 107 ++++
 .../riscv/rvv/base/abi-callee-saved-2.c       | 117 +++++
 27 files changed, 2695 insertions(+), 49 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-callee-saved-1-fixed-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-save-restore.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-save-restore.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2.c

-- 
2.36.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH V4 1/3] RISC-V: Part-1: Select suitable vector registers for vector type args and returns
  2023-08-31 12:26 [PATCH V4 0/3] RISC-V: Add an experimental vector calling convention Lehua Ding
@ 2023-08-31 12:26 ` Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 2/3] RISC-V: Part-2: Save/Restore vector registers which need to be preversed Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 3/3] RISC-V: Part-3: Output .variant_cc directive for vector function Lehua Ding
  2 siblings, 0 replies; 4+ messages in thread
From: Lehua Ding @ 2023-08-31 12:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, rdapp.gcc, palmer, jeffreyalaw

I post the vector register calling convention rules from in the proposal[1]
directly here:

v0 is used to pass the first vector mask argument to a function, and to return
vector mask result from a function. v8-v23 are used to pass vector data
arguments, vector tuple arguments and the rest vector mask arguments to a
function, and to return vector data and vector tuple results from a function.

Each vector data type and vector tuple type has an LMUL attribute that
indicates a vector register group. The value of LMUL indicates the number of
vector registers in the vector register group and requires the first vector
register number in the vector register group must be a multiple of it. For
example, the LMUL of `vint64m8_t` is 8, so v8-v15 vector register group can be
allocated to this type, but v9-v16 can not because the v9 register number is
not a multiple of 8. If LMUL is less than 1, it is treated as 1. If it is a
vector mask type, its LMUL is 1.

Each vector tuple type also has an NFIELDS attribute that indicates how many
vector register groups the type contains. Thus a vector tuple type needs to
take up LMUL×NFIELDS registers.

The rules for passing vector arguments are as follows:

1. For the first vector mask argument, use v0 to pass it. The argument has now
been allocated.

2. For vector data arguments or rest vector mask arguments, starting from the
v8 register, if a vector register group between v8-v23 that has not been
allocated can be found and the first register number is a multiple of LMUL,
then allocate this vector register group to the argument and mark these
registers as allocated. Otherwise, pass it by reference. The argument has now
been allocated.

3. For vector tuple arguments, starting from the v8 register, if NFIELDS
consecutive vector register groups between v8-v23 that have not been allocated
can be found and the first register number is a multiple of LMUL, then allocate
these vector register groups to the argument and mark these registers as
allocated. Otherwise, pass it by reference. The argument has now been allocated.

NOTE: It should be stressed that the search for the appropriate vector register
groups starts at v8 each time and does not start at the next register after the
registers are allocated for the previous vector argument. Therefore, it is
possible that the vector register number allocated to a vector argument can be
less than the vector register number allocated to previous vector arguments.
For example, for the function
`void foo (vint32m1_t a, vint32m2_t b, vint32m1_t c)`, according to the rules
of allocation, v8 will be allocated to `a`, v10-v11 will be allocated to `b`
and v9 will be allocated to `c`. This approach allows more vector registers to
be allocated to arguments in some cases.

Vector values are returned in the same manner as the first named argument of
the same type would be passed.

[1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389

gcc/ChangeLog:

	* config/riscv/riscv-protos.h (builtin_type_p): New function for checking vector type.
	* config/riscv/riscv-vector-builtins.cc (builtin_type_p): Ditto.
	* config/riscv/riscv.cc (struct riscv_arg_info): New fields.
	(riscv_init_cumulative_args): Setup variant_cc field.
	(riscv_vector_type_p): New function for checking vector type.
	(riscv_hard_regno_nregs): Hoist declare.
	(riscv_get_vector_arg): Subroutine of riscv_get_arg_info.
	(riscv_get_arg_info): Support vector cc.
	(riscv_function_arg_advance): Update cum.
	(riscv_pass_by_reference): Handle vector args.
	(riscv_v_abi): New function return vector abi.
	(riscv_return_value_is_vector_type_p): New function for check vector arguments.
	(riscv_arguments_is_vector_type_p): New function for check vector returns.
	(riscv_fntype_abi): Implement TARGET_FNTYPE_ABI.
	(TARGET_FNTYPE_ABI): Implement TARGET_FNTYPE_ABI.
	* config/riscv/riscv.h (GCC_RISCV_H): Define macros for vector abi.
	(MAX_ARGS_IN_VECTOR_REGISTERS): Ditto.
	(MAX_ARGS_IN_MASK_REGISTERS): Ditto.
	(V_ARG_FIRST): Ditto.
	(V_ARG_LAST): Ditto.
	(enum riscv_cc): Define all RISCV_CC variants.
	* config/riscv/riscv.opt: Add --param=riscv-vector-abi.
---
 gcc/config/riscv/riscv-protos.h               |   1 +
 gcc/config/riscv/riscv-vector-builtins.cc     |  10 +
 gcc/config/riscv/riscv.cc                     | 235 ++++++++++++++--
 gcc/config/riscv/riscv.h                      |  25 ++
 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      | 260 ++++++++++++++++++
 .../riscv/rvv/base/abi-call-args-3.c          | 116 ++++++++
 .../riscv/rvv/base/abi-call-args-4-run.c      | 145 ++++++++++
 .../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 +++++++++++++
 16 files changed, 1611 insertions(+), 17 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

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index e145ee6c69b..3761ff3b86b 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -365,6 +365,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 4a7eb47972e..df75562fd26 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -3992,6 +3992,16 @@ mangle_builtin_type (const_tree type)
   return NULL;
 }
 
+/* Return true if TYPE is a built-in RVV type defined by the ABI.  */
+bool
+builtin_type_p (const_tree type)
+{
+  if (!type)
+    return false;
+
+  return lookup_vector_type_attribute (type);
+}
+
 /* Initialize all compiler built-ins related to RVV that should be
    defined at start-up.  */
 void
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 8bca8075713..a317afd1c15 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -201,6 +201,18 @@ struct riscv_arg_info {
 
   /* The offset of the first register used, provided num_fprs is nonzero.  */
   unsigned int fpr_offset;
+
+  /* The number of vector registers allocated to this argument.  */
+  unsigned int num_vrs;
+
+  /* The offset of the first register used, provided num_vrs is nonzero.  */
+  unsigned int vr_offset;
+
+  /* The number of mask registers allocated to this argument.  */
+  unsigned int num_mrs;
+
+  /* The offset of the first register used, provided num_mrs is nonzero.  */
+  unsigned int mr_offset;
 };
 
 /* One stage in a constant building sequence.  These sequences have
@@ -4404,6 +4416,11 @@ riscv_init_cumulative_args (CUMULATIVE_ARGS *cum,
 {
   memset (cum, 0, sizeof (*cum));
 
+  if (fntype)
+    cum->variant_cc = (riscv_cc) fntype_abi (fntype).id ();
+  else
+    cum->variant_cc = RISCV_CC_BASE;
+
   if (fndecl)
     {
       const tree_function_decl &fn
@@ -4414,12 +4431,105 @@ riscv_init_cumulative_args (CUMULATIVE_ARGS *cum,
     }
 }
 
-/* Fill INFO with information about a single argument, and return an
-   RTL pattern to pass or return the argument.  CUM is the cumulative
-   state for earlier arguments.  MODE is the mode of this argument and
-   TYPE is its type (if known).  NAMED is true if this is a named
-   (fixed) argument rather than a variable one.  RETURN_P is true if
-   returning the argument, or false if passing the argument.  */
+/* Return true if TYPE is a vector type that can be passed in vector registers.
+ */
+
+static bool
+riscv_vector_type_p (const_tree type)
+{
+  /* Currently, only builtin scalabler vector type is allowed, in the future,
+     more vector types may be allowed, such as GNU vector type, etc.  */
+  return riscv_vector::builtin_type_p (type);
+}
+
+static unsigned int
+riscv_hard_regno_nregs (unsigned int regno, machine_mode mode);
+
+/* Subroutine of riscv_get_arg_info.  */
+
+static rtx
+riscv_get_vector_arg (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
+		      machine_mode mode, bool return_p)
+{
+  gcc_assert (riscv_v_ext_mode_p (mode));
+
+  info->mr_offset = cum->num_mrs;
+  if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
+    {
+      /* For scalable mask return value.  */
+      if (return_p)
+	return gen_rtx_REG (mode, V_REG_FIRST);
+
+      /* For the first scalable mask argument.  */
+      if (info->mr_offset < MAX_ARGS_IN_MASK_REGISTERS)
+	{
+	  info->num_mrs = 1;
+	  return gen_rtx_REG (mode, V_REG_FIRST);
+	}
+      else
+	{
+	  /* Rest scalable mask arguments are treated as scalable data
+	     arguments.  */
+	}
+    }
+
+  /* The number and alignment of vector registers need for this scalable vector
+     argument. When the mode size is less than a full vector, we use 1 vector
+     register to pass. Just call TARGET_HARD_REGNO_NREGS for the number
+     information.  */
+  int nregs = riscv_hard_regno_nregs (V_ARG_FIRST, mode);
+  int LMUL = riscv_v_ext_tuple_mode_p (mode)
+	       ? nregs / riscv_vector::get_nf (mode)
+	       : nregs;
+  int arg_reg_start = V_ARG_FIRST - V_REG_FIRST;
+  int arg_reg_end = V_ARG_LAST - V_REG_FIRST;
+  int aligned_reg_start = ROUND_UP (arg_reg_start, LMUL);
+
+  /* For scalable data and scalable tuple return value.  */
+  if (return_p)
+    return gen_rtx_REG (mode, aligned_reg_start + V_REG_FIRST);
+
+  /* Iterate through the USED_VRS array to find vector register groups that have
+     not been allocated and the first register is aligned with LMUL.  */
+  for (int i = aligned_reg_start; i + nregs - 1 <= arg_reg_end; i += LMUL)
+    {
+      /* The index in USED_VRS array.  */
+      int idx = i - arg_reg_start;
+      /* Find the first register unused.  */
+      if (!cum->used_vrs[idx])
+	{
+	  bool find_set = true;
+	  /* Ensure there are NREGS continuous unused registers.  */
+	  for (int j = 1; j < nregs; j++)
+	    if (cum->used_vrs[idx + j])
+	      {
+		find_set = false;
+		/* Update I to the last aligned register which
+		   cannot be used and the next iteration will add
+		   LMUL step to I.  */
+		i += (j / LMUL) * LMUL;
+		break;
+	      }
+
+	  if (find_set)
+	    {
+	      info->num_vrs = nregs;
+	      info->vr_offset = idx;
+	      return gen_rtx_REG (mode, i + V_REG_FIRST);
+	    }
+	}
+    }
+
+  return NULL_RTX;
+}
+
+/* Fill INFO with information about a single argument, and return an RTL
+   pattern to pass or return the argument. Return NULL_RTX if argument cannot
+   pass or return in registers, then the argument may be passed by reference or
+   through the stack or  .  CUM is the cumulative state for earlier arguments.
+   MODE is the mode of this argument and TYPE is its type (if known). NAMED is
+   true if this is a named (fixed) argument rather than a variable one. RETURN_P
+   is true if returning the argument, or false if passing the argument.  */
 
 static rtx
 riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
@@ -4441,11 +4551,9 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
       riscv_pass_in_vector_p (type);
     }
 
-  /* All current vector arguments and return values are passed through the
-     function stack. Ideally, we should either warn the user not to use an RVV
-     vector type as function argument or support a calling convention
-     with better performance.  */
-  if (riscv_v_ext_mode_p (mode))
+  /* When disable vector_abi or scalable vector argument is anonymous, this
+     argument is passed by reference.  */
+  if (riscv_v_ext_mode_p (mode) && (!riscv_vector_abi || !named))
     return NULL_RTX;
 
   if (named)
@@ -4509,6 +4617,10 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum,
 				      gregno, TYPE_MODE (fields[1].type),
 				      fields[1].offset);
 	}
+
+      /* For scalable vector argument.  */
+      if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode))
+	return riscv_get_vector_arg (info, cum, mode, return_p);
     }
 
   /* Work out the size of the argument.  */
@@ -4555,12 +4667,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.  */
@@ -4622,20 +4750,23 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg)
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
 
   /* ??? std_gimplify_va_arg_expr passes NULL for cum.  Fortunately, we
-     never pass variadic arguments in floating-point registers, so we can
-     avoid the call to riscv_get_arg_info in this case.  */
+     never pass variadic arguments in floating-point and vector registers,
+     so we can avoid the call to riscv_get_arg_info in this case.  */
   if (cum != NULL)
     {
       /* Don't pass by reference if we can use a floating-point register.  */
       riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false);
       if (info.num_fprs)
 	return false;
+
+      /* Don't pass by reference if we can use vector register groups.  */
+      if (info.num_vrs > 0 || info.num_mrs > 0)
+	return false;
     }
 
-  /* All current vector arguments and return values are passed through the
-     function stack. Ideally, we should either warn the user not to use an RVV
-     vector type as function argument or support a calling convention
-     with better performance.  */
+  /* When vector abi disabled(without --param=riscv-vector-abi option) or
+     scalable vector argument is anonymous or cannot be passed through vector
+     registers, this argument is passed by reference. */
   if (riscv_v_ext_mode_p (arg.mode))
     return true;
 
@@ -4693,6 +4824,73 @@ riscv_setup_incoming_varargs (cumulative_args_t cum,
     cfun->machine->varargs_size = gp_saved * UNITS_PER_WORD;
 }
 
+/* Return the descriptor of the Standard Vector Calling Convention Variant.  */
+
+static const predefined_function_abi &
+riscv_v_abi ()
+{
+  predefined_function_abi &v_abi = function_abis[RISCV_CC_V];
+  if (!v_abi.initialized_p ())
+    {
+      HARD_REG_SET full_reg_clobbers
+	= default_function_abi.full_reg_clobbers ();
+      /* Callee-saved vector registers: v1-v7, v24-v31.  */
+      for (int regno = V_REG_FIRST + 1; regno <= V_REG_FIRST + 7; regno += 1)
+	CLEAR_HARD_REG_BIT (full_reg_clobbers, regno);
+      for (int regno = V_REG_FIRST + 24; regno <= V_REG_FIRST + 31; regno += 1)
+	CLEAR_HARD_REG_BIT (full_reg_clobbers, regno);
+      v_abi.initialize (RISCV_CC_V, full_reg_clobbers);
+    }
+  return v_abi;
+}
+
+/* Return true if a function with type FNTYPE returns its value in
+   RISC-V V registers.  */
+
+static bool
+riscv_return_value_is_vector_type_p (const_tree fntype)
+{
+  tree return_type = TREE_TYPE (fntype);
+
+  return riscv_vector_type_p (return_type);
+}
+
+/* Return true if a function with type FNTYPE takes arguments in
+   RISC-V V registers.  */
+
+static bool
+riscv_arguments_is_vector_type_p (const_tree fntype)
+{
+  for (tree chain = TYPE_ARG_TYPES (fntype); chain && chain != void_list_node;
+       chain = TREE_CHAIN (chain))
+    {
+      tree arg_type = TREE_VALUE (chain);
+      if (riscv_vector_type_p (arg_type))
+	return true;
+    }
+
+  return false;
+}
+
+/* Implement TARGET_FNTYPE_ABI.  */
+
+static const predefined_function_abi &
+riscv_fntype_abi (const_tree fntype)
+{
+  /* Implementing an experimental vector calling convention, the proposal
+     can be viewed at the bellow link:
+       https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389
+
+     You can enable this feature via the `--param=riscv-vector-abi` compiler
+     option.  */
+  if (riscv_vector_abi
+      && (riscv_return_value_is_vector_type_p (fntype)
+	  || riscv_arguments_is_vector_type_p (fntype)))
+    return riscv_v_abi ();
+
+  return default_function_abi;
+}
+
 /* Handle an attribute requiring a FUNCTION_DECL;
    arguments as in struct attribute_spec.handler.  */
 static tree
@@ -9365,6 +9563,9 @@ riscv_frame_pointer_required (void)
 #undef TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED riscv_frame_pointer_required
 
+#undef TARGET_FNTYPE_ABI
+#define TARGET_FNTYPE_ABI riscv_fntype_abi
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index fa0d795168e..222aeec2b24 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.  */
@@ -666,6 +667,9 @@ enum reg_class
 
 #define MAX_ARGS_IN_REGISTERS (riscv_abi == ABI_ILP32E ? 6 : 8)
 
+#define MAX_ARGS_IN_VECTOR_REGISTERS (16)
+#define MAX_ARGS_IN_MASK_REGISTERS (1)
+
 /* Symbolic macros for the first/last argument registers.  */
 
 #define GP_ARG_FIRST (GP_REG_FIRST + 10)
@@ -673,6 +677,8 @@ enum reg_class
 #define GP_TEMP_FIRST (GP_REG_FIRST + 5)
 #define FP_ARG_FIRST (FP_REG_FIRST + 10)
 #define FP_ARG_LAST  (FP_ARG_FIRST + MAX_ARGS_IN_REGISTERS - 1)
+#define V_ARG_FIRST (V_REG_FIRST + 8)
+#define V_ARG_LAST (V_ARG_FIRST + MAX_ARGS_IN_VECTOR_REGISTERS - 1)
 
 #define CALLEE_SAVED_REG_NUMBER(REGNO)			\
   ((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 :		\
@@ -696,7 +702,19 @@ enum reg_class
   (IN_RANGE ((N), GP_ARG_FIRST, GP_ARG_LAST)				\
    || (UNITS_PER_FP_ARG && IN_RANGE ((N), FP_ARG_FIRST, FP_ARG_LAST)))
 
+/* Define the standard RISC-V calling convention and variants.  */
+
+enum riscv_cc
+{
+  RISCV_CC_BASE = 0, /* Base standard RISC-V ABI.  */
+  RISCV_CC_V, /* For functions that pass or return values in V registers.  */
+  RISCV_CC_UNKNOWN
+};
+
 typedef struct {
+  /* The calling convention that current function used.  */
+  enum riscv_cc variant_cc;
+
   /* Number of integer registers used so far, up to MAX_ARGS_IN_REGISTERS. */
   unsigned int num_gprs;
 
@@ -704,6 +722,13 @@ typedef struct {
   unsigned int num_fprs;
 
   int rvv_psabi_warning;
+
+  /* Number of mask registers used so far, up to MAX_ARGS_IN_MASK_REGISTERS.  */
+  unsigned int num_mrs;
+
+  /* The used state of args in vector registers, true for used by prev arg,
+     initial to false.  */
+  bool used_vrs[MAX_ARGS_IN_VECTOR_REGISTERS];
 } CUMULATIVE_ARGS;
 
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index d2407c3c502..7d00f4e6c5f 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -314,3 +314,8 @@ Enum(riscv_autovec_lmul) String(m8) Value(RVV_M8)
 -param=riscv-autovec-lmul=
 Target RejectNegative Joined Enum(riscv_autovec_lmul) Var(riscv_autovec_lmul) Init(RVV_M1)
 -param=riscv-autovec-lmul=<string>	Set the RVV LMUL of auto-vectorization in the RISC-V port.
+
+-param=riscv-vector-abi
+Target Undocumented Bool Var(riscv_vector_abi) Init(0)
+Enable the use of vector registers for function arguments and return value.
+This is an experimental switch and may be subject to change in the future.
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c
new file mode 100644
index 00000000000..60407278a5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1-run.c
@@ -0,0 +1,127 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-1.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "riscv_vector.h"
+
+#define FOO_(TYPE) void foo_##TYPE (TYPE val, TYPE *out);
+
+FOO_ (vbool1_t)
+FOO_ (vbool2_t)
+FOO_ (vbool4_t)
+FOO_ (vbool8_t)
+FOO_ (vbool16_t)
+FOO_ (vbool32_t)
+FOO_ (vbool64_t)
+FOO_ (vint8mf8_t)
+FOO_ (vint8mf4_t)
+FOO_ (vint8mf2_t)
+FOO_ (vint8m1_t)
+FOO_ (vint8m2_t)
+FOO_ (vint8m4_t)
+FOO_ (vint8m8_t)
+FOO_ (vint8m1x5_t)
+FOO_ (vint8m1x8_t)
+FOO_ (vint8m2x3_t)
+FOO_ (vint8m2x4_t)
+FOO_ (vint8m4x2_t)
+
+bool
+check_mask (int8_t *test_data, int8_t *golden_data, size_t vl)
+{
+  size_t i = 0;
+  for (; i + 8 <= vl; i += 8)
+    {
+      if (test_data[i / 8] != golden_data[i / 8])
+	{
+	  printf ("mask diff %lu: %d, %d\n", i / 8, test_data[i / 8],
+		  golden_data[i / 8]);
+	  return false;
+	}
+    }
+  if (vl % 8 != 0)
+    {
+      if ((test_data[i / 8] << (8 - (vl % 8)))
+	  != (golden_data[i / 8] << (8 - (vl % 8))))
+	{
+	  printf ("mask tail diff %lu, tail %d: %d, %d\n", i / 8, vl % 8,
+		  test_data[i / 8], golden_data[i / 8]);
+	  return false;
+	}
+    }
+  return true;
+}
+
+bool
+check_data (int8_t *test_data, int8_t *golden_data, size_t vl)
+{
+  for (size_t i = 0; i < vl; i += 1)
+    {
+      if (test_data[i] != golden_data[i])
+	{
+	  printf ("data diff %lu: %d, %d\n", i, test_data[i], golden_data[i]);
+	  return false;
+	}
+    }
+  return true;
+}
+
+#define INIT_DATA                                                              \
+  size_t vlmax_e8m8 = __riscv_vsetvlmax_e8m8 ();                               \
+  int8_t golden_data[vlmax_e8m8];                                              \
+  memset (golden_data, 0, vlmax_e8m8 * sizeof (int8_t));                       \
+  int8_t test_data[vlmax_e8m8];                                                \
+  memset (test_data, 0, vlmax_e8m8 * sizeof (int8_t));                         \
+  for (size_t i = 0; i < vlmax_e8m8; i += 1)                                   \
+    golden_data[i] = vlmax_e8m8 - 1;
+
+#define FOO_MASK(TYPE, VL)                                                     \
+  {                                                                            \
+    INIT_DATA                                                                  \
+    for (size_t i = 0; i < vlmax_e8m8; i += 1)                                 \
+      test_data[i] = 0;                                                        \
+    TYPE val = *(TYPE *) golden_data;                                          \
+    foo_##TYPE (val, (TYPE *) test_data);                                      \
+    if (!check_mask (test_data, golden_data, VL))                              \
+      abort ();                                                                \
+  }
+
+#define FOO_DATA(TYPE, VL)                                                     \
+  {                                                                            \
+    INIT_DATA                                                                  \
+    for (size_t i = 0; i < vlmax_e8m8; i += 1)                                 \
+      test_data[i] = 0;                                                        \
+    TYPE val = *(TYPE *) golden_data;                                          \
+    foo_##TYPE (val, (TYPE *) test_data);                                      \
+    if (!check_data (test_data, golden_data, VL))                              \
+      abort ();                                                                \
+  }
+
+int
+main ()
+{
+  size_t vlmax = __riscv_vsetvlmax_e8mf8 ();
+  FOO_MASK (vbool1_t, vlmax * 64)
+  FOO_MASK (vbool2_t, vlmax * 32)
+  FOO_MASK (vbool4_t, vlmax * 16)
+  FOO_MASK (vbool8_t, vlmax * 8)
+  FOO_MASK (vbool16_t, vlmax * 4)
+  FOO_MASK (vbool32_t, vlmax * 2)
+  FOO_MASK (vbool64_t, vlmax)
+  FOO_DATA (vint8mf8_t, vlmax)
+  FOO_DATA (vint8mf4_t, vlmax * 2)
+  FOO_DATA (vint8mf2_t, vlmax * 4)
+  FOO_DATA (vint8m1_t, vlmax * 8)
+  FOO_DATA (vint8m2_t, vlmax * 16)
+  FOO_DATA (vint8m4_t, vlmax * 32)
+  FOO_DATA (vint8m8_t, vlmax * 64)
+  FOO_DATA (vint8m1x5_t, vlmax * 8 * 5)
+  FOO_DATA (vint8m1x8_t, vlmax * 8 * 8)
+  FOO_DATA (vint8m2x3_t, vlmax * 16 * 3)
+  FOO_DATA (vint8m2x4_t, vlmax * 16 * 4)
+  FOO_DATA (vint8m4x2_t, vlmax * 32 * 2)
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c
new file mode 100644
index 00000000000..40560fccfc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-1.c
@@ -0,0 +1,197 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "riscv_vector.h"
+
+#define FOO_(TYPE)                                                             \
+  void foo_##TYPE (TYPE val, TYPE *out)                                        \
+  {                                                                            \
+    *out = val;                                                                \
+  }
+
+/* Test the first vector mask type argument */
+
+/*
+** foo_vbool1_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool1_t)
+
+/*
+** foo_vbool2_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool2_t)
+
+/*
+** foo_vbool4_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool4_t)
+
+/*
+** foo_vbool8_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool8_t)
+
+/*
+** foo_vbool16_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool16_t)
+
+/*
+** foo_vbool32_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool32_t)
+
+/*
+** foo_vbool64_t:
+**   ...
+**   vsm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool64_t)
+
+/* Test the first vector data type argument */
+
+/*
+** foo_vint8mf8_t:
+**   ...
+**   vse8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf8_t)
+
+/*
+** foo_vint8mf4_t:
+**   ...
+**   vse8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf4_t)
+
+/*
+** foo_vint8mf2_t:
+**   ...
+**   vse8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf2_t)
+
+/*
+** foo_vint8m1_t:
+**   vs1r\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m1_t)
+
+/*
+** foo_vint8m2_t:
+**   vs2r\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m2_t)
+
+/*
+** foo_vint8m4_t:
+**   vs4r\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m4_t)
+
+/*
+** foo_vint8m8_t:
+**   vs8r\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m8_t)
+
+/*
+** foo_vint8m1x5_t:
+**   ...
+**   vs1r\.v\tv8,0\(a0\)
+**   ...
+**   vs1r\.v\tv9,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv10,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv11,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv12,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x5_t)
+
+/*
+** foo_vint8m1x8_t:
+**   ...
+**   vs1r\.v\tv8,0\(a0\)
+**   ...
+**   vs1r\.v\tv9,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv10,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv11,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv12,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv13,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv14,0\(a\d+\)
+**   ...
+**   vs1r\.v\tv15,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x8_t)
+
+/*
+** foo_vint8m2x3_t:
+**   ...
+**   vs2r\.v\tv8,0\(a0\)
+**   ...
+**   vs2r\.v\tv10,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv12,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x3_t)
+
+/*
+** foo_vint8m2x4_t:
+**   ...
+**   vs2r\.v\tv8,0\(a0\)
+**   ...
+**   vs2r\.v\tv10,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv12,0\(a\d+\)
+**   ...
+**   vs2r\.v\tv14,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x4_t)
+
+/*
+** foo_vint8m4x2_t:
+**   ...
+**   vs4r\.v\tv8,0\(a0\)
+**   ...
+**   vs4r\.v\tv12,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m4x2_t)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c
new file mode 100644
index 00000000000..0cb7f7479ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2-run.c
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-2.c } */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include "riscv_vector.h"
+
+int8_t
+va_callee (int count, ...);
+
+bool __attribute__ ((noinline)) va_caller ()
+{
+  size_t vlmax = __riscv_vsetvlmax_e8m1 ();
+  vint8m1_t a1 = __riscv_vmv_v_x_i8m1 (1, vlmax);
+  vint8m1_t a2 = __riscv_vmv_v_x_i8m1 (2, vlmax);
+  vint8m1_t a3 = __riscv_vmv_v_x_i8m1 (3, vlmax);
+  vint8m1_t a4 = __riscv_vmv_v_x_i8m1 (4, vlmax);
+  vint8m1_t a5 = __riscv_vmv_v_x_i8m1 (5, vlmax);
+  vint8m1_t a6 = __riscv_vmv_v_x_i8m1 (6, vlmax);
+  vint8m1_t a7 = __riscv_vmv_v_x_i8m1 (7, vlmax);
+  vint8m1_t a8 = __riscv_vmv_v_x_i8m1 (8, vlmax);
+  int8_t sum = va_callee (8, a1, a2, a3, a4, a5, a6, a7, a8);
+
+  return sum == (int8_t) vlmax * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
+}
+
+int
+main ()
+{
+  if (va_caller ())
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c
new file mode 100644
index 00000000000..6352f2e594a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-2.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+
+#include <stdarg.h>
+#include "riscv_vector.h"
+
+int8_t
+va_callee (int count, ...)
+{
+  size_t vlmax = __riscv_vsetvlmax_e8m1 ();
+  vint8m1_t sum = __riscv_vmv_v_x_i8m1 (0, vlmax);
+  va_list ap;
+  va_start (ap, count);
+  for (int i = count; i > 0; i--)
+    {
+      vint8m1_t arg = va_arg (ap, vint8m1_t);
+      sum = __riscv_vredsum_vs_i8m1_i8m1 (arg, sum, vlmax);
+    }
+  va_end (ap);
+  return __riscv_vmv_x_s_i8m1_i8 (sum);
+}
+
+/* Make sure the variadic arguments is not passed through the vector register.
+ */
+/* { dg-final { scan-assembler-not {vs[0-9]+r} } } */
+/* { dg-final { scan-assembler-not {vsm} } } */
+/* { dg-final { scan-assembler-not {vse[0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
new file mode 100644
index 00000000000..3b1da236268
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3-run.c
@@ -0,0 +1,260 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-3.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "riscv_vector.h"
+
+#define INIT_DATA                                                              \
+  size_t vlmax_e8m8 = __riscv_vsetvlmax_e8m8 ();                               \
+  int8_t golden_data[vlmax_e8m8];                                              \
+  memset (golden_data, 0, vlmax_e8m8 * sizeof (int8_t));                       \
+  int8_t test_data[vlmax_e8m8];                                                \
+  memset (test_data, 0, vlmax_e8m8 * sizeof (int8_t));                         \
+  for (size_t i = 0; i < vlmax_e8m8; i += 1)                                   \
+    golden_data[i] = vlmax_e8m8 - 1;                                           \
+  int8_t dummy_data[vlmax_e8m8];                                               \
+  for (size_t i = 0; i < vlmax_e8m8; i += 1)                                   \
+    dummy_data[i] = -1;
+
+bool
+check_mask (int8_t *test_data, int8_t *golden_data, size_t vl)
+{
+  size_t i = 0;
+  for (; i + 8 <= vl; i += 8)
+    {
+      if (test_data[i / 8] != golden_data[i / 8])
+	{
+	  printf ("mask diff %lu: %d, %d\n", i / 8, test_data[i / 8],
+		  golden_data[i / 8]);
+	  return false;
+	}
+    }
+  if (vl % 8 != 0)
+    {
+      if ((test_data[i / 8] << (8 - (vl % 8)))
+	  != (golden_data[i / 8] << (8 - (vl % 8))))
+	{
+	  printf ("mask tail diff %lu, tail %d: %d, %d\n", i / 8, vl % 8,
+		  test_data[i / 8], golden_data[i / 8]);
+	  return false;
+	}
+    }
+  return true;
+}
+
+bool
+check_data (int8_t *test_data, int8_t *golden_data, size_t vl)
+{
+  for (size_t i = 0; i < vl; i += 1)
+    {
+      if (test_data[i] != golden_data[i])
+	{
+	  printf ("data diff %lu: %d, %d\n", i, test_data[i], golden_data[i]);
+	  return false;
+	}
+    }
+  return true;
+}
+
+void
+foo1 (vbool1_t a, vbool2_t b, vbool4_t c, vbool2_t *out_b);
+void
+check_foo1 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vbool1_t a = *(vbool1_t *) dummy_data;
+  vbool2_t b = *(vbool2_t *) golden_data;
+  vbool4_t c = *(vbool4_t *) dummy_data;
+  foo1 (a, b, c, (vbool2_t *) test_data);
+  if (!check_mask (test_data, golden_data, vlmax_e8mf8 * 32))
+    abort ();
+}
+
+void
+foo2 (vbool1_t a, vbool2_t b, vbool4_t c, vbool8_t d, vbool16_t e, vbool32_t f,
+      vbool64_t g, vbool64_t *out_g);
+void
+check_foo2 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vbool1_t a = *(vbool1_t *) dummy_data;
+  vbool2_t b = *(vbool2_t *) dummy_data;
+  vbool4_t c = *(vbool4_t *) dummy_data;
+  vbool8_t d = *(vbool8_t *) dummy_data;
+  vbool16_t e = *(vbool16_t *) dummy_data;
+  vbool32_t f = *(vbool32_t *) dummy_data;
+  vbool64_t g = *(vbool64_t *) golden_data;
+  foo2 (a, b, c, d, e, f, g, (vbool64_t *) test_data);
+  if (!check_mask (test_data, golden_data, vlmax_e8mf8))
+    abort ();
+}
+
+void
+foo3 (vbool1_t a, vint8m4_t b, vbool2_t c, vbool2_t *out_c);
+void
+check_foo3 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vbool1_t a = *(vbool1_t *) dummy_data;
+  vint8m4_t b = *(vint8m4_t *) dummy_data;
+  vbool2_t c = *(vbool2_t *) golden_data;
+  foo3 (a, b, c, (vbool2_t *) test_data);
+  if (!check_mask (test_data, golden_data, vlmax_e8mf8 * 32))
+    abort ();
+}
+
+void
+foo4 (vbool1_t a, vint8m4_t b, vbool2_t c, vint8m8_t d, vint8m8_t *out_d);
+void
+check_foo4 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vbool1_t a = *(vbool1_t *) dummy_data;
+  vint8m4_t b = *(vint8m4_t *) dummy_data;
+  vbool2_t c = *(vbool2_t *) dummy_data;
+  vint8m8_t d = *(vint8m8_t *) golden_data;
+  foo4 (a, b, c, d, (vint8m8_t *) test_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 64))
+    abort ();
+}
+
+void
+foo5 (vbool1_t a, vint8m8_t b, vint8m8_t c, vint8m4_t d, vint8m4_t *out_d);
+void
+check_foo5 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vbool1_t a = *(vbool1_t *) dummy_data;
+  vint8m8_t b = *(vint8m8_t *) dummy_data;
+  vint8m8_t c = *(vint8m8_t *) dummy_data;
+  vint8m4_t d = *(vint8m4_t *) golden_data;
+  foo5 (a, b, c, d, (vint8m4_t *) test_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 32))
+    abort ();
+}
+
+void
+foo6 (vint8m1_t a, vint8m8_t b, vint8m4_t c, vint8m2_t d, vint8m1_t e,
+      vint8m1_t *out_a, vint8m8_t *out_b, vint8m4_t *out_c, vint8m2_t *out_d,
+      vint8m1_t *out_e);
+void
+check_foo6 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vint8m1_t a = *(vint8m1_t *) golden_data;
+  vint8m8_t b = *(vint8m8_t *) golden_data;
+  vint8m4_t c = *(vint8m4_t *) golden_data;
+  vint8m2_t d = *(vint8m2_t *) golden_data;
+  vint8m1_t e = *(vint8m1_t *) golden_data;
+  foo6 (a, b, c, d, e, (vint8m1_t *) test_data, (vint8m8_t *) dummy_data,
+	(vint8m4_t *) dummy_data, (vint8m2_t *) dummy_data,
+	(vint8m1_t *) dummy_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 8))
+    abort ();
+
+  foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) test_data,
+	(vint8m4_t *) dummy_data, (vint8m2_t *) dummy_data,
+	(vint8m1_t *) dummy_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 64))
+    abort ();
+
+  foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) dummy_data,
+	(vint8m4_t *) test_data, (vint8m2_t *) dummy_data,
+	(vint8m1_t *) dummy_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 32))
+    abort ();
+
+  foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) dummy_data,
+	(vint8m4_t *) dummy_data, (vint8m2_t *) test_data,
+	(vint8m1_t *) dummy_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 16))
+    abort ();
+
+  foo6 (a, b, c, d, e, (vint8m1_t *) dummy_data, (vint8m8_t *) dummy_data,
+	(vint8m4_t *) dummy_data, (vint8m2_t *) dummy_data,
+	(vint8m1_t *) test_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 8))
+    abort ();
+}
+
+void
+foo7 (vint8m1_t a1, vint8m1_t a2, vint8m1_t a3, vint8m1_t a4, vint8m1_t a5,
+      vint8m1_t a6, vint8m1_t a7, vint8m1_t a8, vint8m1_t a9, vint8m1_t a10,
+      vint8m1_t a11, vint8m1_t a12, vint8m1_t a13, vint8m1_t a14, vint8m1_t a15,
+      vint8m1_t a16, vint8m1_t a17, vint8m1_t *out_a17);
+void
+check_foo7 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vint8m1_t a1 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a2 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a3 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a4 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a5 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a6 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a7 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a8 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a9 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a10 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a11 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a12 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a13 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a14 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a15 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a16 = *(vint8m1_t *) dummy_data;
+  vint8m1_t a17 = *(vint8m1_t *) golden_data;
+  foo7 (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16,
+	a17, (vint8m1_t *) test_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 8))
+    abort ();
+}
+
+void
+foo8 (vint8m8_t a1, vint8m8_t a2, vint8m8_t a3,
+      vint8m8_t *out_a3);
+void
+check_foo8 ()
+{
+  INIT_DATA
+
+  size_t vlmax_e8mf8 = __riscv_vsetvlmax_e8mf8 ();
+  vint8m8_t a1 = *(vint8m8_t *) dummy_data;
+  vint8m8_t a2 = *(vint8m8_t *) dummy_data;
+  vint8m8_t a3 = *(vint8m8_t *) golden_data;
+
+  foo8 (a1, a2, a3, (vint8m8_t *) test_data);
+  if (!check_data (test_data, golden_data, vlmax_e8mf8 * 64))
+    abort ();
+}
+
+int
+main ()
+{
+  check_foo1 ();
+  check_foo2 ();
+  check_foo3 ();
+  check_foo4 ();
+  check_foo5 ();
+  check_foo6 ();
+  check_foo7 ();
+  check_foo8 ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
new file mode 100644
index 00000000000..435d61c2c21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-3.c
@@ -0,0 +1,116 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "riscv_vector.h"
+
+/* Test args order.  */
+
+/*
+** foo1:
+**   ...
+**   vsm\.v\tv8,0\(a0\)
+**   ...
+*/
+void
+foo1 (vbool1_t a, vbool2_t b, vbool4_t c, vbool2_t *out_b)
+{
+  *out_b = b;
+}
+
+/*
+** foo2:
+**   ...
+**   vsm\.v\tv13,0\(a0\)
+**   ...
+*/
+void
+foo2 (vbool1_t a, vbool2_t b, vbool4_t c, vbool8_t d, vbool16_t e, vbool32_t f,
+      vbool64_t g, vbool64_t *out_g)
+{
+  *out_g = g;
+}
+
+/*
+** foo3:
+**   ...
+**   vsm\.v\tv12,0\(a0\)
+**   ...
+*/
+void
+foo3 (vbool1_t a, vint8m4_t b, vbool2_t c, vbool2_t *out_c)
+{
+  *out_c = c;
+}
+
+/*
+** foo4:
+**   vs8r\.v\tv16,0\(a0\)
+**   ...
+*/
+void
+foo4 (vbool1_t a, vint8m4_t b, vbool2_t c, vint8m8_t d, vint8m8_t *out_d)
+{
+  *out_d = d;
+}
+
+/*
+** foo5:
+**   vl4re8\.v\tv[0-9]+,0\(a0\)
+**   ...
+**   vs4r\.v\tv[0-9]+,0\(a1\)
+**   ...
+*/
+void
+foo5 (vbool1_t a, vint8m8_t b, vint8m8_t c, vint8m4_t d, vint8m4_t *out_d)
+{
+  *out_d = d;
+}
+
+/*
+** foo6:
+**   vs1r\.v\tv8,0\(a0\)
+**   vs8r\.v\tv16,0\(a1\)
+**   vs4r\.v\tv12,0\(a2\)
+**   vs2r\.v\tv10,0\(a3\)
+**   vs1r\.v\tv9,0\(a4\)
+**   ...
+*/
+void
+foo6 (vint8m1_t a, vint8m8_t b, vint8m4_t c, vint8m2_t d, vint8m1_t e,
+      vint8m1_t *out_a, vint8m8_t *out_b, vint8m4_t *out_c, vint8m2_t *out_d,
+      vint8m1_t *out_e)
+{
+  *out_a = a;
+  *out_b = b;
+  *out_c = c;
+  *out_d = d;
+  *out_e = e;
+}
+
+/*
+** foo7:
+**   vl1re8\.v\tv\d+,0\(a0\)
+**   vs1r\.v\tv\d+,0\(a1\)
+**   ...
+*/
+void
+foo7 (vint8m1_t a1, vint8m1_t a2, vint8m1_t a3, vint8m1_t a4, vint8m1_t a5,
+      vint8m1_t a6, vint8m1_t a7, vint8m1_t a8, vint8m1_t a9, vint8m1_t a10,
+      vint8m1_t a11, vint8m1_t a12, vint8m1_t a13, vint8m1_t a14, vint8m1_t a15,
+      vint8m1_t a16, vint8m1_t a17, vint8m1_t *out_a17)
+{
+  *out_a17 = a17;
+}
+
+/*
+** foo8:
+**   vl8re8\.v\tv\d+,0\(a0\)
+**   vs8r\.v\tv\d+,0\(a1\)
+**   ...
+*/
+void
+foo8 (vint8m8_t a1, vint8m8_t a2, vint8m8_t a3, vint8m8_t *out_a3)
+{
+  *out_a3 = a3;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
new file mode 100644
index 00000000000..f13ab7a8ade
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4-run.c
@@ -0,0 +1,145 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-args-4.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "riscv_vector.h"
+
+vint64m8_t
+foo1 (vint8m1_t a1, vint8m1_t a2, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1,
+      size_t vl);
+vint64m8_t
+foo2 (vint8m1_t a1, vint16m2_t b1, vint8m1_t a2, vint32m4_t c1, vint64m8_t d1,
+      size_t vl);
+vint64m8_t
+foo3 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint8m1_t a2, vint64m8_t d1,
+      size_t vl);
+vint64m8_t
+foo4 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1, vint8m1_t a2,
+      size_t vl);
+
+vint8m1x8_t
+foo5 (vint8m8_t a1, vint8m1x8_t a2);
+
+int
+main ()
+{
+  size_t vlmax_e8m1 = __riscv_vsetvlmax_e8m1 ();
+  int8_t a1[vlmax_e8m1], a2[vlmax_e8m1];
+  int16_t b1[vlmax_e8m1], b2[vlmax_e8m1];
+  int32_t c1[vlmax_e8m1], c2[vlmax_e8m1];
+  int64_t d1[vlmax_e8m1], d2[vlmax_e8m1];
+  memset (a1, 0, vlmax_e8m1 * sizeof (int8_t));
+  memset (a2, 0, vlmax_e8m1 * sizeof (int8_t));
+  memset (b1, 0, vlmax_e8m1 * sizeof (int16_t));
+  memset (b2, 0, vlmax_e8m1 * sizeof (int16_t));
+  memset (c1, 0, vlmax_e8m1 * sizeof (int32_t));
+  memset (c2, 0, vlmax_e8m1 * sizeof (int32_t));
+  memset (d1, 0, vlmax_e8m1 * sizeof (int64_t));
+  memset (d2, 0, vlmax_e8m1 * sizeof (int64_t));
+
+  for (size_t i = 0; i < vlmax_e8m1; i++)
+    {
+      a1[i] = 67 * i;
+      a2[i] = 83 * i;
+      b1[i] = 132 * i;
+      c1[i] = 1928 * i;
+      d1[i] = 23495 * i;
+    }
+
+  for (size_t i = 0; i < vlmax_e8m1; i++)
+    {
+      b2[i] = a1[i] + a2[i];
+    }
+  for (size_t i = 0; i < vlmax_e8m1; i++)
+    {
+      c2[i] = b1[i] - b2[i];
+    }
+
+  for (size_t i = 0; i < vlmax_e8m1; i++)
+    {
+      d2[i] = c1[i] * c2[i];
+      d2[i] = d2[i] & d1[i];
+    }
+  int64_t golden = 0;
+  for (size_t i = 0; i < vlmax_e8m1; i++)
+    {
+      golden += d2[i];
+    }
+
+  int64_t test;
+
+  vint64m8_t res1
+    = foo1 (*(vint8m1_t *) a1, *(vint8m1_t *) a2, *(vint16m2_t *) b1,
+	    *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1);
+  test = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res1, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+
+  if (test != golden)
+    {
+      printf ("foo1: %ld, %ld\n", test, golden);
+      abort ();
+    }
+
+  vint64m8_t res2
+    = foo2 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint8m1_t *) a2,
+	    *(vint32m4_t *) c1, *(vint64m8_t *) d1, vlmax_e8m1);
+  test = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res2, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+
+  if (test != golden)
+    {
+      printf ("foo2: %ld, %ld\n", test, golden);
+      abort ();
+    }
+
+  vint64m8_t res3
+    = foo3 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1,
+	    *(vint8m1_t *) a2, *(vint64m8_t *) d1, vlmax_e8m1);
+  test = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res3, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+  if (test != golden)
+    {
+      printf ("foo3: %ld, %ld\n", test, golden);
+      abort ();
+    }
+
+  vint64m8_t res4
+    = foo4 (*(vint8m1_t *) a1, *(vint16m2_t *) b1, *(vint32m4_t *) c1,
+	    *(vint64m8_t *) d1, *(vint8m1_t *) a2, vlmax_e8m1);
+  test = __riscv_vmv_x_s_i64m1_i64 (
+    __riscv_vredsum_vs_i64m8_i64m1 (res4, __riscv_vmv_v_x_i64m1 (0, vlmax_e8m1),
+				    vlmax_e8m1));
+  if (test != golden)
+    {
+      printf ("foo4: %ld, %ld\n", test, golden);
+      abort ();
+    }
+
+  int8_t t1[vlmax_e8m1 * 8];
+  int8_t t2[vlmax_e8m1 * 8];
+  for (size_t i = 0; i < vlmax_e8m1 * 8; i++)
+    {
+      t1[i] = 67 * i;
+      t2[i] = 83 * i;
+    }
+  vint8m1x8_t res5 = foo5 (*(vint8m8_t *) t1, *(vint8m1x8_t *) t2);
+  int8_t test_arr[vlmax_e8m1 * 8];
+  memset (test_arr, 0, vlmax_e8m1 * 8 * sizeof (int8_t));
+  *(vint8m1x8_t *) test_arr = res5;
+  for (size_t i = 0; i < vlmax_e8m1 * 8; i += 1)
+    if (t2[i] != test_arr[i])
+      {
+	printf ("foo5 %d: %ld, %ld\n", i, test_arr[i], t2[i]);
+	abort ();
+      }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c
new file mode 100644
index 00000000000..b1d99dff979
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-args-4.c
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "riscv_vector.h"
+
+/*
+** foo1:
+**   ...
+**   vwadd\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwsub\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vand\.vv\tv8,v\d+,v\d+
+**   ...
+*/
+vint64m8_t
+foo1 (vint8m1_t a1, vint8m1_t a2, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1,
+      size_t vl)
+{
+  vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl);
+  vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl);
+  vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl);
+  return __riscv_vand_vv_i64m8 (d1, d2, vl);
+}
+
+/*
+** foo2:
+**   ...
+**   vwadd\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwsub\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vand\.vv\tv8,v\d+,v\d+
+**   ...
+*/
+vint64m8_t
+foo2 (vint8m1_t a1, vint16m2_t b1, vint8m1_t a2, vint32m4_t c1, vint64m8_t d1,
+      size_t vl)
+{
+  vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl);
+  vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl);
+  vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl);
+  return __riscv_vand_vv_i64m8 (d1, d2, vl);
+}
+
+/*
+** foo3:
+**   ...
+**   vwadd\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwsub\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vand\.vv\tv8,v\d+,v\d+
+**   ...
+*/
+vint64m8_t
+foo3 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint8m1_t a2, vint64m8_t d1,
+      size_t vl)
+{
+  vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl);
+  vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl);
+  vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl);
+  return __riscv_vand_vv_i64m8 (d1, d2, vl);
+}
+
+/*
+** foo4:
+**   ...
+**   vwadd\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwsub\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vwmul\.vv\tv\d+,v\d+,v\d+
+**   ...
+**   vand\.vv\tv8,v\d+,v\d+
+**   ...
+*/
+vint64m8_t
+foo4 (vint8m1_t a1, vint16m2_t b1, vint32m4_t c1, vint64m8_t d1, vint8m1_t a2,
+      size_t vl)
+{
+  vint16m2_t b2 = __riscv_vwadd_vv_i16m2 (a1, a2, vl);
+  vint32m4_t c2 = __riscv_vwsub_vv_i32m4 (b1, b2, vl);
+  vint64m8_t d2 = __riscv_vwmul_vv_i64m8 (c1, c2, vl);
+  return __riscv_vand_vv_i64m8 (d1, d2, vl);
+}
+
+/*
+** foo5:
+**   vmv1r\.v\tv8,v16
+**   vmv1r\.v\tv9,v17
+**   vmv1r\.v\tv10,v18
+**   vmv1r\.v\tv11,v19
+**   vmv1r\.v\tv12,v20
+**   vmv1r\.v\tv13,v21
+**   vmv1r\.v\tv14,v22
+**   vmv1r\.v\tv15,v23
+**   ...
+*/
+vint8m1x8_t
+foo5 (vint8m8_t a, vint8m1x8_t b)
+{
+  return b;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c
new file mode 100644
index 00000000000..fce548303ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-error-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "--param=riscv-vector-abi -Wno-psabi -Wno-implicit-function-declaration" } */
+
+#include "riscv_vector.h"
+
+int
+foo (int8_t *in)
+{
+  vint8m1_t a = *(vint8m1_t *)in;
+  bar (a); /* { dg-error "RVV type 'vint8m1_t' cannot be passed to an unprototyped function" } */
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c
new file mode 100644
index 00000000000..7802b2ff667
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return-run.c
@@ -0,0 +1,127 @@
+/* { dg-do run } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-additional-sources abi-call-return.c } */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "riscv_vector.h"
+
+#define FOO_(TYPE) TYPE foo_##TYPE (TYPE *out);
+
+FOO_ (vbool1_t)
+FOO_ (vbool2_t)
+FOO_ (vbool4_t)
+FOO_ (vbool8_t)
+FOO_ (vbool16_t)
+FOO_ (vbool32_t)
+FOO_ (vbool64_t)
+FOO_ (vint8mf8_t)
+FOO_ (vint8mf4_t)
+FOO_ (vint8mf2_t)
+FOO_ (vint8m1_t)
+FOO_ (vint8m2_t)
+FOO_ (vint8m4_t)
+FOO_ (vint8m8_t)
+FOO_ (vint8m1x5_t)
+FOO_ (vint8m1x8_t)
+FOO_ (vint8m2x3_t)
+FOO_ (vint8m2x4_t)
+FOO_ (vint8m4x2_t)
+
+bool
+check_mask (int8_t *test_data, int8_t *golden_data, size_t vl)
+{
+  size_t i = 0;
+  for (; i + 8 <= vl; i += 8)
+    {
+      if (test_data[i / 8] != golden_data[i / 8])
+	{
+	  printf ("mask diff %lu: %d, %d\n", i / 8, test_data[i / 8],
+		  golden_data[i / 8]);
+	  return false;
+	}
+    }
+  if (vl % 8 != 0)
+    {
+      if ((test_data[i / 8] << (8 - (vl % 8)))
+	  != (golden_data[i / 8] << (8 - (vl % 8))))
+	{
+	  printf ("mask tail diff %lu, tail %d: %d, %d\n", i / 8, vl % 8,
+		  test_data[i / 8], golden_data[i / 8]);
+	  return false;
+	}
+    }
+  return true;
+}
+
+bool
+check_data (int8_t *test_data, int8_t *golden_data, size_t vl)
+{
+  for (size_t i = 0; i < vl; i += 1)
+    {
+      if (test_data[i] != golden_data[i])
+	{
+	  printf ("data diff %lu: %d, %d\n", i, test_data[i], golden_data[i]);
+	  return false;
+	}
+    }
+  return true;
+}
+
+#define INIT_DATA                                                              \
+  size_t vlmax_e8m8 = __riscv_vsetvlmax_e8m8 ();                               \
+  int8_t golden_data[vlmax_e8m8];                                              \
+  memset (golden_data, 0, vlmax_e8m8 * sizeof (int8_t));                       \
+  int8_t test_data[vlmax_e8m8];                                                \
+  memset (test_data, 0, vlmax_e8m8 * sizeof (int8_t));                         \
+  for (size_t i = 0; i < vlmax_e8m8; i += 1)                                   \
+    golden_data[i] = vlmax_e8m8 - 1;
+
+#define FOO_MASK(TYPE, VL)                                                     \
+  {                                                                            \
+    INIT_DATA                                                                  \
+    for (size_t i = 0; i < vlmax_e8m8; i += 1)                                 \
+      test_data[i] = 0;                                                        \
+    TYPE val = foo_##TYPE ((TYPE *) golden_data);                              \
+    *(TYPE *) test_data = val;                                                 \
+    if (!check_mask (test_data, golden_data, VL))                              \
+      abort ();                                                                \
+  }
+
+#define FOO_DATA(TYPE, VL)                                                     \
+  {                                                                            \
+    INIT_DATA                                                                  \
+    for (size_t i = 0; i < vlmax_e8m8; i += 1)                                 \
+      test_data[i] = 0;                                                        \
+    TYPE val = foo_##TYPE ((TYPE *) golden_data);                              \
+    *(TYPE *) test_data = val;                                                 \
+    if (!check_data (test_data, golden_data, VL))                              \
+      abort ();                                                                \
+  }
+
+int
+main ()
+{
+  size_t vlmax = __riscv_vsetvlmax_e8mf8 ();
+  FOO_MASK (vbool1_t, vlmax * 64)
+  FOO_MASK (vbool2_t, vlmax * 32)
+  FOO_MASK (vbool4_t, vlmax * 16)
+  FOO_MASK (vbool8_t, vlmax * 8)
+  FOO_MASK (vbool16_t, vlmax * 4)
+  FOO_MASK (vbool32_t, vlmax * 2)
+  FOO_MASK (vbool64_t, vlmax)
+  FOO_DATA (vint8mf8_t, vlmax)
+  FOO_DATA (vint8mf4_t, vlmax * 2)
+  FOO_DATA (vint8mf2_t, vlmax * 4)
+  FOO_DATA (vint8m1_t, vlmax * 8)
+  FOO_DATA (vint8m2_t, vlmax * 16)
+  FOO_DATA (vint8m4_t, vlmax * 32)
+  FOO_DATA (vint8m8_t, vlmax * 64)
+  FOO_DATA (vint8m1x5_t, vlmax * 8 * 5)
+  FOO_DATA (vint8m1x8_t, vlmax * 8 * 8)
+  FOO_DATA (vint8m2x3_t, vlmax * 16 * 3)
+  FOO_DATA (vint8m2x4_t, vlmax * 16 * 4)
+  FOO_DATA (vint8m4x2_t, vlmax * 32 * 2)
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c
new file mode 100644
index 00000000000..0e0f3fce299
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-return.c
@@ -0,0 +1,197 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "riscv_vector.h"
+
+#define FOO_(TYPE)                                                             \
+  TYPE foo_##TYPE (TYPE *out)                                                  \
+  {                                                                            \
+    return *out;                                                               \
+  }
+
+/* Test the first vector mask type argument */
+
+/*
+** foo_vbool1_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool1_t)
+
+/*
+** foo_vbool2_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool2_t)
+
+/*
+** foo_vbool4_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool4_t)
+
+/*
+** foo_vbool8_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool8_t)
+
+/*
+** foo_vbool16_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool16_t)
+
+/*
+** foo_vbool32_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool32_t)
+
+/*
+** foo_vbool64_t:
+**   ...
+**   vlm\.v\tv0,0\(a0\)
+**   ...
+*/
+FOO_ (vbool64_t)
+
+/* Test the first vector data type argument */
+
+/*
+** foo_vint8mf8_t:
+**   ...
+**   vle8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf8_t)
+
+/*
+** foo_vint8mf4_t:
+**   ...
+**   vle8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf4_t)
+
+/*
+** foo_vint8mf2_t:
+**   ...
+**   vle8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8mf2_t)
+
+/*
+** foo_vint8m1_t:
+**   vl1re8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m1_t)
+
+/*
+** foo_vint8m2_t:
+**   vl2re8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m2_t)
+
+/*
+** foo_vint8m4_t:
+**   vl4re8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m4_t)
+
+/*
+** foo_vint8m8_t:
+**   vl8re8\.v\tv8,0\(a0\)
+**   ...
+*/
+FOO_ (vint8m8_t)
+
+/*
+** foo_vint8m1x5_t:
+**   ...
+**   vl1re8\.v\tv8,0\(a0\)
+**   ...
+**   vl1re8\.v\tv9,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv10,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv11,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv12,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x5_t)
+
+/*
+** foo_vint8m1x8_t:
+**   ...
+**   vl1re8\.v\tv8,0\(a0\)
+**   ...
+**   vl1re8\.v\tv9,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv10,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv11,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv12,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv13,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv14,0\(a\d+\)
+**   ...
+**   vl1re8\.v\tv15,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m1x8_t)
+
+/*
+** foo_vint8m2x3_t:
+**   ...
+**   vl2re8\.v\tv8,0\(a0\)
+**   ...
+**   vl2re8\.v\tv10,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv12,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x3_t)
+
+/*
+** foo_vint8m2x4_t:
+**   ...
+**   vl2re8\.v\tv8,0\(a0\)
+**   ...
+**   vl2re8\.v\tv10,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv12,0\(a\d+\)
+**   ...
+**   vl2re8\.v\tv14,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m2x4_t)
+
+/*
+** foo_vint8m4x2_t:
+**   ...
+**   vl4re8\.v\tv8,0\(a0\)
+**   ...
+**   vl4re8\.v\tv12,0\(a\d+\)
+**   ...
+*/
+FOO_ (vint8m4x2_t)
-- 
2.36.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH V4 2/3] RISC-V: Part-2: Save/Restore vector registers which need to be preversed
  2023-08-31 12:26 [PATCH V4 0/3] RISC-V: Add an experimental vector calling convention Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 1/3] RISC-V: Part-1: Select suitable vector registers for vector type args and returns Lehua Ding
@ 2023-08-31 12:26 ` Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 3/3] RISC-V: Part-3: Output .variant_cc directive for vector function Lehua Ding
  2 siblings, 0 replies; 4+ messages in thread
From: Lehua Ding @ 2023-08-31 12:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, rdapp.gcc, palmer, jeffreyalaw

Because functions which follow vector calling convention variant has
callee-saved vector reigsters but functions which follow standard calling
convention don't have. We need to distinguish which function callee is so that
we can tell GCC exactly which vector registers callee will clobber. So I encode
the callee's calling convention information into the calls rtx pattern like
AArch64. The old operand 2 and 3 of call pattern which copy from MIPS target are
useless and removed according to my analysis.

gcc/ChangeLog:

	* config/riscv/riscv-sr.cc (riscv_remove_unneeded_save_restore_calls): Pass riscv_cc.
	* config/riscv/riscv.cc (struct riscv_frame_info): Add new fileds.
	(riscv_frame_info::reset): Reset new fileds.
	(riscv_call_tls_get_addr): Pass riscv_cc.
	(riscv_function_arg): Return riscv_cc for call patterm.
	(riscv_insn_callee_abi): Implement TARGET_INSN_CALLEE_ABI.
	(riscv_save_reg_p): Add vector callee-saved check.
	(riscv_stack_align): Add vector save area comment.
	(riscv_compute_frame_info): Ditto.
	(riscv_restore_reg): Update for type change.
	(riscv_for_each_saved_v_reg): New function save vector registers.
	(riscv_first_stack_step): Handle funciton with vector callee-saved registers.
	(riscv_expand_prologue): Ditto.
	(riscv_expand_epilogue): Ditto.
	(riscv_output_mi_thunk): Pass riscv_cc.
	(TARGET_INSN_CALLEE_ABI): Implement TARGET_INSN_CALLEE_ABI.
	* config/riscv/riscv.md: Add CALLEE_CC operand for call pattern.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-1.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-1-save-restore.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-1-zcmp.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-1.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-2-save-restore.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-2-zcmp.c: New test.
	* gcc.target/riscv/rvv/base/abi-callee-saved-2.c: New test.

---
 gcc/config/riscv/riscv-sr.cc                  |  12 +-
 gcc/config/riscv/riscv.cc                     | 194 ++++++++++++++++--
 gcc/config/riscv/riscv.md                     |  43 ++--
 .../rvv/base/abi-callee-saved-1-fixed-1.c     |  86 ++++++++
 .../rvv/base/abi-callee-saved-1-fixed-2.c     |  86 ++++++++
 .../base/abi-callee-saved-1-save-restore.c    |  85 ++++++++
 .../riscv/rvv/base/abi-callee-saved-1-zcmp.c  |  85 ++++++++
 .../riscv/rvv/base/abi-callee-saved-1.c       |  88 ++++++++
 .../base/abi-callee-saved-2-save-restore.c    | 108 ++++++++++
 .../riscv/rvv/base/abi-callee-saved-2-zcmp.c  | 107 ++++++++++
 .../riscv/rvv/base/abi-callee-saved-2.c       | 117 +++++++++++
 11 files changed, 979 insertions(+), 32 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-save-restore.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-save-restore.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-zcmp.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2.c

diff --git a/gcc/config/riscv/riscv-sr.cc b/gcc/config/riscv/riscv-sr.cc
index 7248f04d68f..e6e17685df5 100644
--- a/gcc/config/riscv/riscv-sr.cc
+++ b/gcc/config/riscv/riscv-sr.cc
@@ -447,12 +447,18 @@ riscv_remove_unneeded_save_restore_calls (void)
       && !SIBCALL_REG_P (REGNO (target)))
     return;
 
+  /* Extract RISCV CC from the UNSPEC rtx.  */
+  rtx unspec = XVECEXP (callpat, 0, 1);
+  gcc_assert (GET_CODE (unspec) == UNSPEC
+	      && XINT (unspec, 1) == UNSPEC_CALLEE_CC);
+  riscv_cc cc = (riscv_cc) INTVAL (XVECEXP (unspec, 0, 0));
   rtx sibcall = NULL;
   if (set_target != NULL)
-    sibcall
-      = gen_sibcall_value_internal (set_target, target, const0_rtx);
+    sibcall = gen_sibcall_value_internal (set_target, target, const0_rtx,
+					  gen_int_mode (cc, SImode));
   else
-    sibcall = gen_sibcall_internal (target, const0_rtx);
+    sibcall
+      = gen_sibcall_internal (target, const0_rtx, gen_int_mode (cc, SImode));
 
   rtx_insn *before_call = PREV_INSN (call);
   remove_insn (call);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a317afd1c15..0605298fcb3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -109,6 +109,9 @@ struct GTY(())  riscv_frame_info {
   /* Likewise FPR X.  */
   unsigned int fmask;
 
+  /* Likewise for vector registers.  */
+  unsigned int vmask;
+
   /* How much the GPR save/restore routines adjust sp (or 0 if unused).  */
   unsigned save_libcall_adjustment;
 
@@ -124,6 +127,10 @@ struct GTY(())  riscv_frame_info {
   poly_int64 gp_sp_offset;
   poly_int64 fp_sp_offset;
 
+  /* Top and bottom offsets of vector save areas from frame bottom.  */
+  poly_int64 v_sp_offset_top;
+  poly_int64 v_sp_offset_bottom;
+
   /* Offset of virtual frame pointer from stack pointer/frame bottom */
   poly_int64 frame_pointer_offset;
 
@@ -277,7 +284,7 @@ unsigned riscv_stack_boundary;
 /* If non-zero, this is an offset to be added to SP to redefine the CFA
    when restoring the FP register from the stack.  Only valid when generating
    the epilogue.  */
-static int epilogue_cfa_sp_offset;
+static poly_int64 epilogue_cfa_sp_offset;
 
 /* Which tuning parameters to use.  */
 static const struct riscv_tune_param *tune_param;
@@ -449,10 +456,13 @@ void riscv_frame_info::reset(void)
   total_size = 0;
   mask = 0;
   fmask = 0;
+  vmask = 0;
   save_libcall_adjustment = 0;
 
   gp_sp_offset = 0;
   fp_sp_offset = 0;
+  v_sp_offset_top = 0;
+  v_sp_offset_bottom = 0;
 
   frame_pointer_offset = 0;
 
@@ -1892,7 +1902,8 @@ riscv_call_tls_get_addr (rtx sym, rtx result)
   start_sequence ();
 
   emit_insn (riscv_got_load_tls_gd (a0, sym));
-  insn = emit_call_insn (gen_call_value (result, func, const0_rtx, NULL));
+  insn = emit_call_insn (gen_call_value (result, func, const0_rtx,
+					 gen_int_mode (RISCV_CC_BASE, SImode)));
   RTL_CONST_CALL_P (insn) = 1;
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
   insn = get_insns ();
@@ -4651,7 +4662,8 @@ riscv_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
   struct riscv_arg_info info;
 
   if (arg.end_marker_p ())
-    return NULL;
+    /* Return the calling convention that used by the current function. */
+    return gen_int_mode (cum->variant_cc, SImode);
 
   return riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false);
 }
@@ -4891,6 +4903,21 @@ riscv_fntype_abi (const_tree fntype)
   return default_function_abi;
 }
 
+/* Implement TARGET_INSN_CALLEE_ABI.  */
+
+const predefined_function_abi &
+riscv_insn_callee_abi (const rtx_insn *insn)
+{
+  rtx pat = PATTERN (insn);
+  gcc_assert (GET_CODE (pat) == PARALLEL);
+  rtx unspec = XVECEXP (pat, 0, 1);
+  gcc_assert (GET_CODE (unspec) == UNSPEC
+	      && XINT (unspec, 1) == UNSPEC_CALLEE_CC);
+  riscv_cc cc = (riscv_cc) INTVAL (XVECEXP (unspec, 0, 0));
+  gcc_assert (cc < RISCV_CC_UNKNOWN);
+  return function_abis[cc];
+}
+
 /* Handle an attribute requiring a FUNCTION_DECL;
    arguments as in struct attribute_spec.handler.  */
 static tree
@@ -5746,6 +5773,11 @@ riscv_save_reg_p (unsigned int regno)
   if (call_saved && might_clobber)
     return true;
 
+  /* Save callee-saved V registers.  */
+  if (V_REG_P (regno) && !crtl->abi->clobbers_full_reg_p (regno)
+      && might_clobber)
+    return true;
+
   if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
     return true;
 
@@ -5918,6 +5950,12 @@ riscv_stack_align (HOST_WIDE_INT value)
 	|                               |       + UNITS_PER_FP_REG
 	|  FPR save area                |
 	|                               |
+	+-------------------------------+ <-- stack_pointer_rtx
+	|                               |       + v_sp_offset_top
+	|  Vector Registers save area   |
+	|                               |
+	| ----------------------------- | <-- stack_pointer_rtx
+	| padding                       |       + v_sp_offset_bottom
 	+-------------------------------+ <-- frame_pointer_rtx (virtual)
 	|                               |
 	|  local variables              |
@@ -5941,6 +5979,7 @@ riscv_compute_frame_info (void)
   poly_int64 offset;
   bool interrupt_save_prologue_temp = false;
   unsigned int regno, i, num_x_saved = 0, num_f_saved = 0, x_save_size = 0;
+  unsigned int num_v_saved = 0;
 
   frame = &cfun->machine->frame;
 
@@ -5979,6 +6018,15 @@ riscv_compute_frame_info (void)
 	for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
 	  if (riscv_save_reg_p (regno))
 	    frame->fmask |= 1 << (regno - FP_REG_FIRST), num_f_saved++;
+
+      /* Find out which V registers we need to save. */
+      if (TARGET_VECTOR)
+	for (regno = V_REG_FIRST; regno <= V_REG_LAST; regno++)
+	  if (riscv_save_reg_p (regno))
+	    {
+	      frame->vmask |= 1 << (regno - V_REG_FIRST);
+	      num_v_saved++;
+	    }
     }
 
   if (frame->mask)
@@ -6025,6 +6073,12 @@ riscv_compute_frame_info (void)
   offset += riscv_stack_align (get_frame_size ());
   /* The virtual frame pointer points above the local variables. */
   frame->frame_pointer_offset = offset;
+  /* Next are the callee-saved VRs.  */
+  if (frame->vmask)
+    offset += riscv_stack_align (num_v_saved * UNITS_PER_V_REG);
+  frame->v_sp_offset_top = offset;
+  frame->v_sp_offset_bottom
+    = frame->v_sp_offset_top - num_v_saved * UNITS_PER_V_REG;
   /* Next are the callee-saved FPRs. */
   if (frame->fmask)
     offset += riscv_stack_align (num_f_saved * UNITS_PER_FP_REG);
@@ -6137,10 +6191,12 @@ riscv_restore_reg (rtx reg, rtx mem)
   rtx dwarf = NULL_RTX;
   dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
 
-  if (epilogue_cfa_sp_offset && REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
+  if (known_gt (epilogue_cfa_sp_offset, 0)
+      && REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
     {
-      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-					 GEN_INT (epilogue_cfa_sp_offset));
+      rtx cfa_adjust_rtx
+	= gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+			gen_int_mode (epilogue_cfa_sp_offset, Pmode));
       dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
     }
 
@@ -6322,6 +6378,79 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
       }
 }
 
+/* Call FN for each V register that is saved by the current function.  */
+
+static void
+riscv_for_each_saved_v_reg (poly_int64 &remaining_size,
+			    riscv_save_restore_fn fn, bool prologue)
+{
+  rtx vlen = NULL_RTX;
+  if (cfun->machine->frame.vmask != 0)
+    {
+      if (UNITS_PER_V_REG.is_constant ()
+	  && SMALL_OPERAND (UNITS_PER_V_REG.to_constant ()))
+	vlen = GEN_INT (UNITS_PER_V_REG.to_constant ());
+      else
+	{
+	  vlen = RISCV_PROLOGUE_TEMP (Pmode);
+	  rtx insn
+	    = emit_move_insn (vlen, gen_int_mode (UNITS_PER_V_REG, Pmode));
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	}
+    }
+
+  /* Select the mode where LMUL is 1 and SEW is largest.  */
+  machine_mode m1_mode = TARGET_VECTOR_ELEN_64 ? RVVM1DImode : RVVM1SImode;
+
+  if (prologue)
+    {
+      /* This loop must iterate over the same space as its companion in
+	 riscv_compute_frame_info.  */
+      for (unsigned int regno = V_REG_FIRST; regno <= V_REG_LAST; regno++)
+	if (BITSET_P (cfun->machine->frame.vmask, regno - V_REG_FIRST))
+	  {
+	    bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
+	    if (handle_reg)
+	      {
+		rtx insn = NULL_RTX;
+		if (CONST_INT_P (vlen))
+		  {
+		    gcc_assert (SMALL_OPERAND (-INTVAL (vlen)));
+		    insn = emit_insn (gen_add3_insn (stack_pointer_rtx,
+						     stack_pointer_rtx,
+						     GEN_INT (-INTVAL (vlen))));
+		  }
+		else
+		  insn = emit_insn (
+		    gen_sub3_insn (stack_pointer_rtx, stack_pointer_rtx, vlen));
+		gcc_assert (insn != NULL_RTX);
+		RTX_FRAME_RELATED_P (insn) = 1;
+		riscv_save_restore_reg (m1_mode, regno, 0, fn);
+		remaining_size -= UNITS_PER_V_REG;
+	      }
+	  }
+    }
+  else
+    {
+      /* This loop must iterate over the same space as its companion in
+	 riscv_compute_frame_info.  */
+      for (unsigned int regno = V_REG_LAST; regno >= V_REG_FIRST; regno--)
+	if (BITSET_P (cfun->machine->frame.vmask, regno - V_REG_FIRST))
+	  {
+	    bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
+	    if (handle_reg)
+	      {
+		riscv_save_restore_reg (m1_mode, regno, 0, fn);
+		rtx insn = emit_insn (
+		  gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, vlen));
+		gcc_assert (insn != NULL_RTX);
+		RTX_FRAME_RELATED_P (insn) = 1;
+		remaining_size -= UNITS_PER_V_REG;
+	      }
+	  }
+    }
+}
+
 /* For stack frames that can't be allocated with a single ADDI instruction,
    compute the best value to initially allocate.  It must at a minimum
    allocate enough space to spill the callee-saved registers.  If TARGET_RVC,
@@ -6339,6 +6468,11 @@ riscv_first_stack_step (struct riscv_frame_info *frame, poly_int64 remaining_siz
   else
     remaining_const_size = remaining_size.to_constant ();
 
+  /* First step must be set to the top of vector registers save area if any
+     vector registers need be preversed.  */
+  if (frame->vmask != 0)
+    return (remaining_size - frame->v_sp_offset_top).to_constant ();
+
   if (SMALL_OPERAND (remaining_const_size))
     return remaining_const_size;
 
@@ -6532,11 +6666,20 @@ riscv_expand_prologue (void)
   if (riscv_use_multi_push (frame))
     {
       remaining_size -= frame->multi_push_adj_base;
-      if (known_gt (remaining_size, 2 * ZCMP_SP_INC_STEP))
+      /* If there are vector registers that need to be saved, then it can only
+	 be reduced to the frame->v_sp_offset_top position at most, since the
+	 vector registers will need to be saved one by one by decreasing the SP
+	 later.  */
+      poly_int64 remaining_size_above_varea
+	= frame->vmask != 0
+	    ? remaining_size - frame->v_sp_offset_top
+	    : remaining_size;
+
+      if (known_gt (remaining_size_above_varea, 2 * ZCMP_SP_INC_STEP))
 	spimm = 3;
-      else if (known_gt (remaining_size, ZCMP_SP_INC_STEP))
+      else if (known_gt (remaining_size_above_varea, ZCMP_SP_INC_STEP))
 	spimm = 2;
-      else if (known_gt (remaining_size, 0))
+      else if (known_gt (remaining_size_above_varea, 0))
 	spimm = 1;
       else
 	spimm = 0;
@@ -6580,7 +6723,7 @@ riscv_expand_prologue (void)
       REG_NOTES (insn) = dwarf;
     }
 
-  /* Save the registers.  */
+  /* Save the GP, FP registers.  */
   if ((frame->mask | frame->fmask) != 0)
     {
       if (known_gt (remaining_size, frame->frame_pointer_offset))
@@ -6608,6 +6751,10 @@ riscv_expand_prologue (void)
       riscv_emit_stack_tie ();
     }
 
+  /* Save the V registers.  */
+  if (frame->vmask != 0)
+    riscv_for_each_saved_v_reg (remaining_size, riscv_save_reg, true);
+
   /* Allocate the rest of the frame.  */
   if (known_gt (remaining_size, 0))
     {
@@ -6787,7 +6934,7 @@ riscv_expand_epilogue (int style)
   unsigned mask = frame->mask;
   unsigned fmask = frame->fmask;
   unsigned mask_fprs_push = 0;
-  HOST_WIDE_INT step2 = 0;
+  poly_int64 step2 = 0;
   bool use_multi_pop_normal
     = ((style == NORMAL_RETURN) && riscv_use_multi_push (frame));
   bool use_multi_pop_sibcall
@@ -6892,7 +7039,16 @@ riscv_expand_epilogue (int style)
   if (use_restore_libcall || use_multi_pop)
     frame->mask = mask; /* Undo the above fib.  */
 
-  poly_int64 step1 = frame->total_size - step2 - libcall_size - multipop_size;
+  poly_int64 step1;
+  /* STEP1 must be set to the bottom of vector registers save area if any
+     vector registers need be preversed.  */
+  if (frame->vmask != 0)
+    {
+      step1 = frame->v_sp_offset_bottom;
+      step2 = frame->total_size - step1 - libcall_size - multipop_size;
+    }
+  else
+    step1 = frame->total_size - step2 - libcall_size - multipop_size;
 
   /* Set TARGET to BASE + STEP1.  */
   if (known_gt (step1, 0))
@@ -6928,7 +7084,8 @@ riscv_expand_epilogue (int style)
 	  rtx dwarf = NULL_RTX;
 	  rtx cfa_adjust_rtx
 	    = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-			    GEN_INT (step2 + libcall_size + multipop_size));
+			    gen_int_mode (step2 + libcall_size + multipop_size,
+					  Pmode));
 
 	  dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
 	  RTX_FRAME_RELATED_P (insn) = 1;
@@ -6957,6 +7114,7 @@ riscv_expand_epilogue (int style)
     frame->mask = 0; /* Temporarily fib that we need not restore GPRs.  */
 
   /* Restore the registers.  */
+  riscv_for_each_saved_v_reg (step2, riscv_restore_reg, false);
   riscv_for_each_saved_reg (frame->total_size - step2 - libcall_size
 			      - multipop_size,
 			    riscv_restore_reg, true, style == EXCEPTION_RETURN);
@@ -6968,10 +7126,10 @@ riscv_expand_epilogue (int style)
     riscv_emit_stack_tie ();
 
   /* Deallocate the final bit of the frame.  */
-  if (step2 > 0)
+  if (step2.to_constant () > 0)
     {
       insn = emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
-				       GEN_INT (step2)));
+				       GEN_INT (step2.to_constant ())));
 
       rtx dwarf = NULL_RTX;
       rtx cfa_adjust_rtx
@@ -7634,7 +7792,8 @@ riscv_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     }
 
   /* Jump to the target function.  */
-  insn = emit_call_insn (gen_sibcall (fnaddr, const0_rtx, NULL, const0_rtx));
+  rtx callee_cc = gen_int_mode (fndecl_abi (function).id (), SImode);
+  insn = emit_call_insn (gen_sibcall (fnaddr, const0_rtx, callee_cc));
   SIBLING_CALL_P (insn) = 1;
 
   /* Run just enough of rest_of_compilation.  This sequence was
@@ -9566,6 +9725,9 @@ riscv_frame_pointer_required (void)
 #undef TARGET_FNTYPE_ABI
 #define TARGET_FNTYPE_ABI riscv_fntype_abi
 
+#undef TARGET_INSN_CALLEE_ABI
+#define TARGET_INSN_CALLEE_ABI riscv_insn_callee_abi
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 4041875e0e3..5ebe8ab116f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -79,6 +79,9 @@
   UNSPEC_CLMUL
   UNSPEC_CLMULH
   UNSPEC_CLMULR
+
+  ;; the calling convention of callee
+  UNSPEC_CALLEE_CC
 ])
 
 (define_c_enum "unspecv" [
@@ -3033,18 +3036,20 @@
 (define_expand "sibcall"
   [(parallel [(call (match_operand 0 "")
 		    (match_operand 1 ""))
-	      (use (match_operand 2 ""))	;; next_arg_reg
-	      (use (match_operand 3 ""))])]	;; struct_value_size_rtx
+	      (unspec:SI [
+		(match_operand 2 "const_int_operand")
+	       ] UNSPEC_CALLEE_CC)])]
   ""
 {
   rtx target = riscv_legitimize_call_address (XEXP (operands[0], 0));
-  emit_call_insn (gen_sibcall_internal (target, operands[1]));
+  emit_call_insn (gen_sibcall_internal (target, operands[1], operands[2]));
   DONE;
 })
 
 (define_insn "sibcall_internal"
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S,U"))
-	 (match_operand 1 "" ""))]
+	 (match_operand 1 "" ""))
+   (unspec:SI [(match_operand 2 "const_int_operand")] UNSPEC_CALLEE_CC)]
   "SIBLING_CALL_P (insn)"
   "@
    jr\t%0
@@ -3056,18 +3061,22 @@
   [(parallel [(set (match_operand 0 "")
 		   (call (match_operand 1 "")
 			 (match_operand 2 "")))
-	      (use (match_operand 3 ""))])]		;; next_arg_reg
+	      (unspec:SI [
+		(match_operand 3 "const_int_operand")
+	       ] UNSPEC_CALLEE_CC)])]
   ""
 {
   rtx target = riscv_legitimize_call_address (XEXP (operands[1], 0));
-  emit_call_insn (gen_sibcall_value_internal (operands[0], target, operands[2]));
+  emit_call_insn (gen_sibcall_value_internal (operands[0], target, operands[2],
+					      operands[3]));
   DONE;
 })
 
 (define_insn "sibcall_value_internal"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand 1 "call_insn_operand" "j,S,U"))
-	      (match_operand 2 "" "")))]
+	      (match_operand 2 "" "")))
+   (unspec:SI [(match_operand 3 "const_int_operand")] UNSPEC_CALLEE_CC)]
   "SIBLING_CALL_P (insn)"
   "@
    jr\t%1
@@ -3078,18 +3087,20 @@
 (define_expand "call"
   [(parallel [(call (match_operand 0 "")
 		    (match_operand 1 ""))
-	      (use (match_operand 2 ""))	;; next_arg_reg
-	      (use (match_operand 3 ""))])]	;; struct_value_size_rtx
+	      (unspec:SI [
+		(match_operand 2 "const_int_operand")
+	       ] UNSPEC_CALLEE_CC)])]
   ""
 {
   rtx target = riscv_legitimize_call_address (XEXP (operands[0], 0));
-  emit_call_insn (gen_call_internal (target, operands[1]));
+  emit_call_insn (gen_call_internal (target, operands[1], operands[2]));
   DONE;
 })
 
 (define_insn "call_internal"
   [(call (mem:SI (match_operand 0 "call_insn_operand" "l,S,U"))
 	 (match_operand 1 "" ""))
+   (unspec:SI [(match_operand 2 "const_int_operand")] UNSPEC_CALLEE_CC)
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
   "@
@@ -3102,11 +3113,14 @@
   [(parallel [(set (match_operand 0 "")
 		   (call (match_operand 1 "")
 			 (match_operand 2 "")))
-	      (use (match_operand 3 ""))])]		;; next_arg_reg
+	      (unspec:SI [
+		(match_operand 3 "const_int_operand")
+	       ] UNSPEC_CALLEE_CC)])]
   ""
 {
   rtx target = riscv_legitimize_call_address (XEXP (operands[1], 0));
-  emit_call_insn (gen_call_value_internal (operands[0], target, operands[2]));
+  emit_call_insn (gen_call_value_internal (operands[0], target, operands[2],
+					   operands[3]));
   DONE;
 })
 
@@ -3114,6 +3128,7 @@
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand 1 "call_insn_operand" "l,S,U"))
 	      (match_operand 2 "" "")))
+   (unspec:SI [(match_operand 3 "const_int_operand")] UNSPEC_CALLEE_CC)
    (clobber (reg:SI RETURN_ADDR_REGNUM))]
   ""
   "@
@@ -3133,7 +3148,9 @@
 {
   int i;
 
-  emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
+  /* Untyped calls always use the RISCV_CC_BASE calling convention.  */
+  emit_call_insn (gen_call (operands[0], const0_rtx,
+			    gen_int_mode (RISCV_CC_BASE, SImode)));
 
   for (i = 0; i < XVECLEN (operands[2], 0); i++)
     {
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-1.c
new file mode 100644
index 00000000000..1e6292e84ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-1.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gczve32x -mabi=lp64d --param=riscv-vector-abi --param=riscv-autovec-preference=fixed-vlmax -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar (int8_t *data);
+
+/*
+** foo1:
+**   addi\tsp,sp,-16
+**   sd\tra,8\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv1,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv2,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv3,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv4,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv5,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv6,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv7,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv24,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv25,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv26,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv27,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv28,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv29,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv30,0\(sp\)
+**   addi\tsp,sp,-4
+**   vs1r\.v\tv31,0\(sp\)
+**   addi\tsp,sp,-1028
+**   mv\ta0,sp
+**   call\tbar
+**   addi\tsp,sp,1028
+**   vl1re32\.v\tv31,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv30,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv29,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv28,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv27,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv26,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv25,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv24,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv7,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv6,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv5,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv4,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv3,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv2,0\(sp\)
+**   addi\tsp,sp,4
+**   vl1re32\.v\tv1,0\(sp\)
+**   addi\tsp,sp,4
+**   ld\tra,8\(sp\)
+**   addi\tsp,sp,16
+**   jr\tra
+*/
+void
+foo1 (vint8m1_t a)
+{
+  int8_t data[1024];
+  bar (data);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c
new file mode 100644
index 00000000000..9fdbcd8deb3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zvl4096b -mabi=lp64d --param=riscv-vector-abi --param=riscv-autovec-preference=fixed-vlmax -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar (int8_t *data);
+
+/*
+** foo1:
+**   addi\tsp,sp,-16
+**   sd\tra,8\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv1,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv2,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv3,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv4,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv5,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv6,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv7,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv24,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv25,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv26,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv27,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv28,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv29,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv30,0\(sp\)
+**   addi\tsp,sp,-512
+**   vs1r\.v\tv31,0\(sp\)
+**   addi\tsp,sp,-1024
+**   mv\ta0,sp
+**   call\tbar
+**   addi\tsp,sp,1024
+**   vl1re64\.v\tv31,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv30,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv29,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv28,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv27,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv26,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv25,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv24,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv7,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv6,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv5,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv4,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv3,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv2,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re64\.v\tv1,0\(sp\)
+**   addi\tsp,sp,512
+**   ld\tra,8\(sp\)
+**   addi\tsp,sp,16
+**   jr\tra
+*/
+void
+foo1 (vint8m1_t a)
+{
+  int8_t data[1024];
+  bar (data);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-save-restore.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-save-restore.c
new file mode 100644
index 00000000000..007c27498b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-save-restore.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh -mabi=lp64d --param=riscv-vector-abi -Wno-psabi -msave-restore" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar (int8_t *data);
+
+/*
+** foo1:
+**   call\tt0,__riscv_save_0
+**   csrr\tt0,vlenb
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv1,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv2,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv3,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv4,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv5,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv6,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv7,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv24,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv25,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv26,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv27,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv28,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv29,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv30,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv31,0\(sp\)
+**   addi\tsp,sp,-1024
+**   mv\ta0,sp
+**   call\tbar
+**   addi\tsp,sp,1024
+**   csrr\tt0,vlenb
+**   vl1re64\.v\tv31,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv30,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv29,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv28,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv27,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv26,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv25,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv24,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv7,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv6,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv5,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv4,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv3,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv2,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv1,0\(sp\)
+**   add\tsp,sp,t0
+**   tail\t__riscv_restore_0
+*/
+void
+foo1 (vint8m1_t a)
+{
+  int8_t data[1024];
+  bar (data);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-zcmp.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-zcmp.c
new file mode 100644
index 00000000000..5f697e7c372
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-zcmp.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh_zca_zcmp -mabi=lp64d --param=riscv-vector-abi -Wno-psabi -fno-shrink-wrap-separate" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar (int8_t *data);
+
+/*
+** foo1:
+**   cm.push\t\{ra\},\s*-16
+**   csrr\tt0,vlenb
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv1,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv2,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv3,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv4,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv5,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv6,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv7,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv24,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv25,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv26,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv27,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv28,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv29,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv30,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv31,0\(sp\)
+**   addi\tsp,sp,-1024
+**   mv\ta0,sp
+**   call\tbar
+**   addi\tsp,sp,1024
+**   csrr\tt0,vlenb
+**   vl1re64\.v\tv31,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv30,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv29,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv28,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv27,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv26,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv25,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv24,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv7,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv6,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv5,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv4,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv3,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv2,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv1,0\(sp\)
+**   add\tsp,sp,t0
+**   cm.popret\t{ra},\s*16
+*/
+void
+foo1 (vint8m1_t a)
+{
+  int8_t data[1024];
+  bar (data);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c
new file mode 100644
index 00000000000..42d099d39fd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c
@@ -0,0 +1,88 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh -mabi=lp64d --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar (int8_t *data);
+
+/*
+** foo1:
+**   addi\tsp,sp,-16
+**   sd\tra,8\(sp\)
+**   csrr\tt0,vlenb
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv1,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv2,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv3,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv4,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv5,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv6,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv7,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv24,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv25,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv26,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv27,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv28,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv29,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv30,0\(sp\)
+**   sub\tsp,sp,t0
+**   vs1r\.v\tv31,0\(sp\)
+**   addi\tsp,sp,-1024
+**   mv\ta0,sp
+**   call\tbar
+**   addi\tsp,sp,1024
+**   csrr\tt0,vlenb
+**   vl1re64\.v\tv31,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv30,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv29,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv28,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv27,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv26,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv25,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv24,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv7,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv6,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv5,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv4,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv3,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv2,0\(sp\)
+**   add\tsp,sp,t0
+**   vl1re64\.v\tv1,0\(sp\)
+**   add\tsp,sp,t0
+**   ld\tra,8\(sp\)
+**   addi\tsp,sp,16
+**   jr\tra
+*/
+void
+foo1 (vint8m1_t a)
+{
+  int8_t data[1024];
+  bar (data);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-save-restore.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-save-restore.c
new file mode 100644
index 00000000000..ce2f68e07d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-save-restore.c
@@ -0,0 +1,108 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh -mabi=lp64d --param=riscv-vector-abi -Wno-psabi -msave-restore" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar1 (vint8m1_t a);
+void bar2 ();
+
+/*
+** foo1:
+**   tail\tbar1
+*/
+void
+foo1 (vint8m1_t a)
+{
+  bar1 (a);
+}
+
+/*
+**  foo2:
+**    call\tt0,__riscv_save_0
+**    csrr\tt0,vlenb
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv1,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv2,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv3,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv4,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv5,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv6,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv7,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv24,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv25,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv26,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv27,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv28,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv29,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv30,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv31,0\(sp\)
+**    call\tbar2
+**    csrr\tt0,vlenb
+**    vl1re64\.v\tv31,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv30,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv29,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv28,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv27,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv26,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv25,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv24,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv7,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv6,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv5,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv4,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv3,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv2,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv1,0\(sp\)
+**    add\tsp,sp,t0
+**    tail\t__riscv_restore_0
+
+*/
+void
+foo2 (vint8m1_t a)
+{
+  bar2 ();
+}
+
+/*
+** foo3:
+**   call\tt0,__riscv_save_0
+**   vl1re8\.v\tv8,0\(a0\)
+**   call\tbar1
+**   call\tbar2
+**   tail\t__riscv_restore_0
+*/
+void
+foo3 (vint8m1_t *a)
+{
+  bar1 (*a);
+  bar2 ();
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-zcmp.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-zcmp.c
new file mode 100644
index 00000000000..08ca1a102a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2-zcmp.c
@@ -0,0 +1,107 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh_zca_zcmp -mabi=lp64d --param=riscv-vector-abi -Wno-psabi -fno-shrink-wrap-separate" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar1 (vint8m1_t a);
+void bar2 ();
+
+/*
+** foo1:
+**   cm.push\t{ra},\s*-16
+**   call\tbar1
+**   cm.popret\t{ra},\s*16
+*/
+void
+foo1 (vint8m1_t a)
+{
+  bar1 (a);
+}
+
+/*
+**  foo2:
+**    cm.push\t{ra},\s*-16
+**    csrr\tt0,vlenb
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv1,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv2,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv3,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv4,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv5,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv6,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv7,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv24,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv25,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv26,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv27,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv28,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv29,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv30,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv31,0\(sp\)
+**    call\tbar2
+**    csrr\tt0,vlenb
+**    vl1re64\.v\tv31,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv30,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv29,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv28,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv27,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv26,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv25,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv24,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv7,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv6,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv5,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv4,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv3,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv2,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv1,0\(sp\)
+**    add\tsp,sp,t0
+**    cm.popret\t{ra},\s*16
+*/
+void
+foo2 (vint8m1_t a)
+{
+  bar2 ();
+}
+
+/*
+** foo3:
+**   cm.push\t{ra},\s*-16
+**   vl1re8\.v\tv8,0\(a0\)
+**   call\tbar1
+**   cm.popret\t{ra},\s*16
+*/
+void
+foo3 (vint8m1_t *a)
+{
+  bar1 (*a);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2.c
new file mode 100644
index 00000000000..0ea3e247368
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-2.c
@@ -0,0 +1,117 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh -mabi=lp64d --param=riscv-vector-abi -Wno-psabi" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <riscv_vector.h>
+
+void bar1 (vint8m1_t a);
+void bar2 ();
+
+/*
+** foo1:
+**   addi\tsp,sp,-16
+**   sd\tra,8\(sp\)
+**   call\tbar1
+**   ld\tra,8\(sp\)
+**   addi\tsp,sp,16
+**   jr\tra
+*/
+void
+foo1 (vint8m1_t a)
+{
+  bar1 (a);
+}
+
+/*
+**  foo2:
+**    addi\tsp,sp,-16
+**    sd\tra,8\(sp\)
+**    csrr\tt0,vlenb
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv1,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv2,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv3,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv4,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv5,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv6,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv7,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv24,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv25,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv26,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv27,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv28,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv29,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv30,0\(sp\)
+**    sub\tsp,sp,t0
+**    vs1r\.v\tv31,0\(sp\)
+**    call\tbar2
+**    csrr\tt0,vlenb
+**    vl1re64\.v\tv31,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv30,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv29,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv28,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv27,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv26,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv25,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv24,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv7,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv6,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv5,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv4,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv3,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv2,0\(sp\)
+**    add\tsp,sp,t0
+**    vl1re64\.v\tv1,0\(sp\)
+**    add\tsp,sp,t0
+**    ld\tra,8\(sp\)
+**    addi\tsp,sp,16
+**    jr\tra
+
+*/
+void
+foo2 (vint8m1_t a)
+{
+  bar2 ();
+}
+
+/*
+** foo3:
+**   addi\tsp,sp,-16
+**   sd\tra,8\(sp\)
+**   vl1re8\.v\tv8,0\(a0\)
+**   call\tbar1
+**   ld\tra,8\(sp\)
+**   addi\tsp,sp,16
+**   jr\tra
+*/
+void
+foo3 (vint8m1_t *a)
+{
+  bar1 (*a);
+}
-- 
2.36.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH V4 3/3] RISC-V: Part-3: Output .variant_cc directive for vector function
  2023-08-31 12:26 [PATCH V4 0/3] RISC-V: Add an experimental vector calling convention Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 1/3] RISC-V: Part-1: Select suitable vector registers for vector type args and returns Lehua Ding
  2023-08-31 12:26 ` [PATCH V4 2/3] RISC-V: Part-2: Save/Restore vector registers which need to be preversed Lehua Ding
@ 2023-08-31 12:26 ` Lehua Ding
  2 siblings, 0 replies; 4+ messages in thread
From: Lehua Ding @ 2023-08-31 12:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, rdapp.gcc, palmer, jeffreyalaw

Functions which follow vector calling convention variant need be annotated by
.variant_cc directive according the RISC-V Assembly Programmer's Manual[1] and
RISC-V ELF Specification[2].

[1] https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md#pseudo-ops
[2] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#dynamic-linking

gcc/ChangeLog:

	* config/riscv/riscv-protos.h (riscv_declare_function_name): Add protos.
	(riscv_asm_output_alias): Ditto.
	(riscv_asm_output_external): Ditto.
	* config/riscv/riscv.cc (riscv_asm_output_variant_cc):
	Output .variant_cc directive for vector function.
	(riscv_declare_function_name): Ditto.
	(riscv_asm_output_alias): Ditto.
	(riscv_asm_output_external): Ditto.
	* config/riscv/riscv.h (ASM_DECLARE_FUNCTION_NAME):
	Implement ASM_DECLARE_FUNCTION_NAME.
	(ASM_OUTPUT_DEF_FROM_DECLS): Implement ASM_OUTPUT_DEF_FROM_DECLS.
	(ASM_OUTPUT_EXTERNAL): Implement ASM_OUTPUT_EXTERNAL.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/abi-call-variant_cc.c: New test.

---
 gcc/config/riscv/riscv-protos.h               |  3 ++
 gcc/config/riscv/riscv.cc                     | 48 +++++++++++++++++++
 gcc/config/riscv/riscv.h                      | 15 ++++++
 .../riscv/rvv/base/abi-call-variant_cc.c      | 39 +++++++++++++++
 4 files changed, 105 insertions(+)
 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 3761ff3b86b..5853808694f 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -102,6 +102,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 *);
 extern bool
 riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT, int);
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 0605298fcb3..5b9b504d1bc 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7708,6 +7708,54 @@ riscv_emit_attribute ()
            riscv_stack_boundary / 8);
 }
 
+/* Output .variant_cc for function symbol which follows vector calling
+   convention.  */
+
+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.  */
+
+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.  */
+
+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.  */
+
+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);
+}
+
 /* Implement TARGET_ASM_FILE_START.  */
 
 static void
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 222aeec2b24..22a419a44e4 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -1046,6 +1046,21 @@ while (0)
 
 #define ASM_COMMENT_START "#"
 
+/* Add output .variant_cc directive for specific function definition.  */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL)                             \
+  riscv_declare_function_name (STR, NAME, DECL)
+
+/* Add output .variant_cc directive for specific alias definition.  */
+#undef ASM_OUTPUT_DEF_FROM_DECLS
+#define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET)                           \
+  riscv_asm_output_alias (STR, DECL, TARGET)
+
+/* Add output .variant_cc directive for specific extern function.  */
+#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/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 } } */
-- 
2.36.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-08-31 12:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-31 12:26 [PATCH V4 0/3] RISC-V: Add an experimental vector calling convention Lehua Ding
2023-08-31 12:26 ` [PATCH V4 1/3] RISC-V: Part-1: Select suitable vector registers for vector type args and returns Lehua Ding
2023-08-31 12:26 ` [PATCH V4 2/3] RISC-V: Part-2: Save/Restore vector registers which need to be preversed Lehua Ding
2023-08-31 12:26 ` [PATCH V4 3/3] RISC-V: Part-3: Output .variant_cc directive for vector function Lehua Ding

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).