diff mbox series

[v3] C-SKY: Support -mfloat-abi=hard.

Message ID 1600157281-28652-1-git-send-email-jiejie_rong@c-sky.com
State New
Headers show
Series [v3] C-SKY: Support -mfloat-abi=hard. | expand

Commit Message

Jojo R Sept. 15, 2020, 8:08 a.m. UTC
gcc/ChangeLog:

	* config/csky/csky.md (CSKY_NPARM_FREGS): New.
	(call_value_internal_vs/d): New.
	(untyped_call): New.
	* config/csky/csky.h (TARGET_SINGLE_FPU): New.
	(TARGET_DOUBLE_FPU): New.
	(FUNCTION_VARG_REGNO_P): New.
	(CSKY_VREG_MODE_P): New.
	(FUNCTION_VARG_MODE_P): New.
	(CUMULATIVE_ARGS): Add extra regs info.
	(INIT_CUMULATIVE_ARGS): Use csky_init_cumulative_args.
	(FUNCTION_ARG_REGNO_P): Use FUNCTION_VARG_REGNO_P.
	* config/csky/csky-protos.h (csky_init_cumulative_args): Extern.
	* config/csky/csky.c (csky_cpu_cpp_builtins): Support TARGET_HARD_FLOAT_ABI.
	(csky_function_arg): Likewise.
	(csky_num_arg_regs): Likewise.
	(csky_function_arg_advance): Likewise.
	(csky_function_value): Likewise.
	(csky_libcall_value): Likewise.
	(csky_function_value_regno_p): Likewise.
	(csky_arg_partial_bytes): Likewise.
	(csky_setup_incoming_varargs): Likewise.
	(csky_init_cumulative_args): New.

gcc/testsuite/ChangeLog:

	* gcc.dg/builtin-apply2.c : Skip if CSKY.
	* gcc.dg/torture/stackalign/builtin-apply-2.c : Likewise.

---
 gcc/config/csky/csky-protos.h                      |  2 +
 gcc/config/csky/csky.c                             | 96 +++++++++++++++++++---
 gcc/config/csky/csky.h                             | 34 ++++++--
 gcc/config/csky/csky.md                            | 84 +++++++++++++++++++
 gcc/testsuite/gcc.dg/builtin-apply2.c              |  2 +-
 .../gcc.dg/torture/stackalign/builtin-apply-2.c    |  2 +-
 6 files changed, 200 insertions(+), 20 deletions(-)

Comments

Xianmiao Qu Sept. 16, 2020, 3:05 a.m. UTC | #1
It looks good to me, pushed it to trunck.


Thanks,

Cooper

