1. Update PUSH_ARGS to accept an argument. When the PUSH instruction
usage is optional, pass the number of bytes to push to PUSH_ARGS so that
the backend can decide if PUSH instructions should be generated.
2. Change x86 PUSH_ARGS to return 0 when number of bytes to push is more
than a word to avoid generating non-existent PUSH instructions.
3. Remove target PUSH_ARGS definitions which return 0 as it is the same
as the default.
gcc/
PR target/100704
* calls.c (expand_call): Add 0 to PUSH_ARGS.
(emit_library_call_value_1): Likewise.
* defaults.h (PUSH_ARGS): Add npush.
(PUSH_ARGS_REVERSED): Add 0 to PUSH_ARGS.
* expr.c (block_move_libcall_safe_for_call_parm): Add 0 to
PUSH_ARGS.
(emit_push_insn): Pass the number bytes to push to PUSH_ARGS.
Pass 0 to PUSH_ARGS if ARGS_ADDR is 0.
* rtlanal.c (nonzero_bits1): Add 0 to PUSH_ARGS.
* config/bpf/bpf.h (PUSH_ARGS): Removed.
* config/cr16/cr16.h (PUSH_ARGS): Updated.
* config/i386/i386.h (PUSH_ARGS): Return 0 if the number of
bytes to push is more than UNITS_PER_WORD.
* config/m32c/m32c.h (PUSH_ARGS): Updated.
* config/nios2/nios2.h (PUSH_ARGS): Removed.
* config/pru/pru.h (PUSH_ARGS): Removed.
* doc/tm.texi.in: Update PUSH_ARGS documentation.
* doc/tm.texi: Regenerated.
gcc/testsuite/
PR target/100704
* gcc.target/i386/pr100704-1.c: New test.
* gcc.target/i386/pr100704-2.c: Likewise.
---
gcc/calls.c | 6 +++---
gcc/config/bpf/bpf.h | 3 ---
gcc/config/cr16/cr16.h | 2 +-
gcc/config/i386/i386.h | 12 +++++++----
gcc/config/m32c/m32c.h | 2 +-
gcc/config/nios2/nios2.h | 1 -
gcc/config/pru/pru.h | 1 -
gcc/defaults.h | 6 +++---
gcc/doc/tm.texi | 8 +++++---
gcc/doc/tm.texi.in | 8 +++++---
gcc/expr.c | 14 ++++++++++---
gcc/rtlanal.c | 2 +-
gcc/testsuite/gcc.target/i386/pr100704-1.c | 24 ++++++++++++++++++++++
gcc/testsuite/gcc.target/i386/pr100704-2.c | 23 +++++++++++++++++++++
14 files changed, 85 insertions(+), 27 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/i386/pr100704-1.c
create mode 100644 gcc/testsuite/gcc.target/i386/pr100704-2.c
diff --git a/gcc/calls.c b/gcc/calls.c
index f3da1839dc5..0cb7c23d310 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -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 = !PUSH_ARGS (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 && PUSH_ARGS (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 (!PUSH_ARGS (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 4c5b19e262b..80195cea5b2 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.h b/gcc/config/cr16/cr16.h
index 4ce9e81b0e3..68db73348bf 100644
--- a/gcc/config/cr16/cr16.h
+++ b/gcc/config/cr16/cr16.h
@@ -376,7 +376,7 @@ enum reg_class
#define ACCUMULATE_OUTGOING_ARGS 0
-#define PUSH_ARGS 1
+#define PUSH_ARGS(npush) 1
#define PUSH_ROUNDING(BYTES) cr16_push_rounding (BYTES)
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 53d503fc6e0..48b99033c28 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1462,10 +1462,14 @@ 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)
+/* If defined, a C expression whose value is nonzero when we want to
+ use PUSH instructions to pass outgoing arguments. NPUSH is the
+ number of bytes to push. */
+
+#define PUSH_ARGS(npush) \
+ ((npush) <= UNITS_PER_WORD \
+ && TARGET_PUSH_ARGS \
+ && !ACCUMULATE_OUTGOING_ARGS)
/* We want the stack and args grow in opposite directions, even if
PUSH_ARGS is 0. */
diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h
index 635f5924c20..33b96d973c8 100644
--- a/gcc/config/m32c/m32c.h
+++ b/gcc/config/m32c/m32c.h
@@ -472,7 +472,7 @@ enum reg_class
/* Passing Function Arguments on the Stack */
-#define PUSH_ARGS 1
+#define PUSH_ARGS(npush) 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 1840a466f96..dfca12cc525 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 4c35a7d7ee3..9b6be323e6d 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 91216593e75..09446981d3d 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -804,9 +804,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.
If not, see
/* Supply a default definition for PUSH_ARGS. */
#ifndef PUSH_ARGS
#ifdef PUSH_ROUNDING
-#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS
+#define PUSH_ARGS(npush) !ACCUMULATE_OUTGOING_ARGS
#else
-#define PUSH_ARGS 0
+#define PUSH_ARGS(npush) 0
#endif
#endif
@@ -820,7 +820,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 PUSH_ARGS(0)
#endif
#endif
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index e3a080e4a7c..03586e2a1fe 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3807,9 +3807,11 @@ 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.
+@defmac PUSH_ARGS (@var{npush})
+A C expression. If nonzero, push insns 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, set it to zero.
That directs GCC to use an alternate strategy: to
allocate the entire argument block and then store the arguments into
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index d9fbbe20e6f..62e3456a10a 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -3100,9 +3100,11 @@ 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.
+@defmac PUSH_ARGS (@var{npush})
+A C expression. If nonzero, push insns 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, set it to zero.
That directs GCC to use an alternate strategy: to
allocate the entire argument block and then store the arguments into
diff --git a/gcc/expr.c b/gcc/expr.c
index e4660f0e90a..1b565d9be3a 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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 (PUSH_ARGS (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
+ && PUSH_ARGS (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 && PUSH_ARGS (0))
emit_single_push_insn (mode, x, type);
else
#endif
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 712c2c28578..1082d8cbb30 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 && PUSH_ARGS (0))
{
poly_uint64 rounded_1 = PUSH_ROUNDING (poly_int64 (1));
alignment = MIN (known_alignment (rounded_1), alignment);
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 00000000000..02461db9695
--- /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 00000000000..07b9bd18c7a
--- /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 } } */
--
2.31.1