diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/calls.c | 6 | ||||
-rw-r--r-- | gcc/config/bpf/bpf.h | 3 | ||||
-rw-r--r-- | gcc/config/cr16/cr16.c | 2 | ||||
-rw-r--r-- | gcc/config/cr16/cr16.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 14 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 7 | ||||
-rw-r--r-- | gcc/config/m32c/m32c.c | 3 | ||||
-rw-r--r-- | gcc/config/m32c/m32c.h | 1 | ||||
-rw-r--r-- | gcc/config/nios2/nios2.h | 1 | ||||
-rw-r--r-- | gcc/config/pru/pru.h | 1 | ||||
-rw-r--r-- | gcc/defaults.h | 11 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 19 | ||||
-rw-r--r-- | gcc/doc/tm.texi.in | 9 | ||||
-rw-r--r-- | gcc/expr.c | 14 | ||||
-rw-r--r-- | gcc/hooks.c | 8 | ||||
-rw-r--r-- | gcc/hooks.h | 1 | ||||
-rw-r--r-- | gcc/rtlanal.c | 2 | ||||
-rw-r--r-- | gcc/target.def | 14 | ||||
-rw-r--r-- | gcc/targhooks.c | 12 | ||||
-rw-r--r-- | gcc/targhooks.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr100704-1.c | 24 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr100704-2.c | 23 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr100704-3.c | 20 |
23 files changed, 151 insertions, 47 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index a7c78ed..4bf2b5d 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -3729,7 +3729,7 @@ expand_call (tree exp, rtx target, int ignore) So the entire argument block must then be preallocated (i.e., we ignore PUSH_ROUNDING in that case). */ - int must_preallocate = !PUSH_ARGS; + int must_preallocate = !targetm.calls.push_argument (0); /* Size of the stack reserved for parameter registers. */ int reg_parm_stack_space = 0; @@ -3838,7 +3838,7 @@ expand_call (tree exp, rtx target, int ignore) #endif if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))) - && reg_parm_stack_space > 0 && PUSH_ARGS) + && reg_parm_stack_space > 0 && targetm.calls.push_argument (0)) must_preallocate = 1; /* Set up a place to return a structure. */ @@ -5479,7 +5479,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, } else { - if (!PUSH_ARGS) + if (!targetm.calls.push_argument (0)) argblock = push_block (gen_int_mode (args_size.constant, Pmode), 0, 0); } diff --git a/gcc/config/bpf/bpf.h b/gcc/config/bpf/bpf.h index 4c5b19e..80195ce 100644 --- a/gcc/config/bpf/bpf.h +++ b/gcc/config/bpf/bpf.h @@ -288,9 +288,6 @@ enum reg_class never used when passing arguments. However, we still have to define the constants below. */ -/* If nonzero, push insns will be used to pass outgoing arguments. */ -#define PUSH_ARGS 0 - /* If nonzero, function arguments will be evaluated from last to first, rather than from first to last. */ #define PUSH_ARGS_REVERSED 1 diff --git a/gcc/config/cr16/cr16.c b/gcc/config/cr16/cr16.c index 6c81c39..aaa2260 100644 --- a/gcc/config/cr16/cr16.c +++ b/gcc/config/cr16/cr16.c @@ -158,6 +158,8 @@ static void cr16_print_operand_address (FILE *, machine_mode, rtx); #define TARGET_CLASS_LIKELY_SPILLED_P cr16_class_likely_spilled_p /* Passing function arguments. */ +#undef TARGET_PUSH_ARGUMENT +#define TARGET_PUSH_ARGUMENT hook_bool_uint_true #undef TARGET_FUNCTION_ARG #define TARGET_FUNCTION_ARG cr16_function_arg #undef TARGET_FUNCTION_ARG_ADVANCE diff --git a/gcc/config/cr16/cr16.h b/gcc/config/cr16/cr16.h index 4ce9e81..a3ad035 100644 --- a/gcc/config/cr16/cr16.h +++ b/gcc/config/cr16/cr16.h @@ -376,8 +376,6 @@ enum reg_class #define ACCUMULATE_OUTGOING_ARGS 0 -#define PUSH_ARGS 1 - #define PUSH_ROUNDING(BYTES) cr16_push_rounding (BYTES) #ifndef CUMULATIVE_ARGS diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a612558..7d0d414 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -4191,6 +4191,18 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) } } +/* Implement TARGET_PUSH_ARGUMENT. */ + +static bool +ix86_push_argument (unsigned int npush) +{ + /* If SSE2 is available, use vector move to put large argument onto + stack. NB: In 32-bit mode, use 8-byte vector move. */ + return ((!TARGET_SSE2 || npush < (TARGET_64BIT ? 16 : 8)) + && TARGET_PUSH_ARGS + && !ACCUMULATE_OUTGOING_ARGS); +} + /* Create the va_list data type. */ @@ -23695,6 +23707,8 @@ ix86_run_selftests (void) #define TARGET_C_EXCESS_PRECISION ix86_get_excess_precision #undef TARGET_PROMOTE_PROTOTYPES #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true +#undef TARGET_PUSH_ARGUMENT +#define TARGET_PUSH_ARGUMENT ix86_push_argument #undef TARGET_SETUP_INCOMING_VARARGS #define TARGET_SETUP_INCOMING_VARARGS ix86_setup_incoming_varargs #undef TARGET_MUST_PASS_IN_STACK diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 182b327..6e0340a 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1462,13 +1462,8 @@ enum reg_class || TARGET_64BIT_MS_ABI \ || (TARGET_MACHO && crtl->profile)) -/* If defined, a C expression whose value is nonzero when we want to use PUSH - instructions to pass outgoing arguments. */ - -#define PUSH_ARGS (TARGET_PUSH_ARGS && !ACCUMULATE_OUTGOING_ARGS) - /* We want the stack and args grow in opposite directions, even if - PUSH_ARGS is 0. */ + targetm.calls.push_argument returns false. */ #define PUSH_ARGS_REVERSED 1 /* Offset of first parameter from the argument pointer register value. */ diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c index b1cb359..d22bdd7 100644 --- a/gcc/config/m32c/m32c.c +++ b/gcc/config/m32c/m32c.c @@ -1296,6 +1296,9 @@ m32c_push_rounding (poly_int64 n) return (n + 1) & ~1; } +#undef TARGET_PUSH_ARGUMENT +#define TARGET_PUSH_ARGUMENT hook_bool_uint_true + /* Passing Arguments in Registers */ /* Implements TARGET_FUNCTION_ARG. Arguments are passed partly in diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h index 635f592..228a73d 100644 --- a/gcc/config/m32c/m32c.h +++ b/gcc/config/m32c/m32c.h @@ -472,7 +472,6 @@ enum reg_class /* Passing Function Arguments on the Stack */ -#define PUSH_ARGS 1 #define PUSH_ROUNDING(N) m32c_push_rounding (N) #define CALL_POPS_ARGS(C) 0 diff --git a/gcc/config/nios2/nios2.h b/gcc/config/nios2/nios2.h index 1840a46..dfca12c 100644 --- a/gcc/config/nios2/nios2.h +++ b/gcc/config/nios2/nios2.h @@ -297,7 +297,6 @@ typedef struct nios2_args ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) /* Passing function arguments on stack. */ -#define PUSH_ARGS 0 #define ACCUMULATE_OUTGOING_ARGS 1 /* We define TARGET_RETURN_IN_MEMORY, so set to zero. */ diff --git a/gcc/config/pru/pru.h b/gcc/config/pru/pru.h index 4c35a7d..9b6be32 100644 --- a/gcc/config/pru/pru.h +++ b/gcc/config/pru/pru.h @@ -339,7 +339,6 @@ typedef struct pru_args ((REGNO) >= FIRST_ARG_REGNUM && (REGNO) <= LAST_ARG_REGNUM) /* Passing function arguments on stack. */ -#define PUSH_ARGS 0 #define ACCUMULATE_OUTGOING_ARGS 1 /* We define TARGET_RETURN_IN_MEMORY, so set to zero. */ diff --git a/gcc/defaults.h b/gcc/defaults.h index 9121659..ba79a8e 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -801,15 +801,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define NEXT_OBJC_RUNTIME 0 #endif -/* Supply a default definition for PUSH_ARGS. */ -#ifndef PUSH_ARGS -#ifdef PUSH_ROUNDING -#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS -#else -#define PUSH_ARGS 0 -#endif -#endif - /* Decide whether a function's arguments should be processed from first to last or from last to first. @@ -820,7 +811,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifndef PUSH_ARGS_REVERSED #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD) -#define PUSH_ARGS_REVERSED PUSH_ARGS +#define PUSH_ARGS_REVERSED targetm.calls.push_argument (0) #endif #endif diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index fc7eb77..2a41ae5 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3900,14 +3900,17 @@ cases of mismatch, it also makes for better code on certain machines. The default is to not promote prototypes. @end deftypefn -@defmac PUSH_ARGS -A C expression. If nonzero, push insns will be used to pass -outgoing arguments. -If the target machine does not have a push instruction, set it to zero. -That directs GCC to use an alternate strategy: to -allocate the entire argument block and then store the arguments into -it. When @code{PUSH_ARGS} is nonzero, @code{PUSH_ROUNDING} must be defined too. -@end defmac +@deftypefn {Target Hook} bool TARGET_PUSH_ARGUMENT (unsigned int @var{npush}) +This target hook returns @code{true} if push instructions will be +used to pass outgoing arguments. When the push instruction usage is +optional, @var{npush} is nonzero to indicate the number of bytes to +push. Otherwise, @var{npush} is zero. If the target machine does not +have a push instruction or push instruction should be avoided, +@code{false} should be returned. That directs GCC to use an alternate +strategy: to allocate the entire argument block and then store the +arguments into it. If this target hook may return @code{true}, +@code{PUSH_ROUNDING} must be defined. +@end deftypefn @defmac PUSH_ARGS_REVERSED A C expression. If nonzero, function arguments will be evaluated from diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 33532f0..f881cda 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3100,14 +3100,7 @@ control passing certain arguments in registers. @hook TARGET_PROMOTE_PROTOTYPES -@defmac PUSH_ARGS -A C expression. If nonzero, push insns will be used to pass -outgoing arguments. -If the target machine does not have a push instruction, set it to zero. -That directs GCC to use an alternate strategy: to -allocate the entire argument block and then store the arguments into -it. When @code{PUSH_ARGS} is nonzero, @code{PUSH_ROUNDING} must be defined too. -@end defmac +@hook TARGET_PUSH_ARGUMENT @defmac PUSH_ARGS_REVERSED A C expression. If nonzero, function arguments will be evaluated from @@ -1823,7 +1823,7 @@ block_move_libcall_safe_for_call_parm (void) tree fn; /* If arguments are pushed on the stack, then they're safe. */ - if (PUSH_ARGS) + if (targetm.calls.push_argument (0)) return true; /* If registers go on the stack anyway, any argument is sure to clobber @@ -4639,11 +4639,19 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, skip = (reg_parm_stack_space == 0) ? 0 : used; #ifdef PUSH_ROUNDING + /* NB: Let the backend known the number of bytes to push and + decide if push insns should be generated. */ + unsigned int push_size; + if (CONST_INT_P (size)) + push_size = INTVAL (size); + else + push_size = 0; + /* Do it with several push insns if that doesn't take lots of insns and if there is no difficulty with push insns that skip bytes on the stack for alignment purposes. */ if (args_addr == 0 - && PUSH_ARGS + && targetm.calls.push_argument (push_size) && CONST_INT_P (size) && skip == 0 && MEM_ALIGN (xinner) >= align @@ -4848,7 +4856,7 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, anti_adjust_stack (gen_int_mode (extra, Pmode)); #ifdef PUSH_ROUNDING - if (args_addr == 0 && PUSH_ARGS) + if (args_addr == 0 && targetm.calls.push_argument (0)) emit_single_push_insn (mode, x, type); else #endif diff --git a/gcc/hooks.c b/gcc/hooks.c index 680271f..4f14abf 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -520,6 +520,14 @@ hook_void_gcc_optionsp (struct gcc_options *) { } +/* Generic hook that takes an unsigned int and returns true. */ + +bool +hook_bool_uint_true (unsigned int) +{ + return true; +} + /* Generic hook that takes an unsigned int, an unsigned int pointer and returns false. */ diff --git a/gcc/hooks.h b/gcc/hooks.h index add9a74..71781c7 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -89,6 +89,7 @@ extern void hook_void_tree (tree); extern void hook_void_tree_treeptr (tree, tree *); extern void hook_void_int_int (int, int); extern void hook_void_gcc_optionsp (struct gcc_options *); +extern bool hook_bool_uint_true (unsigned int); extern bool hook_bool_uint_uintp_false (unsigned int, unsigned int *); extern int hook_int_uint_mode_1 (unsigned int, machine_mode); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 712c2c28..55c338e 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -4870,7 +4870,7 @@ nonzero_bits1 (const_rtx x, scalar_int_mode mode, const_rtx known_x, /* If PUSH_ROUNDING is defined, it is possible for the stack to be momentarily aligned only to that amount, so we pick the least alignment. */ - if (x == stack_pointer_rtx && PUSH_ARGS) + if (x == stack_pointer_rtx && targetm.calls.push_argument (0)) { poly_uint64 rounded_1 = PUSH_ROUNDING (poly_int64 (1)); alignment = MIN (known_alignment (rounded_1), alignment); diff --git a/gcc/target.def b/gcc/target.def index ebe5803..c009671 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4753,6 +4753,20 @@ Most ports do not need to implement anything for this hook.", hook_void_void) DEFHOOK +(push_argument, + "This target hook returns @code{true} if push instructions will be\n\ +used to pass outgoing arguments. When the push instruction usage is\n\ +optional, @var{npush} is nonzero to indicate the number of bytes to\n\ +push. Otherwise, @var{npush} is zero. If the target machine does not\n\ +have a push instruction or push instruction should be avoided,\n\ +@code{false} should be returned. That directs GCC to use an alternate\n\ +strategy: to allocate the entire argument block and then store the\n\ +arguments into it. If this target hook may return @code{true},\n\ +@code{PUSH_ROUNDING} must be defined.", + bool, (unsigned int npush), + default_push_argument) + +DEFHOOK (strict_argument_naming, "Define this hook to return @code{true} if the location where a function\n\ argument is passed depends on whether or not it is a named argument.\n\ diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 08f676b..44a1fac 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -770,6 +770,18 @@ hook_void_CUMULATIVE_ARGS_tree (cumulative_args_t ca ATTRIBUTE_UNUSED, { } +/* Default implementation of TARGET_PUSH_ARGUMENT. */ + +bool +default_push_argument (unsigned int) +{ +#ifdef PUSH_ROUNDING + return !ACCUMULATE_OUTGOING_ARGS; +#else + return false; +#endif +} + void default_function_arg_advance (cumulative_args_t, const function_arg_info &) { diff --git a/gcc/targhooks.h b/gcc/targhooks.h index b537038..f70a307d 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -149,6 +149,7 @@ extern const char *hook_invalid_arg_for_unprototyped_fn (const_tree, const_tree, const_tree); extern void default_function_arg_advance (cumulative_args_t, const function_arg_info &); +extern bool default_push_argument (unsigned int); extern HOST_WIDE_INT default_function_arg_offset (machine_mode, const_tree); extern pad_direction default_function_arg_padding (machine_mode, const_tree); extern rtx default_function_arg (cumulative_args_t, const function_arg_info &); diff --git a/gcc/testsuite/gcc.target/i386/pr100704-1.c b/gcc/testsuite/gcc.target/i386/pr100704-1.c new file mode 100644 index 0000000..02461db --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr100704-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -march=x86-64" } */ + +struct S +{ + long long s1 __attribute__ ((aligned (8))); + unsigned s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14; +}; + +extern struct S a[]; + +void bar (struct S); + +void +foo (void) +{ + bar (a[0]); +} + +/* { dg-final { scan-assembler-not "pushq" } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, \\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 16\\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 32\\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 48\\(%\[\^,\]+\\)" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr100704-2.c b/gcc/testsuite/gcc.target/i386/pr100704-2.c new file mode 100644 index 0000000..07b9bd1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr100704-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -march=x86-64" } */ + +struct S +{ + char array[64]; +}; + +extern struct S a[]; + +void bar (struct S); + +void +foo (void) +{ + bar (a[0]); +} + +/* { dg-final { scan-assembler-not "pushq" } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, \\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 16\\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 32\\(%\[\^,\]+\\)" 1 } } */ +/* { dg-final { scan-assembler-times "movups\[\\t \]%xmm\[0-9\]+, 48\\(%\[\^,\]+\\)" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr100704-3.c b/gcc/testsuite/gcc.target/i386/pr100704-3.c new file mode 100644 index 0000000..65f9745 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr100704-3.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-sse" } */ + +struct S +{ + long long s1 __attribute__ ((aligned (8))); + unsigned s2, s3; +}; + +extern struct S foooo[]; + +void bar (int, int, int, int, int, int, struct S); + +void +foo (void) +{ + bar (1, 2, 3, 4, 5, 6, foooo[0]); +} + +/* { dg-final { scan-assembler "push\[lq\]\tfoooo\+" } } */ |