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 } */ -- 1.9.1