@@ -3727,7 +3727,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;
@@ -3836,7 +3836,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. */
@@ -5477,7 +5477,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);
}
@@ -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
@@ -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
@@ -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
@@ -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. */
@@ -23637,6 +23649,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
@@ -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. */
@@ -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
@@ -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
@@ -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. */
@@ -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. */
@@ -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
@@ -3807,14 +3807,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
@@ -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
@@ -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. */
@@ -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);
@@ -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);
@@ -4749,6 +4749,20 @@ Most ports do not need to implement anything for this hook.",
void, (void),
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\
@@ -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 &)
{
@@ -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 &);
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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\+" } } */