On 9/15/20 4:08 PM, Jojo R wrote:
> gcc/ChangeLog:
>
> 	* config/csky/csky.md (CSKY_NPARM_FREGS): New.
> 	(call_value_internal_vs/d): New.
> 	(untyped_call): New.
> 	* config/csky/csky.h (TARGET_SINGLE_FPU): New.
> 	(TARGET_DOUBLE_FPU): New.
> 	(FUNCTION_VARG_REGNO_P): New.
> 	(CSKY_VREG_MODE_P): New.
> 	(FUNCTION_VARG_MODE_P): New.
> 	(CUMULATIVE_ARGS): Add extra regs info.
> 	(INIT_CUMULATIVE_ARGS): Use csky_init_cumulative_args.
> 	(FUNCTION_ARG_REGNO_P): Use FUNCTION_VARG_REGNO_P.
> 	* config/csky/csky-protos.h (csky_init_cumulative_args): Extern.
> 	* config/csky/csky.c (csky_cpu_cpp_builtins): Support TARGET_HARD_FLOAT_ABI.
> 	(csky_function_arg): Likewise.
> 	(csky_num_arg_regs): Likewise.
> 	(csky_function_arg_advance): Likewise.
> 	(csky_function_value): Likewise.
> 	(csky_libcall_value): Likewise.
> 	(csky_function_value_regno_p): Likewise.
> 	(csky_arg_partial_bytes): Likewise.
> 	(csky_setup_incoming_varargs): Likewise.
> 	(csky_init_cumulative_args): New.
>
> gcc/testsuite/ChangeLog:
>
> 	* gcc.dg/builtin-apply2.c : Skip if CSKY.
> 	* gcc.dg/torture/stackalign/builtin-apply-2.c : Likewise.
>
> ---
>   gcc/config/csky/csky-protos.h                      |  2 +
>   gcc/config/csky/csky.c                             | 96 +++++++++++++++++++---
>   gcc/config/csky/csky.h                             | 34 ++++++--
>   gcc/config/csky/csky.md                            | 84 +++++++++++++++++++
>   gcc/testsuite/gcc.dg/builtin-apply2.c              |  2 +-
>   .../gcc.dg/torture/stackalign/builtin-apply-2.c    |  2 +-
>   6 files changed, 200 insertions(+), 20 deletions(-)
>
> diff --git a/gcc/config/csky/csky-protos.h b/gcc/config/csky/csky-protos.h
> index cc1a033..2c02399 100644
> --- a/gcc/config/csky/csky-protos.h
> +++ b/gcc/config/csky/csky-protos.h
> @@ -68,4 +68,6 @@ extern int csky_compute_pushpop_length (rtx *);
>   
>   extern int csky_default_branch_cost (bool, bool);
>   extern bool csky_default_logical_op_non_short_circuit (void);
> +
> +extern void csky_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
>   #endif /* GCC_CSKY_PROTOS_H */
> diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c
> index 7ba3ed3..8463d8f 100644
> --- a/gcc/config/csky/csky.c
> +++ b/gcc/config/csky/csky.c
> @@ -328,6 +328,16 @@ csky_cpu_cpp_builtins (cpp_reader *pfile)
>       {
>         builtin_define ("__csky_hard_float__");
>         builtin_define ("__CSKY_HARD_FLOAT__");
> +      if (TARGET_HARD_FLOAT_ABI)
> +	{
> +	  builtin_define ("__csky_hard_float_abi__");
> +	  builtin_define ("__CSKY_HARD_FLOAT_ABI__");
> +	}
> +      if (TARGET_SINGLE_FPU)
> +	{
> +	  builtin_define ("__csky_hard_float_fpu_sf__");
> +	  builtin_define ("__CSKY_HARD_FLOAT_FPU_SF__");
> +	}
>       }
>     else
>       {
> @@ -1790,9 +1800,22 @@ static rtx
>   csky_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
>   {
>     CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
> +  int reg = pcum->reg;
> +  machine_mode mode = arg.mode;
>   
> -  if (*pcum < CSKY_NPARM_REGS)
> -    return gen_rtx_REG (arg.mode, CSKY_FIRST_PARM_REGNUM + *pcum);
> +  if (FUNCTION_VARG_MODE_P(mode)
> +      && !pcum->is_stdarg)
> +    {
> +      reg = pcum->freg;
> +
> +      if (reg < CSKY_NPARM_FREGS)
> +	return gen_rtx_REG (mode, CSKY_FIRST_VFP_REGNUM + reg);
> +      else
> +	return NULL_RTX;
> +    }
> +
> +  if (reg < CSKY_NPARM_REGS)
> +    return gen_rtx_REG (mode, CSKY_FIRST_PARM_REGNUM + reg);
>   
>     return NULL_RTX;
>   }
> @@ -1802,7 +1825,7 @@ csky_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
>      MODE and TYPE.  */
>   
>   static int
> -csky_num_arg_regs (machine_mode mode, const_tree type)
> +csky_num_arg_regs (machine_mode mode, const_tree type, bool is_stdarg)
>   {
>     int size;
>   
> @@ -1811,6 +1834,14 @@ csky_num_arg_regs (machine_mode mode, const_tree type)
>     else
>       size = GET_MODE_SIZE (mode);
>   
> +  if (TARGET_HARD_FLOAT_ABI
> +      && !is_stdarg)
> +    {
> +      if (CSKY_VREG_MODE_P(mode)
> +	  && !TARGET_SINGLE_FPU)
> +	return ((CSKY_NUM_WORDS (size) + 1) / 2);
> +    }
> +
>     return CSKY_NUM_WORDS (size);
>   }
>   
> @@ -1822,12 +1853,23 @@ csky_function_arg_advance (cumulative_args_t pcum_v,
>   			   const function_arg_info &arg)
>   {
>     CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
> -  int param_size = csky_num_arg_regs (arg.mode, arg.type);
> +  int *reg = &pcum->reg;
> +  machine_mode mode = arg.mode;
>   
> -  if (*pcum + param_size > CSKY_NPARM_REGS)
> -    *pcum = CSKY_NPARM_REGS;
> +  int param_size = csky_num_arg_regs (mode, arg.type, pcum->is_stdarg);
> +  int param_regs_nums = CSKY_NPARM_REGS;
> +
> +  if (FUNCTION_VARG_MODE_P(mode)
> +      && !pcum->is_stdarg)
> +    {
> +      reg = &pcum->freg;
> +      param_regs_nums = CSKY_NPARM_FREGS;
> +    }
> +
> +  if (*reg + param_size > param_regs_nums)
> +    *reg = param_regs_nums;
>     else
> -    *pcum += param_size;
> +    *reg += param_size;
>   }
>   
>   
> @@ -1843,6 +1885,12 @@ csky_function_value (const_tree type, const_tree func,
>     mode = TYPE_MODE (type);
>     size = int_size_in_bytes (type);
>   
> +  if (FUNCTION_VARG_MODE_P(mode))
> +    {
> +      mode = promote_function_mode (type, mode, &unsignedp, func, 1);
> +      return gen_rtx_REG (mode, CSKY_FIRST_VFP_REGNUM);
> +    }
> +
>     /* Since we promote return types, we must promote the mode here too.  */
>     if (INTEGRAL_TYPE_P (type))
>       {
> @@ -1877,6 +1925,10 @@ static rtx
>   csky_libcall_value (machine_mode mode,
>   		    const_rtx libcall ATTRIBUTE_UNUSED)
>   {
> +  if (FUNCTION_VARG_MODE_P(mode))
> +    {
> +      return gen_rtx_REG (mode, CSKY_FIRST_VFP_REGNUM);
> +    }
>     return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
>   }
>   
> @@ -1887,7 +1939,11 @@ csky_libcall_value (machine_mode mode,
>   static bool
>   csky_function_value_regno_p (const unsigned int regno)
>   {
> -  return (regno == CSKY_FIRST_RET_REGNUM);
> +  if (regno == CSKY_FIRST_RET_REGNUM
> +      || (TARGET_HARD_FLOAT_ABI
> +	  && regno == CSKY_FIRST_VFP_REGNUM))
> +    return true;
> +  return false;
>   }
>   
>   
> @@ -1912,11 +1968,16 @@ static int
>   csky_arg_partial_bytes (cumulative_args_t pcum_v, const function_arg_info &arg)
>   {
>     CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
> -  int param_size = csky_num_arg_regs (arg.mode, arg.type);
> +  int param_size = csky_num_arg_regs (arg.mode, arg.type, pcum->is_stdarg);
> +  int reg = pcum->reg;
> +
> +  if (FUNCTION_VARG_MODE_P(arg.mode)
> +      && !pcum->is_stdarg)
> +    return 0;
>   
> -  if (*pcum < CSKY_NPARM_REGS
> -      && *pcum + param_size > CSKY_NPARM_REGS)
> -    return (CSKY_NPARM_REGS - *pcum) * UNITS_PER_WORD;
> +  if (reg < CSKY_NPARM_REGS
> +      && reg + param_size > CSKY_NPARM_REGS)
> +    return (CSKY_NPARM_REGS - reg) * UNITS_PER_WORD;
>   
>     return 0;
>   }
> @@ -1941,7 +2002,7 @@ csky_setup_incoming_varargs (cumulative_args_t pcum_v,
>     cfun->machine->uses_anonymous_args = 1;
>     local_cum = *pcum;
>     csky_function_arg_advance (local_cum_v, arg);
> -  regs_to_push = CSKY_NPARM_REGS - local_cum;
> +  regs_to_push = CSKY_NPARM_REGS - local_cum.reg;
>     if (regs_to_push)
>       *pretend_size  = regs_to_push * UNITS_PER_WORD;
>   }
> @@ -6775,6 +6836,15 @@ csky_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
>     return true;
>   }
>   
> +void
> +csky_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
> +			   rtx libname ATTRIBUTE_UNUSED,
> +			   tree fndecl ATTRIBUTE_UNUSED)
> +{
> +  memset(pcum, 0, sizeof(*pcum));
> +  if (stdarg_p (fntype))
> +    pcum->is_stdarg = true;
> +}
>   
>   struct gcc_target targetm = TARGET_INITIALIZER;
>   
> diff --git a/gcc/config/csky/csky.h b/gcc/config/csky/csky.h
> index 8f4090b..190a668 100644
> --- a/gcc/config/csky/csky.h
> +++ b/gcc/config/csky/csky.h
> @@ -133,6 +133,22 @@
>   /* Use hardware floating point calling convention.  */
>   #define TARGET_HARD_FLOAT_ABI   (csky_float_abi == CSKY_FLOAT_ABI_HARD)
>   
> +#define TARGET_SINGLE_FPU     (csky_fpu_index == TARGET_FPU_fpv2_sf)
> +#define TARGET_DOUBLE_FPU     (TARGET_HARD_FLOAT && !TARGET_SINGLE_FPU)
> +
> +#define FUNCTION_VARG_REGNO_P(REGNO)      \
> +  (TARGET_HARD_FLOAT_ABI                  \
> +   && IN_RANGE ((REGNO), CSKY_FIRST_VFP_REGNUM, \
> +		CSKY_FIRST_VFP_REGNUM + CSKY_NPARM_FREGS - 1))
> +
> +#define CSKY_VREG_MODE_P(mode) \
> +  ((mode) == SFmode || (mode) == DFmode)
> +
> +#define FUNCTION_VARG_MODE_P(mode)  \
> +  (TARGET_HARD_FLOAT_ABI            \
> +   && CSKY_VREG_MODE_P(mode)        \
> +   && !(mode == DFmode && TARGET_SINGLE_FPU))
> +
>   /* Number of loads/stores handled by ldm/stm.  */
>   #define CSKY_MIN_MULTIPLE_STLD	3
>   #define CSKY_MAX_MULTIPLE_STLD	12
> @@ -360,7 +376,14 @@ extern int csky_arch_isa_features[];
>   
>   /* A C type for declaring a variable that is used as the first argument of
>      TARGET_ FUNCTION_ARG and other related values.  */
> -#define CUMULATIVE_ARGS	 int
> +#if !defined (USED_FOR_TARGET)
> +typedef struct
> +{
> +  int reg;
> +  int freg;
> +  bool is_stdarg;
> +} CUMULATIVE_ARGS;
> +#endif
>   
>   /* Initialize a variable CUM of type CUMULATIVE_ARGS
>      for a call to a function whose data type is FNTYPE.
> @@ -369,15 +392,16 @@ extern int csky_arch_isa_features[];
>      On CSKY, the offset always starts at 0: the first parm reg is always
>      the same reg.  */
>   #define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
> -  ((CUM) = 0)
> +  csky_init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME), (INDIRECT))
>   
>   /* True if N is a possible register number for function argument passing.
>      On the CSKY, r0-r3 are used to pass args.
>      The int cast is to prevent a complaint about unsigned comparison to
>      zero, since CSKY_FIRST_PARM_REGNUM is zero.  */
> -#define FUNCTION_ARG_REGNO_P(REGNO)	    \
> -  (((int)(REGNO) >= CSKY_FIRST_PARM_REGNUM) &&		\
> -   ((REGNO) < (CSKY_NPARM_REGS + CSKY_FIRST_PARM_REGNUM)))
> +#define FUNCTION_ARG_REGNO_P(REGNO)                          \
> +  (((REGNO) >= CSKY_FIRST_PARM_REGNUM                        \
> +    && (REGNO) < (CSKY_NPARM_REGS + CSKY_FIRST_PARM_REGNUM)) \
> +   || FUNCTION_VARG_REGNO_P(REGNO))
>   
>   /* How Large Values Are Returned  */
>   
> diff --git a/gcc/config/csky/csky.md b/gcc/config/csky/csky.md
> index 15f68f9..7f01fbc 100644
> --- a/gcc/config/csky/csky.md
> +++ b/gcc/config/csky/csky.md
> @@ -50,6 +50,7 @@
>      (CSKY_LAST_EH_RETDATA_REGNUM		1)
>      (CSKY_EH_STACKADJ_REGNUM		2)
>      (CSKY_STACKADJUST_REGNUM		4)
> +   (CSKY_NPARM_FREGS 4)
>   ])
>   
>   ;; Supported TLS relocations.
> @@ -100,6 +101,7 @@
>   
>      ; Support for the eh_return pattern.
>      VUNSPEC_EH_RETURN
> +   VUNSPEC_BLOCKAGE
>     ])
>   
>   
> @@ -3310,6 +3312,88 @@
>   				 force_reg (Pmode, XEXP (operands[1], 0)));
>     }")
>   
> +;; Call subroutine returning any type.
> +
> +(define_expand "untyped_call"
> +  [(parallel [(call (match_operand 0 "" "")
> +        (const_int 0))
> +        (match_operand 1 "" "")
> +        (match_operand 2 "" "")])]
> +  ""
> +{
> +  int i;
> +
> +  emit_call_insn (gen_call (operands[0], const0_rtx));
> +
> +  for (i = 0; i < XVECLEN (operands[2], 0); i++)
> +    {
> +      rtx set = XVECEXP (operands[2], 0, i);
> +      emit_move_insn (SET_DEST (set), SET_SRC (set));
> +    }
> +
> +  /* The optimizer does not know that the call sets the function value
> +     registers we stored in the result block.  We avoid problems by
> +     claiming that all hard registers are used and clobbered at this
> +     point.  */
> +  emit_insn (gen_blockage ());
> +
> +  DONE;
> +})
> +
> +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
> +;; all of memory.  This blocks insns from being moved across this point.
> +
> +(define_insn "blockage"
> +  [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)]
> +  ""
> +  ""
> +  [(set_attr "length" "0")])
> +
> +(define_insn "*call_value_internal_vs"
> +  [(set (match_operand:SF               0 "register_operand"          "=v,v,v")
> +        (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b, r,S"))
> +              (match_operand 2 "" "")))
> +   (clobber (reg:SI CSKY_LR_REGNUM))]
> +  "TARGET_HARD_FLOAT_ABI"
> +  "@
> +    jsr\t%1
> +    jsr\t%1
> +    jbsr\t%1"
> +  [(set_attr "length" "2,4,4")
> +   (set_attr "type"   "call_jsr,call_jsr,call")]
> +)
> +
> +(define_insn "*call_value_internal_vd"
> +  [(set (match_operand:DF               0 "register_operand"          "=v,v,v")
> +        (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b, r,S"))
> +              (match_operand 2 "" "")))
> +   (clobber (reg:SI CSKY_LR_REGNUM))]
> +  "TARGET_HARD_FLOAT_ABI && TARGET_DOUBLE_FPU"
> +  "@
> +    jsr\t%1
> +    jsr\t%1
> +    jbsr\t%1"
> +  [(set_attr "length" "2,4,4")
> +   (set_attr "type"   "call_jsr,call_jsr,call")]
> +)
> +
> +(define_insn "*call_value_internal_pic_vs"
> +  [(set (match_operand:SF               0 "register_operand"    "=v")
> +        (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
> +                      (match_operand    2 "" "")))
> +   (clobber (reg:SI CSKY_LR_REGNUM))]
> +  "flag_pic && TARGET_HARD_FLOAT_ABI"
> +  "* return csky_output_call (operands, 1);"
> +)
> +
> +(define_insn "*call_value_internal_pic_vd"
> +  [(set (match_operand:DF               0 "register_operand"    "=v")
> +        (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
> +                      (match_operand    2 "" "")))
> +   (clobber (reg:SI CSKY_LR_REGNUM))]
> +  "flag_pic && TARGET_HARD_FLOAT_ABI && TARGET_DOUBLE_FPU"
> +  "* return csky_output_call (operands, 1);"
> +)
>   
>   (define_insn "*call_value_internal"
>     [(set (match_operand			0 "register_operand"	      "=r,r,r")
> diff --git a/gcc/testsuite/gcc.dg/builtin-apply2.c b/gcc/testsuite/gcc.dg/builtin-apply2.c
> index 06ef24e..9049af5 100644
> --- a/gcc/testsuite/gcc.dg/builtin-apply2.c
> +++ b/gcc/testsuite/gcc.dg/builtin-apply2.c
> @@ -1,7 +1,7 @@
>   /* { dg-do run } */
>   /* { dg-require-effective-target untyped_assembly } */
>   /* { dg-skip-if "Variadic funcs have all args on stack. Normal funcs have args in registers." { "avr-*-* nds32*-*-* amdgcn-*-*" } } */
> -/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs." { "riscv*-*-* or1k*-*-* msp430-*-* pru-*-*" } } */
> +/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs." { "csky*-*-* riscv*-*-* or1k*-*-* msp430-*-* pru-*-*" } } */
>   /* { dg-skip-if "Variadic funcs use Base AAPCS.  Normal funcs use VFP variant." { arm*-*-* && arm_hf_eabi } } */
>   
>   /* PR target/12503 */
> diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
> index 31585a0..5ec0558 100644
> --- a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
> +++ b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
> @@ -9,7 +9,7 @@
>   /* arm_hf_eabi: Variadic funcs use Base AAPCS.  Normal funcs use VFP variant.
>      avr: Variadic funcs don't pass arguments in registers, while normal funcs
>           do.  */
> -/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs" { arm_hf_eabi || { avr-*-* riscv*-*-* or1k*-*-* msp430-*-* amdgcn-*-* pru-*-* } } } */
> +/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs" { arm_hf_eabi || { csky*-*-* avr-*-* riscv*-*-* or1k*-*-* msp430-*-* amdgcn-*-* pru-*-* } } } */
>   /* { dg-skip-if "Variadic funcs have all args on stack. Normal funcs have args in registers." { nds32*-*-* } { v850*-*-* } } */
>   /* { dg-require-effective-target untyped_assembly } */
>
diff mbox series

Patch

diff --git a/gcc/config/csky/csky-protos.h b/gcc/config/csky/csky-protos.h
index cc1a033..2c02399 100644
--- a/gcc/config/csky/csky-protos.h
+++ b/gcc/config/csky/csky-protos.h
@@ -68,4 +68,6 @@  extern int csky_compute_pushpop_length (rtx *);
 
 extern int csky_default_branch_cost (bool, bool);
 extern bool csky_default_logical_op_non_short_circuit (void);
+
+extern void csky_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
 #endif /* GCC_CSKY_PROTOS_H */
diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c
index 7ba3ed3..8463d8f 100644
--- a/gcc/config/csky/csky.c
+++ b/gcc/config/csky/csky.c
@@ -328,6 +328,16 @@  csky_cpu_cpp_builtins (cpp_reader *pfile)
     {
       builtin_define ("__csky_hard_float__");
       builtin_define ("__CSKY_HARD_FLOAT__");
+      if (TARGET_HARD_FLOAT_ABI)
+	{
+	  builtin_define ("__csky_hard_float_abi__");
+	  builtin_define ("__CSKY_HARD_FLOAT_ABI__");
+	}
+      if (TARGET_SINGLE_FPU)
+	{
+	  builtin_define ("__csky_hard_float_fpu_sf__");
+	  builtin_define ("__CSKY_HARD_FLOAT_FPU_SF__");
+	}
     }
   else
     {
@@ -1790,9 +1800,22 @@  static rtx
 csky_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
+  int reg = pcum->reg;
+  machine_mode mode = arg.mode;
 
-  if (*pcum < CSKY_NPARM_REGS)
-    return gen_rtx_REG (arg.mode, CSKY_FIRST_PARM_REGNUM + *pcum);
+  if (FUNCTION_VARG_MODE_P(mode)
+      && !pcum->is_stdarg)
+    {
+      reg = pcum->freg;
+
+      if (reg < CSKY_NPARM_FREGS)
+	return gen_rtx_REG (mode, CSKY_FIRST_VFP_REGNUM + reg);
+      else
+	return NULL_RTX;
+    }
+
+  if (reg < CSKY_NPARM_REGS)
+    return gen_rtx_REG (mode, CSKY_FIRST_PARM_REGNUM + reg);
 
   return NULL_RTX;
 }
@@ -1802,7 +1825,7 @@  csky_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
    MODE and TYPE.  */
 
 static int
-csky_num_arg_regs (machine_mode mode, const_tree type)
+csky_num_arg_regs (machine_mode mode, const_tree type, bool is_stdarg)
 {
   int size;
 
@@ -1811,6 +1834,14 @@  csky_num_arg_regs (machine_mode mode, const_tree type)
   else
     size = GET_MODE_SIZE (mode);
 
+  if (TARGET_HARD_FLOAT_ABI
+      && !is_stdarg)
+    {
+      if (CSKY_VREG_MODE_P(mode)
+	  && !TARGET_SINGLE_FPU)
+	return ((CSKY_NUM_WORDS (size) + 1) / 2);
+    }
+
   return CSKY_NUM_WORDS (size);
 }
 
@@ -1822,12 +1853,23 @@  csky_function_arg_advance (cumulative_args_t pcum_v,
 			   const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
-  int param_size = csky_num_arg_regs (arg.mode, arg.type);
+  int *reg = &pcum->reg;
+  machine_mode mode = arg.mode;
 
-  if (*pcum + param_size > CSKY_NPARM_REGS)
-    *pcum = CSKY_NPARM_REGS;
+  int param_size = csky_num_arg_regs (mode, arg.type, pcum->is_stdarg);
+  int param_regs_nums = CSKY_NPARM_REGS;
+
+  if (FUNCTION_VARG_MODE_P(mode)
+      && !pcum->is_stdarg)
+    {
+      reg = &pcum->freg;
+      param_regs_nums = CSKY_NPARM_FREGS;
+    }
+
+  if (*reg + param_size > param_regs_nums)
+    *reg = param_regs_nums;
   else
-    *pcum += param_size;
+    *reg += param_size;
 }
 
 
@@ -1843,6 +1885,12 @@  csky_function_value (const_tree type, const_tree func,
   mode = TYPE_MODE (type);
   size = int_size_in_bytes (type);
 
+  if (FUNCTION_VARG_MODE_P(mode))
+    {
+      mode = promote_function_mode (type, mode, &unsignedp, func, 1);
+      return gen_rtx_REG (mode, CSKY_FIRST_VFP_REGNUM);
+    }
+
   /* Since we promote return types, we must promote the mode here too.  */
   if (INTEGRAL_TYPE_P (type))
     {
@@ -1877,6 +1925,10 @@  static rtx
 csky_libcall_value (machine_mode mode,
 		    const_rtx libcall ATTRIBUTE_UNUSED)
 {
+  if (FUNCTION_VARG_MODE_P(mode))
+    {
+      return gen_rtx_REG (mode, CSKY_FIRST_VFP_REGNUM);
+    }
   return gen_rtx_REG (mode, CSKY_FIRST_RET_REGNUM);
 }
 
@@ -1887,7 +1939,11 @@  csky_libcall_value (machine_mode mode,
 static bool
 csky_function_value_regno_p (const unsigned int regno)
 {
-  return (regno == CSKY_FIRST_RET_REGNUM);
+  if (regno == CSKY_FIRST_RET_REGNUM
+      || (TARGET_HARD_FLOAT_ABI
+	  && regno == CSKY_FIRST_VFP_REGNUM))
+    return true;
+  return false;
 }
 
 
@@ -1912,11 +1968,16 @@  static int
 csky_arg_partial_bytes (cumulative_args_t pcum_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v);
-  int param_size = csky_num_arg_regs (arg.mode, arg.type);
+  int param_size = csky_num_arg_regs (arg.mode, arg.type, pcum->is_stdarg);
+  int reg = pcum->reg;
+
+  if (FUNCTION_VARG_MODE_P(arg.mode)
+      && !pcum->is_stdarg)
+    return 0;
 
-  if (*pcum < CSKY_NPARM_REGS
-      && *pcum + param_size > CSKY_NPARM_REGS)
-    return (CSKY_NPARM_REGS - *pcum) * UNITS_PER_WORD;
+  if (reg < CSKY_NPARM_REGS
+      && reg + param_size > CSKY_NPARM_REGS)
+    return (CSKY_NPARM_REGS - reg) * UNITS_PER_WORD;
 
   return 0;
 }
@@ -1941,7 +2002,7 @@  csky_setup_incoming_varargs (cumulative_args_t pcum_v,
   cfun->machine->uses_anonymous_args = 1;
   local_cum = *pcum;
   csky_function_arg_advance (local_cum_v, arg);
-  regs_to_push = CSKY_NPARM_REGS - local_cum;
+  regs_to_push = CSKY_NPARM_REGS - local_cum.reg;
   if (regs_to_push)
     *pretend_size  = regs_to_push * UNITS_PER_WORD;
 }
@@ -6775,6 +6836,15 @@  csky_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
   return true;
 }
 
+void
+csky_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
+			   rtx libname ATTRIBUTE_UNUSED,
+			   tree fndecl ATTRIBUTE_UNUSED)
+{
+  memset(pcum, 0, sizeof(*pcum));
+  if (stdarg_p (fntype))
+    pcum->is_stdarg = true;
+}
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
diff --git a/gcc/config/csky/csky.h b/gcc/config/csky/csky.h
index 8f4090b..190a668 100644
--- a/gcc/config/csky/csky.h
+++ b/gcc/config/csky/csky.h
@@ -133,6 +133,22 @@ 
 /* Use hardware floating point calling convention.  */
 #define TARGET_HARD_FLOAT_ABI   (csky_float_abi == CSKY_FLOAT_ABI_HARD)
 
+#define TARGET_SINGLE_FPU     (csky_fpu_index == TARGET_FPU_fpv2_sf)
+#define TARGET_DOUBLE_FPU     (TARGET_HARD_FLOAT && !TARGET_SINGLE_FPU)
+
+#define FUNCTION_VARG_REGNO_P(REGNO)      \
+  (TARGET_HARD_FLOAT_ABI                  \
+   && IN_RANGE ((REGNO), CSKY_FIRST_VFP_REGNUM, \
+		CSKY_FIRST_VFP_REGNUM + CSKY_NPARM_FREGS - 1))
+
+#define CSKY_VREG_MODE_P(mode) \
+  ((mode) == SFmode || (mode) == DFmode)
+
+#define FUNCTION_VARG_MODE_P(mode)  \
+  (TARGET_HARD_FLOAT_ABI            \
+   && CSKY_VREG_MODE_P(mode)        \
+   && !(mode == DFmode && TARGET_SINGLE_FPU))
+
 /* Number of loads/stores handled by ldm/stm.  */
 #define CSKY_MIN_MULTIPLE_STLD	3
 #define CSKY_MAX_MULTIPLE_STLD	12
@@ -360,7 +376,14 @@  extern int csky_arch_isa_features[];
 
 /* A C type for declaring a variable that is used as the first argument of
    TARGET_ FUNCTION_ARG and other related values.  */
-#define CUMULATIVE_ARGS	 int
+#if !defined (USED_FOR_TARGET)
+typedef struct
+{
+  int reg;
+  int freg;
+  bool is_stdarg;
+} CUMULATIVE_ARGS;
+#endif
 
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
@@ -369,15 +392,16 @@  extern int csky_arch_isa_features[];
    On CSKY, the offset always starts at 0: the first parm reg is always
    the same reg.  */
 #define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
-  ((CUM) = 0)
+  csky_init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME), (INDIRECT))
 
 /* True if N is a possible register number for function argument passing.
    On the CSKY, r0-r3 are used to pass args.
    The int cast is to prevent a complaint about unsigned comparison to
    zero, since CSKY_FIRST_PARM_REGNUM is zero.  */
-#define FUNCTION_ARG_REGNO_P(REGNO)	    \
-  (((int)(REGNO) >= CSKY_FIRST_PARM_REGNUM) &&		\
-   ((REGNO) < (CSKY_NPARM_REGS + CSKY_FIRST_PARM_REGNUM)))
+#define FUNCTION_ARG_REGNO_P(REGNO)                          \
+  (((REGNO) >= CSKY_FIRST_PARM_REGNUM                        \
+    && (REGNO) < (CSKY_NPARM_REGS + CSKY_FIRST_PARM_REGNUM)) \
+   || FUNCTION_VARG_REGNO_P(REGNO))
 
 /* How Large Values Are Returned  */
 
diff --git a/gcc/config/csky/csky.md b/gcc/config/csky/csky.md
index 15f68f9..7f01fbc 100644
--- a/gcc/config/csky/csky.md
+++ b/gcc/config/csky/csky.md
@@ -50,6 +50,7 @@ 
    (CSKY_LAST_EH_RETDATA_REGNUM		1)
    (CSKY_EH_STACKADJ_REGNUM		2)
    (CSKY_STACKADJUST_REGNUM		4)
+   (CSKY_NPARM_FREGS 4)
 ])
 
 ;; Supported TLS relocations.
