diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e57cc99779b..b5a198c95dc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,58 @@ +2019-08-20 Richard Sandiford + + * target.def (must_pass_in_stack): Take a function_arg_info instead + of a mode and a type. + * doc/tm.texi: Regenerate. + * calls.h (must_pass_in_stack_var_size): Take a function_arg_info + instead of a mode and a type. + (must_pass_in_stack_var_size_or_pad): Likewise. + * calls.c (must_pass_in_stack_var_size): Likewise. + (must_pass_in_stack_var_size_or_pad): Likewise. + (initialize_argument_information): Update call to + targetm.calls.must_pass_in_stack. + (must_pass_va_arg_on_stack): Likewise. + * function.c (assign_parm_find_entry_rtl): Likewise. + * targhooks.c (hook_pass_by_reference_must_pass_in_stack): Likewise. + * config/alpha/alpha.c (alpha_function_arg): Likewise. + (alpha_function_arg_advance): Likewise. + * config/cr16/cr16.c (cr16_function_arg): Likewise. + (cr16_function_arg_advance): Likewise. + * config/cris/cris.c (cris_pass_by_reference): Likewise. + (cris_arg_partial_bytes): Likewise. + * config/iq2000/iq2000.c (iq2000_pass_by_reference): Likewise. + * config/lm32/lm32.c (lm32_function_arg): Likewise. + * config/mcore/mcore.c (mcore_num_arg_regs): Likewise. + (mcore_function_arg, mcore_arg_partial_bytes): Likewise. + * config/mips/mips.c (mips_pass_by_reference): Likewise. + * config/mmix/mmix.c (mmix_function_arg_advance): Likewise. + (mmix_function_arg_1, mmix_pass_by_reference): Likewise. + * config/sh/sh.c (sh_pass_by_reference): Likewise. + * config/stormy16/stormy16.c (xstormy16_function_arg): Likewise. + * config/xtensa/xtensa.c (xtensa_function_arg_advance): Likewise. + * config/arm/arm.c (arm_must_pass_in_stack): Take a function_arg_info + instead of a mode and a type. + * config/fr30/fr30.c (fr30_must_pass_in_stack): Likewise. + (fr30_num_arg_regs): Likewise. + (fr30_setup_incoming_varargs): Update calls accordingly. + (fr30_arg_partial_bytes, fr30_function_arg): Likewise. + (fr30_function_arg_advance): Likewise. + * config/frv/frv.c (frv_must_pass_in_stack): Take a function_arg_info + instead of a mode and a type. + * config/gcn/gcn.c (num_arg_regs): Likewise. + (gcn_function_arg, gcn_function_arg_advance): Update calls to + num_arg_regs and targetm.calls.must_pass_in_stack. + (gcn_arg_partial_bytes): Likewise. + * config/i386/i386.c (ix86_must_pass_in_stack): Take a + function_arg_info instead of a mode and a type. + (classify_argument): Update call accordingly. + * config/nds32/nds32.c (nds32_must_pass_in_stack): Take a + function_arg_info instead of a mode and a type. + * config/rs6000/rs6000-internal.h (rs6000_must_pass_in_stack): + Likewise. + * config/rs6000/rs6000-call.c (rs6000_must_pass_in_stack): Likewise. + (rs6000_parm_needs_stack): Update call accordingly. + (setup_incoming_varargs): Likewise. + 2019-08-20 Richard Sandiford * target.def (callee_copies): Take a function_arg_info instead diff --git a/gcc/calls.c b/gcc/calls.c index 6be8acd38e3..1f691e84dfe 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2139,7 +2139,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, if (args[i].reg) args[i].partial = targetm.calls.arg_partial_bytes (args_so_far, arg); - args[i].pass_on_stack = targetm.calls.must_pass_in_stack (mode, type); + args[i].pass_on_stack = targetm.calls.must_pass_in_stack (arg); /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]), it means that we are to pass this arg in the register(s) designated @@ -5839,22 +5839,21 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, return sibcall_failure; } -/* Nonzero if we do not know how to pass TYPE solely in registers. */ +/* Nonzero if we do not know how to pass ARG solely in registers. */ bool -must_pass_in_stack_var_size (machine_mode mode ATTRIBUTE_UNUSED, - const_tree type) +must_pass_in_stack_var_size (const function_arg_info &arg) { - if (!type) + if (!arg.type) return false; /* If the type has variable size... */ - if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + if (TREE_CODE (TYPE_SIZE (arg.type)) != INTEGER_CST) return true; /* If the type is marked as addressable (it is required to be constructed into the stack)... */ - if (TREE_ADDRESSABLE (type)) + if (TREE_ADDRESSABLE (arg.type)) return true; return false; @@ -5865,28 +5864,28 @@ must_pass_in_stack_var_size (machine_mode mode ATTRIBUTE_UNUSED, /* ??? Should be able to merge these two by examining BLOCK_REG_PADDING. */ bool -must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type) +must_pass_in_stack_var_size_or_pad (const function_arg_info &arg) { - if (!type) + if (!arg.type) return false; /* If the type has variable size... */ - if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + if (TREE_CODE (TYPE_SIZE (arg.type)) != INTEGER_CST) return true; /* If the type is marked as addressable (it is required to be constructed into the stack)... */ - if (TREE_ADDRESSABLE (type)) + if (TREE_ADDRESSABLE (arg.type)) return true; - if (TYPE_EMPTY_P (type)) + if (TYPE_EMPTY_P (arg.type)) return false; /* If the padding and mode of the type is such that a copy into a register would put it into the wrong part of the register. */ - if (mode == BLKmode - && int_size_in_bytes (type) % (PARM_BOUNDARY / BITS_PER_UNIT) - && (targetm.calls.function_arg_padding (mode, type) + if (arg.mode == BLKmode + && int_size_in_bytes (arg.type) % (PARM_BOUNDARY / BITS_PER_UNIT) + && (targetm.calls.function_arg_padding (arg.mode, arg.type) == (BYTES_BIG_ENDIAN ? PAD_UPWARD : PAD_DOWNWARD))) return true; @@ -5899,7 +5898,8 @@ must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type) bool must_pass_va_arg_in_stack (tree type) { - return targetm.calls.must_pass_in_stack (TYPE_MODE (type), type); + function_arg_info arg (type, /*named=*/false); + return targetm.calls.must_pass_in_stack (arg); } /* Tell the garbage collector about GTY markers in this source file. */ diff --git a/gcc/calls.h b/gcc/calls.h index 709a0769b76..5e8c576424a 100644 --- a/gcc/calls.h +++ b/gcc/calls.h @@ -108,8 +108,8 @@ extern int setjmp_call_p (const_tree); extern bool gimple_maybe_alloca_call_p (const gimple *); extern bool gimple_alloca_call_p (const gimple *); extern bool alloca_call_p (const_tree); -extern bool must_pass_in_stack_var_size (machine_mode, const_tree); -extern bool must_pass_in_stack_var_size_or_pad (machine_mode, const_tree); +extern bool must_pass_in_stack_var_size (const function_arg_info &); +extern bool must_pass_in_stack_var_size_or_pad (const function_arg_info &); extern bool must_pass_va_arg_in_stack (tree); extern rtx prepare_call_address (tree, rtx, rtx, rtx *, int, int); extern bool shift_return_value (machine_mode, bool, rtx); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 477c24e2298..fd6b5a82274 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -5585,7 +5585,7 @@ alpha_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) num_args = cum->num_args; if (num_args >= 6 - || targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + || targetm.calls.must_pass_in_stack (arg)) return NULL_RTX; } #elif TARGET_ABI_OSF @@ -5596,7 +5596,7 @@ alpha_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) if (arg.end_marker_p ()) basereg = 16; - else if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + else if (targetm.calls.must_pass_in_stack (arg)) return NULL_RTX; } #else @@ -5613,7 +5613,7 @@ alpha_function_arg_advance (cumulative_args_t cum_v, const function_arg_info &arg) { CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); - bool onstack = targetm.calls.must_pass_in_stack (arg.mode, arg.type); + bool onstack = targetm.calls.must_pass_in_stack (arg); int increment = onstack ? 6 : ALPHA_ARG_SIZE (arg.mode, arg.type); #if TARGET_ABI_OSF diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 74e7c54524e..3343a7e4639 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -219,7 +219,7 @@ static bool arm_promote_prototypes (const_tree); static bool arm_default_short_enums (void); static bool arm_align_anon_bitfield (void); static bool arm_return_in_msb (const_tree); -static bool arm_must_pass_in_stack (machine_mode, const_tree); +static bool arm_must_pass_in_stack (const function_arg_info &); static bool arm_return_in_memory (const_tree, const_tree); #if ARM_UNWIND_INFO static void arm_unwind_emit (FILE *, rtx_insn *); @@ -15382,12 +15382,12 @@ arm_reload_out_hi (rtx *operands) (padded to the size of a word) should be passed in a register. */ static bool -arm_must_pass_in_stack (machine_mode mode, const_tree type) +arm_must_pass_in_stack (const function_arg_info &arg) { if (TARGET_AAPCS_BASED) - return must_pass_in_stack_var_size (mode, type); + return must_pass_in_stack_var_size (arg); else - return must_pass_in_stack_var_size_or_pad (mode, type); + return must_pass_in_stack_var_size_or_pad (arg); } diff --git a/gcc/config/cr16/cr16.c b/gcc/config/cr16/cr16.c index dc4cb918482..c95d5d19a9c 100644 --- a/gcc/config/cr16/cr16.c +++ b/gcc/config/cr16/cr16.c @@ -606,7 +606,7 @@ cr16_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) if (arg.end_marker_p ()) return NULL_RTX; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type) || (cum->ints < 0)) + if (targetm.calls.must_pass_in_stack (arg) || (cum->ints < 0)) return NULL_RTX; if (arg.mode == BLKmode) @@ -672,7 +672,7 @@ cr16_function_arg_advance (cumulative_args_t cum_v, if (!cum->last_parm_in_reg) return; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type) || (cum->ints < 0)) + if (targetm.calls.must_pass_in_stack (arg) || (cum->ints < 0)) return; if ((arg.mode == SImode) || (arg.mode == HImode) diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c index f238853ba3a..fff641e9f84 100644 --- a/gcc/config/cris/cris.c +++ b/gcc/config/cris/cris.c @@ -4046,7 +4046,7 @@ cris_setup_incoming_varargs (cumulative_args_t ca_v, static bool cris_pass_by_reference (cumulative_args_t, const function_arg_info &arg) { - return (targetm.calls.must_pass_in_stack (arg.mode, arg.type) + return (targetm.calls.must_pass_in_stack (arg) || CRIS_FUNCTION_ARG_SIZE (arg.mode, arg.type) > 8); } @@ -4111,7 +4111,7 @@ static int cris_arg_partial_bytes (cumulative_args_t ca, const function_arg_info &arg) { if (get_cumulative_args (ca)->regs == CRIS_MAX_ARGS_IN_REGS - 1 - && !targetm.calls.must_pass_in_stack (arg.mode, arg.type) + && !targetm.calls.must_pass_in_stack (arg) && CRIS_FUNCTION_ARG_SIZE (arg.mode, arg.type) > 4 && CRIS_FUNCTION_ARG_SIZE (arg.mode, arg.type) <= 8) return UNITS_PER_WORD; diff --git a/gcc/config/fr30/fr30.c b/gcc/config/fr30/fr30.c index 7f1eae17d00..675198fe5de 100644 --- a/gcc/config/fr30/fr30.c +++ b/gcc/config/fr30/fr30.c @@ -116,7 +116,7 @@ static struct fr30_frame_info zero_frame_info; static void fr30_setup_incoming_varargs (cumulative_args_t, const function_arg_info &, int *, int); -static bool fr30_must_pass_in_stack (machine_mode, const_tree); +static bool fr30_must_pass_in_stack (const function_arg_info &); static int fr30_arg_partial_bytes (cumulative_args_t, const function_arg_info &); static rtx fr30_function_arg (cumulative_args_t, const function_arg_info &); @@ -129,7 +129,7 @@ static bool fr30_function_value_regno_p (const unsigned int); static bool fr30_can_eliminate (const int, const int); static void fr30_asm_trampoline_template (FILE *); static void fr30_trampoline_init (rtx, tree, rtx); -static int fr30_num_arg_regs (machine_mode, const_tree); +static int fr30_num_arg_regs (const function_arg_info &); #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) #define RETURN_POINTER_MASK (1 << (RETURN_POINTER_REGNUM)) @@ -480,7 +480,7 @@ fr30_setup_incoming_varargs (cumulative_args_t arg_regs_used_so_far_v, /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named arg must not be treated as an anonymous arg. */ /* ??? This is a pointer increment, which makes no sense. */ - arg_regs_used_so_far += fr30_num_arg_regs (arg.mode, arg.type); + arg_regs_used_so_far += fr30_num_arg_regs (arg); size = FR30_NUM_ARG_REGS - (* arg_regs_used_so_far); @@ -743,30 +743,20 @@ fr30_function_value_regno_p (const unsigned int regno) in registers. */ static bool -fr30_must_pass_in_stack (machine_mode mode, const_tree type) +fr30_must_pass_in_stack (const function_arg_info &arg) { - if (mode == BLKmode) - return true; - if (type == NULL) - return false; - return AGGREGATE_TYPE_P (type); + return arg.mode == BLKmode || arg.aggregate_type_p (); } -/* Compute the number of word sized registers needed to hold a - function argument of mode INT_MODE and tree type TYPE. */ +/* Compute the number of word sized registers needed to hold function + argument ARG. */ static int -fr30_num_arg_regs (machine_mode mode, const_tree type) +fr30_num_arg_regs (const function_arg_info &arg) { - int size; - - if (targetm.calls.must_pass_in_stack (mode, type)) + if (targetm.calls.must_pass_in_stack (arg)) return 0; - if (type && mode == BLKmode) - size = int_size_in_bytes (type); - else - size = GET_MODE_SIZE (mode); - + int size = arg.promoted_size_in_bytes (); return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; } @@ -792,7 +782,7 @@ fr30_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg) are needed because the parameter must be passed on the stack) then return zero, as this parameter does not require partial register, partial stack stack space. */ - if (*cum + fr30_num_arg_regs (arg.mode, arg.type) <= FR30_NUM_ARG_REGS) + if (*cum + fr30_num_arg_regs (arg) <= FR30_NUM_ARG_REGS) return 0; return (FR30_NUM_ARG_REGS - *cum) * UNITS_PER_WORD; @@ -804,7 +794,7 @@ fr30_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); if (!arg.named - || fr30_must_pass_in_stack (arg.mode, arg.type) + || fr30_must_pass_in_stack (arg) || *cum >= FR30_NUM_ARG_REGS) return NULL_RTX; else @@ -817,7 +807,7 @@ fr30_function_arg_advance (cumulative_args_t cum, const function_arg_info &arg) { if (arg.named) - *get_cumulative_args (cum) += fr30_num_arg_regs (arg.mode, arg.type); + *get_cumulative_args (cum) += fr30_num_arg_regs (arg); } /*}}}*/ diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c index 5d319c0bfaf..c1b3c9e6d60 100644 --- a/gcc/config/frv/frv.c +++ b/gcc/config/frv/frv.c @@ -379,7 +379,7 @@ static void frv_output_const_unspec (FILE *, const struct frv_unspec *); static bool frv_function_ok_for_sibcall (tree, tree); static rtx frv_struct_value_rtx (tree, int); -static bool frv_must_pass_in_stack (machine_mode mode, const_tree type); +static bool frv_must_pass_in_stack (const function_arg_info &); static int frv_arg_partial_bytes (cumulative_args_t, const function_arg_info &); static rtx frv_function_arg (cumulative_args_t, const function_arg_info &); @@ -3077,13 +3077,9 @@ frv_init_cumulative_args (CUMULATIVE_ARGS *cum, in registers. */ static bool -frv_must_pass_in_stack (machine_mode mode, const_tree type) +frv_must_pass_in_stack (const function_arg_info &arg) { - if (mode == BLKmode) - return true; - if (type == NULL) - return false; - return AGGREGATE_TYPE_P (type); + return arg.mode == BLKmode || arg.aggregate_type_p (); } /* If defined, a C expression that gives the alignment boundary, in bits, of an diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c index c919d31f696..8645eccf954 100644 --- a/gcc/config/gcn/gcn.c +++ b/gcc/config/gcn/gcn.c @@ -2200,22 +2200,16 @@ gcn_function_value_regno_p (const unsigned int n) return n == RETURN_VALUE_REG; } -/* Calculate the number of registers required to hold a function argument - of MODE and TYPE. */ +/* Calculate the number of registers required to hold function argument + ARG. */ static int -num_arg_regs (machine_mode mode, const_tree type) +num_arg_regs (const function_arg_info &arg) { - int size; - - if (targetm.calls.must_pass_in_stack (mode, type)) + if (targetm.calls.must_pass_in_stack (arg)) return 0; - if (type && mode == BLKmode) - size = int_size_in_bytes (type); - else - size = GET_MODE_SIZE (mode); - + int size = arg.promoted_size_in_bytes (); return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; } @@ -2263,11 +2257,11 @@ gcn_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) if (!arg.named || arg.end_marker_p ()) return 0; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return 0; int reg_num = FIRST_PARM_REG + cum->num; - int num_regs = num_arg_regs (arg.mode, arg.type); + int num_regs = num_arg_regs (arg); if (num_regs > 0) while (reg_num % num_regs != 0) reg_num++; @@ -2323,7 +2317,7 @@ gcn_function_arg_advance (cumulative_args_t cum_v, if (!arg.named) return; - int num_regs = num_arg_regs (arg.mode, arg.type); + int num_regs = num_arg_regs (arg); if (num_regs > 0) while ((FIRST_PARM_REG + cum->num) % num_regs != 0) cum->num++; @@ -2355,14 +2349,14 @@ gcn_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg) if (!arg.named) return 0; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return 0; if (cum->num >= NUM_PARM_REGS) return 0; /* If the argument fits entirely in registers, return 0. */ - if (cum->num + num_arg_regs (arg.mode, arg.type) <= NUM_PARM_REGS) + if (cum->num + num_arg_regs (arg) <= NUM_PARM_REGS) return 0; return (NUM_PARM_REGS - cum->num) * UNITS_PER_WORD; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f036d56731c..49ab50ea41b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1455,19 +1455,19 @@ ix86_function_arg_regno_p (int regno) return false; } -/* Return if we do not know how to pass TYPE solely in registers. */ +/* Return if we do not know how to pass ARG solely in registers. */ static bool -ix86_must_pass_in_stack (machine_mode mode, const_tree type) +ix86_must_pass_in_stack (const function_arg_info &arg) { - if (must_pass_in_stack_var_size_or_pad (mode, type)) + if (must_pass_in_stack_var_size_or_pad (arg)) return true; /* For 32-bit, we want TImode aggregates to go on the stack. But watch out! The layout_type routine is crafty and tries to trick us into passing currently unsupported vector types on the stack by using TImode. */ - return (!TARGET_64BIT && mode == TImode - && type && TREE_CODE (type) != VECTOR_TYPE); + return (!TARGET_64BIT && arg.mode == TImode + && arg.type && TREE_CODE (arg.type) != VECTOR_TYPE); } /* It returns the size, in bytes, of the area reserved for arguments passed @@ -2062,9 +2062,13 @@ classify_argument (machine_mode mode, const_tree type, if (bytes < 0) return 0; - if (mode != VOIDmode - && targetm.calls.must_pass_in_stack (mode, type)) - return 0; + if (mode != VOIDmode) + { + /* The value of "named" doesn't matter. */ + function_arg_info arg (const_cast (type), mode, /*named=*/true); + if (targetm.calls.must_pass_in_stack (arg)) + return 0; + } if (type && AGGREGATE_TYPE_P (type)) { diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c index 80c63812878..59c5132bc06 100644 --- a/gcc/config/iq2000/iq2000.c +++ b/gcc/config/iq2000/iq2000.c @@ -2300,7 +2300,7 @@ iq2000_pass_by_reference (cumulative_args_t cum_v, /* We must pass by reference if we would be both passing in registers and the stack. This is because any subsequent partial arg would be handled incorrectly in this case. */ - if (cum && targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (cum && targetm.calls.must_pass_in_stack (arg)) { /* Don't pass the actual CUM to FUNCTION_ARG, because we would get double copies of any offsets generated for small structs diff --git a/gcc/config/lm32/lm32.c b/gcc/config/lm32/lm32.c index a393dffadec..267ff274815 100644 --- a/gcc/config/lm32/lm32.c +++ b/gcc/config/lm32/lm32.c @@ -629,7 +629,7 @@ lm32_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) /* Compute operand 2 of the call insn. */ return GEN_INT (0); - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return NULL_RTX; if (!arg.named diff --git a/gcc/config/mcore/mcore.c b/gcc/config/mcore/mcore.c index 9feac9566d2..b259da506db 100644 --- a/gcc/config/mcore/mcore.c +++ b/gcc/config/mcore/mcore.c @@ -2713,7 +2713,8 @@ mcore_num_arg_regs (machine_mode mode, const_tree type) { int size; - if (targetm.calls.must_pass_in_stack (mode, type)) + function_arg_info arg (const_cast (type), mode, /*named=*/true); + if (targetm.calls.must_pass_in_stack (arg)) return 0; if (type && mode == BLKmode) @@ -2803,7 +2804,7 @@ mcore_function_arg (cumulative_args_t cum, const function_arg_info &arg) if (!arg.named || arg.end_marker_p ()) return 0; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return 0; arg_reg = ROUND_REG (*get_cumulative_args (cum), arg.mode); @@ -2848,7 +2849,7 @@ mcore_arg_partial_bytes (cumulative_args_t cum, const function_arg_info &arg) if (!arg.named) return 0; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return 0; /* REG is not the *hardware* register number of the register that holds diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 37ebde577b7..c24dc710b13 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -6252,7 +6252,7 @@ mips_pass_by_reference (cumulative_args_t, const function_arg_info &arg) else { /* If we have a variable-sized parameter, we have no choice. */ - return targetm.calls.must_pass_in_stack (arg.mode, arg.type); + return targetm.calls.must_pass_in_stack (arg); } } diff --git a/gcc/config/mmix/mmix.c b/gcc/config/mmix/mmix.c index 7c12e74a73d..8ebb829506c 100644 --- a/gcc/config/mmix/mmix.c +++ b/gcc/config/mmix/mmix.c @@ -621,7 +621,7 @@ mmix_function_arg_advance (cumulative_args_t argsp_v, CUMULATIVE_ARGS *argsp = get_cumulative_args (argsp_v); int arg_size = MMIX_FUNCTION_ARG_SIZE (arg.mode, arg.type); - argsp->regs = ((targetm.calls.must_pass_in_stack (arg.mode, arg.type) + argsp->regs = ((targetm.calls.must_pass_in_stack (arg) || (arg_size > 8 && !TARGET_LIBFUNC && !argsp->lib)) @@ -647,7 +647,7 @@ mmix_function_arg_1 (const cumulative_args_t argsp_v, : NULL_RTX; return (argsp->regs < MMIX_MAX_ARGS_IN_REGS - && !targetm.calls.must_pass_in_stack (arg.mode, arg.type) + && !targetm.calls.must_pass_in_stack (arg) && (GET_MODE_BITSIZE (arg.mode) <= 64 || argsp->lib || TARGET_LIBFUNC)) @@ -686,7 +686,7 @@ mmix_pass_by_reference (cumulative_args_t argsp_v, /* FIXME: Check: I'm not sure the must_pass_in_stack check is necessary. */ - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return true; if (MMIX_FUNCTION_ARG_SIZE (arg.mode, arg.type) > 8 diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 3fd4cc8adeb..3caae14e0e1 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -1951,16 +1951,16 @@ nds32_function_arg (cumulative_args_t ca, const function_arg_info &arg) } static bool -nds32_must_pass_in_stack (machine_mode mode, const_tree type) +nds32_must_pass_in_stack (const function_arg_info &arg) { /* Return true if a type must be passed in memory. If it is NOT using hard float abi, small aggregates can be passed in a register even we are calling a variadic function. So there is no need to take padding into consideration. */ if (TARGET_HARD_FLOAT) - return must_pass_in_stack_var_size_or_pad (mode, type); + return must_pass_in_stack_var_size_or_pad (arg); else - return must_pass_in_stack_var_size (mode, type); + return must_pass_in_stack_var_size (arg); } static int diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 548a7156114..fb87bb2f2cb 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -816,12 +816,12 @@ rs6000_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, /* Return true if TYPE must be passed on the stack and not in registers. */ bool -rs6000_must_pass_in_stack (machine_mode mode, const_tree type) +rs6000_must_pass_in_stack (const function_arg_info &arg) { if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2 || TARGET_64BIT) - return must_pass_in_stack_var_size (mode, type); + return must_pass_in_stack_var_size (arg); else - return must_pass_in_stack_var_size_or_pad (mode, type); + return must_pass_in_stack_var_size_or_pad (arg); } static inline bool @@ -2202,11 +2202,11 @@ rs6000_parm_needs_stack (cumulative_args_t args_so_far, tree type) mode = promote_mode (type, TYPE_MODE (type), &unsignedp); /* If we must pass in stack, we need a stack. */ - if (rs6000_must_pass_in_stack (mode, type)) + function_arg_info arg (type, mode, /*named=*/true); + if (rs6000_must_pass_in_stack (arg)) return true; /* If there is no incoming register, we need a stack. */ - function_arg_info arg (type, mode, /*named=*/true); entry_parm = rs6000_function_arg (args_so_far, arg); if (entry_parm == NULL) return true; @@ -2457,7 +2457,7 @@ setup_incoming_varargs (cumulative_args_t cum, first_reg_offset = next_cum.words; save_area = crtl->args.internal_arg_pointer; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) first_reg_offset += rs6000_arg_size (TYPE_MODE (arg.type), arg.type); } diff --git a/gcc/config/rs6000/rs6000-internal.h b/gcc/config/rs6000/rs6000-internal.h index cdd9327b4ef..baccfb3f887 100644 --- a/gcc/config/rs6000/rs6000-internal.h +++ b/gcc/config/rs6000/rs6000-internal.h @@ -156,7 +156,7 @@ extern void setup_incoming_varargs (cumulative_args_t, const function_arg_info &, int *, int); extern unsigned int rs6000_function_arg_boundary (machine_mode mode, const_tree type); -extern bool rs6000_must_pass_in_stack (machine_mode mode, const_tree type); +extern bool rs6000_must_pass_in_stack (const function_arg_info &); extern int rs6000_arg_partial_bytes (cumulative_args_t, const function_arg_info &); extern void rs6000_function_arg_advance (cumulative_args_t, diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index da912ca9abd..3b22d960b61 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -7901,7 +7901,7 @@ sh_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) { CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type)) + if (targetm.calls.must_pass_in_stack (arg)) return true; /* ??? std_gimplify_va_arg_expr passes NULL for cum. That function diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c index 7ccfbda7aad..23f546a0203 100644 --- a/gcc/config/stormy16/stormy16.c +++ b/gcc/config/stormy16/stormy16.c @@ -1239,7 +1239,7 @@ xstormy16_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) if (arg.end_marker_p ()) return const0_rtx; - if (targetm.calls.must_pass_in_stack (arg.mode, arg.type) + if (targetm.calls.must_pass_in_stack (arg) || (*cum + XSTORMY16_WORD_SIZE (arg.type, arg.mode) > NUM_ARGUMENT_REGISTERS)) return NULL_RTX; diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c index a277633e6ef..98f30c5cc21 100644 --- a/gcc/config/xtensa/xtensa.c +++ b/gcc/config/xtensa/xtensa.c @@ -2118,7 +2118,7 @@ xtensa_function_arg_advance (cumulative_args_t cum, / UNITS_PER_WORD); if (*arg_words < max - && (targetm.calls.must_pass_in_stack (arg.mode, arg.type) + && (targetm.calls.must_pass_in_stack (arg) || *arg_words + words > max)) *arg_words = max; diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 99dbfb8d0fb..55069088b52 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4012,8 +4012,8 @@ defined, the argument will be computed in the stack and then loaded into a register. @end deftypefn -@deftypefn {Target Hook} bool TARGET_MUST_PASS_IN_STACK (machine_mode @var{mode}, const_tree @var{type}) -This target hook should return @code{true} if we should not pass @var{type} +@deftypefn {Target Hook} bool TARGET_MUST_PASS_IN_STACK (const function_arg_info @var{&arg}) +This target hook should return @code{true} if we should not pass @var{arg} solely in registers. The file @file{expr.h} defines a definition that is usually appropriate, refer to @file{expr.h} for additional documentation. diff --git a/gcc/function.c b/gcc/function.c index 1d7687aebce..46ed75c77be 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -2552,8 +2552,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, /* If this parameter was passed both in registers and in the stack, use the copy on the stack. */ - if (targetm.calls.must_pass_in_stack (data->promoted_mode, - data->passed_type)) + if (targetm.calls.must_pass_in_stack (arg)) entry_parm = 0; if (entry_parm) diff --git a/gcc/target.def b/gcc/target.def index 4f8acfd2276..b2332d8215c 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4630,11 +4630,11 @@ false.", Need audit to verify that this is the case. */ DEFHOOK (must_pass_in_stack, - "This target hook should return @code{true} if we should not pass @var{type}\n\ + "This target hook should return @code{true} if we should not pass @var{arg}\n\ solely in registers. The file @file{expr.h} defines a\n\ definition that is usually appropriate, refer to @file{expr.h} for additional\n\ documentation.", - bool, (machine_mode mode, const_tree type), + bool, (const function_arg_info &arg), must_pass_in_stack_var_size_or_pad) /* Return true if type TYPE, mode MODE, which is passed by reference, diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 5a0ed2f72de..1d12ec54704 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -323,7 +323,7 @@ bool hook_pass_by_reference_must_pass_in_stack (cumulative_args_t, const function_arg_info &arg) { - return targetm.calls.must_pass_in_stack (arg.mode, arg.type); + return targetm.calls.must_pass_in_stack (arg); } /* Return true if a parameter follows callee copies conventions. This