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 aa6b46d7611..09c9e09e83a 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -108,6 +108,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;
 
@@ -115,6 +118,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;
 
@@ -265,7 +272,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;
@@ -425,10 +432,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;
 
@@ -1727,7 +1737,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 ();
@@ -4385,7 +4396,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);
 }
@@ -4625,6 +4637,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
@@ -5446,6 +5473,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;
 
@@ -5546,6 +5578,12 @@ riscv_save_libcall_count (unsigned mask)
 	|                               |       + UNITS_PER_HWVALUE
 	|  FPR save area                |
 	|                               |
+	+-------------------------------+ <-- stack_pointer_rtx
+	|                               |       + v_sp_offset_top
+	|  Vector Registers save area   |
+	|                               |
+	| ----------------------------- | <-- stack_pointer_rtx
+	|  area padding                 |       + v_sp_offset_bottom
 	+-------------------------------+ <-- frame_pointer_rtx (virtual)
 	|                               |
 	|  local variables              |
@@ -5582,6 +5620,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;
 
@@ -5620,6 +5659,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)
@@ -5657,6 +5705,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);
@@ -5761,10 +5815,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);
     }
 
@@ -5942,6 +5998,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,
@@ -5959,6 +6088,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;
 
@@ -6074,31 +6208,47 @@ riscv_expand_prologue (void)
       REG_NOTES (insn) = dwarf;
     }
 
-  /* Save the registers.  */
-  if ((frame->mask | frame->fmask) != 0)
+  /* Save the GP, FP, and V registers.  */
+  if ((frame->mask | frame->fmask | frame->vmask) != 0)
     {
       HOST_WIDE_INT step1 = riscv_first_stack_step (frame, remaining_size);
-
-      insn = gen_add3_insn (stack_pointer_rtx,
-			    stack_pointer_rtx,
-			    GEN_INT (-step1));
-      RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
-      remaining_size -= step1;
+      if (step1 != 0)
+	{
+	  insn = gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
+				GEN_INT (-step1));
+	  RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+	  remaining_size -= step1;
+	}
       riscv_for_each_saved_reg (remaining_size, riscv_save_reg, false, false);
-    }
 
-  frame->mask = mask; /* Undo the above fib.  */
+      /* Set up the frame pointer, if we're using one.  */
+      if (frame_pointer_needed)
+	{
+	  insn = gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx,
+				GEN_INT ((frame->hard_frame_pointer_offset
+					  - remaining_size)
+					   .to_constant ()));
+	  RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
+
+	  riscv_emit_stack_tie ();
+	}
 
+      riscv_for_each_saved_v_reg (remaining_size, riscv_save_reg, true);
+    }
   /* Set up the frame pointer, if we're using one.  */
-  if (frame_pointer_needed)
+  else if (frame_pointer_needed)
     {
-      insn = gen_add3_insn (hard_frame_pointer_rtx, stack_pointer_rtx,
-			    GEN_INT ((frame->hard_frame_pointer_offset - remaining_size).to_constant ()));
+      insn = gen_add3_insn (
+	hard_frame_pointer_rtx, stack_pointer_rtx,
+	GEN_INT (
+	  (frame->hard_frame_pointer_offset - remaining_size).to_constant ()));
       RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
 
       riscv_emit_stack_tie ();
     }
 
+  frame->mask = mask; /* Undo the above fib.  */
+
   /* Allocate the rest of the frame.  */
   if (known_gt (remaining_size, 0))
     {
@@ -6178,7 +6328,7 @@ riscv_expand_epilogue (int style)
      Start off by assuming that no registers need to be restored.  */
   struct riscv_frame_info *frame = &cfun->machine->frame;
   unsigned mask = frame->mask;
-  HOST_WIDE_INT step2 = 0;
+  poly_int64 step2 = 0;
   bool use_restore_libcall = ((style == NORMAL_RETURN)
 			      && riscv_use_save_libcall (frame));
   unsigned libcall_size = (use_restore_libcall
@@ -6258,13 +6408,22 @@ riscv_expand_epilogue (int style)
 
   /* If we need to restore registers, deallocate as much stack as
      possible in the second step without going out of range.  */
-  if ((frame->mask | frame->fmask) != 0)
+  if ((frame->mask | frame->fmask | frame->vmask) != 0)
     step2 = riscv_first_stack_step (frame, frame->total_size - libcall_size);
 
   if (use_restore_libcall)
     frame->mask = mask; /* Undo the above fib.  */
 
-  poly_int64 step1 = frame->total_size - step2 - libcall_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;
+    }
+  else
+    step1 = frame->total_size - step2 - libcall_size;
 
   /* Set TARGET to BASE + STEP1.  */
   if (known_gt (step1, 0))
@@ -6298,8 +6457,9 @@ riscv_expand_epilogue (int style)
 					   stack_pointer_rtx,
 					   adjust));
 	  rtx dwarf = NULL_RTX;
-	  rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-					     GEN_INT (step2 + libcall_size));
+	  rtx cfa_adjust_rtx
+	    = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+			    gen_int_mode (step2 + libcall_size, Pmode));
 
 	  dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
 	  RTX_FRAME_RELATED_P (insn) = 1;
@@ -6318,9 +6478,9 @@ riscv_expand_epilogue (int style)
     frame->mask = 0; /* Temporarily fib that we need not save 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,
-			    riscv_restore_reg,
-			    true, style == EXCEPTION_RETURN);
+			    riscv_restore_reg, true, style == EXCEPTION_RETURN);
 
   if (use_restore_libcall)
       frame->mask = mask; /* Undo the above fib.  */
@@ -6329,10 +6489,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 = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
@@ -6951,7 +7111,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
@@ -8868,6 +9029,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 688fd697255..371e9959e61 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -70,6 +70,9 @@
   UNSPEC_CLMUL
   UNSPEC_CLMULH
   UNSPEC_CLMULR
+
+  ;; the calling convention of callee
+  UNSPEC_CALLEE_CC
 ])
 
 (define_c_enum "unspecv" [
@@ -2928,18 +2931,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
@@ -2951,18 +2956,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
@@ -2973,18 +2982,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))]
   ""
   "@
@@ -2997,11 +3008,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;
 })
 
@@ -3009,6 +3023,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))]
   ""
   "@
@@ -3028,7 +3043,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..d0660588c63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-1.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gczve32x -mabi=lp64d --param=riscv-vector-abi --param=riscv-autovec-preference=fixed-vlmax -Wno-psabi" } */
+
+#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..77c5fee24ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1-fixed-2.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zvl4096b -mabi=lp64d --param=riscv-vector-abi --param=riscv-autovec-preference=fixed-vlmax -Wno-psabi" } */
+
+#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,-1028
+**   mv\ta0,sp
+**   call\tbar
+**   addi\tsp,sp,1028
+**   vl1re32\.v\tv31,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv30,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv29,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv28,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv27,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv26,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv25,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv24,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv7,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv6,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv5,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv4,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv3,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.v\tv2,0\(sp\)
+**   addi\tsp,sp,512
+**   vl1re32\.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.c b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c
new file mode 100644
index 00000000000..a2a7f78100e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-callee-saved-1.c
@@ -0,0 +1,87 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=rv64gcv_zfh -mabi=lp64d --param=riscv-vector-abi -Wno-psabi" } */
+
+#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.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);
+}