@@ -100,6 +101,7 @@ 
 
    ; Support for the eh_return pattern.
    VUNSPEC_EH_RETURN
+   VUNSPEC_BLOCKAGE
   ])
 
 
@@ -3310,6 +3312,88 @@ 
 				 force_reg (Pmode, XEXP (operands[1], 0)));
   }")
 
+;; Call subroutine returning any type.
+
+(define_expand "untyped_call"
+  [(parallel [(call (match_operand 0 "" "")
+        (const_int 0))
+        (match_operand 1 "" "")
+        (match_operand 2 "" "")])]
+  ""
+{
+  int i;
+
+  emit_call_insn (gen_call (operands[0], const0_rtx));
+
+  for (i = 0; i < XVECLEN (operands[2], 0); i++)
+    {
+      rtx set = XVECEXP (operands[2], 0, i);
+      emit_move_insn (SET_DEST (set), SET_SRC (set));
+    }
+
+  /* The optimizer does not know that the call sets the function value
+     registers we stored in the result block.  We avoid problems by
+     claiming that all hard registers are used and clobbered at this
+     point.  */
+  emit_insn (gen_blockage ());
+
+  DONE;
+})
+
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory.  This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+  [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)]
+  ""
+  ""
+  [(set_attr "length" "0")])
+
+(define_insn "*call_value_internal_vs"
+  [(set (match_operand:SF               0 "register_operand"          "=v,v,v")
+        (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b, r,S"))
+              (match_operand 2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  "TARGET_HARD_FLOAT_ABI"
+  "@
+    jsr\t%1
+    jsr\t%1
+    jbsr\t%1"
+  [(set_attr "length" "2,4,4")
+   (set_attr "type"   "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_value_internal_vd"
+  [(set (match_operand:DF               0 "register_operand"          "=v,v,v")
+        (call (mem:SI (match_operand:SI 1 "csky_call_address_operand" "b, r,S"))
+              (match_operand 2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  "TARGET_HARD_FLOAT_ABI && TARGET_DOUBLE_FPU"
+  "@
+    jsr\t%1
+    jsr\t%1
+    jbsr\t%1"
+  [(set_attr "length" "2,4,4")
+   (set_attr "type"   "call_jsr,call_jsr,call")]
+)
+
+(define_insn "*call_value_internal_pic_vs"
+  [(set (match_operand:SF               0 "register_operand"    "=v")
+        (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
+                      (match_operand    2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  "flag_pic && TARGET_HARD_FLOAT_ABI"
+  "* return csky_output_call (operands, 1);"
+)
+
+(define_insn "*call_value_internal_pic_vd"
+  [(set (match_operand:DF               0 "register_operand"    "=v")
+        (call (mem:SI (match_operand:SI 1 "csky_unspec_operand" "X"))
+                      (match_operand    2 "" "")))
+   (clobber (reg:SI CSKY_LR_REGNUM))]
+  "flag_pic && TARGET_HARD_FLOAT_ABI && TARGET_DOUBLE_FPU"
+  "* return csky_output_call (operands, 1);"
+)
 
 (define_insn "*call_value_internal"
   [(set (match_operand			0 "register_operand"	      "=r,r,r")
diff --git a/gcc/testsuite/gcc.dg/builtin-apply2.c b/gcc/testsuite/gcc.dg/builtin-apply2.c
index 06ef24e..9049af5 100644
--- a/gcc/testsuite/gcc.dg/builtin-apply2.c
+++ b/gcc/testsuite/gcc.dg/builtin-apply2.c
@@ -1,7 +1,7 @@ 
 /* { dg-do run } */
 /* { dg-require-effective-target untyped_assembly } */
 /* { dg-skip-if "Variadic funcs have all args on stack. Normal funcs have args in registers." { "avr-*-* nds32*-*-* amdgcn-*-*" } } */
-/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs." { "riscv*-*-* or1k*-*-* msp430-*-* pru-*-*" } } */
+/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs." { "csky*-*-* riscv*-*-* or1k*-*-* msp430-*-* pru-*-*" } } */
 /* { dg-skip-if "Variadic funcs use Base AAPCS.  Normal funcs use VFP variant." { arm*-*-* && arm_hf_eabi } } */
 
 /* PR target/12503 */
diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
index 31585a0..5ec0558 100644
--- a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
+++ b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
@@ -9,7 +9,7 @@ 
 /* arm_hf_eabi: Variadic funcs use Base AAPCS.  Normal funcs use VFP variant.
    avr: Variadic funcs don't pass arguments in registers, while normal funcs
         do.  */
-/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs" { arm_hf_eabi || { avr-*-* riscv*-*-* or1k*-*-* msp430-*-* amdgcn-*-* pru-*-* } } } */
+/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs" { arm_hf_eabi || { csky*-*-* avr-*-* riscv*-*-* or1k*-*-* msp430-*-* amdgcn-*-* pru-*-* } } } */
 /* { dg-skip-if "Variadic funcs have all args on stack. Normal funcs have args in registers." { nds32*-*-* } { v850*-*-* } } */
 /* { dg-require-effective-target untyped_assembly } */