Add a target calls hook: TARGET_PUSH_ARGUMENT
1. Replace PUSH_ARGS with a target calls hook, TARGET_PUSH_ARGUMENT, which takes an integer argument. When it returns true, push instructions will be used to pass outgoing arguments. If the argument is nonzero, it is the number of bytes to push and indicates the PUSH instruction usage is optional so that the backend can decide if PUSH instructions should be generated. Otherwise, the argument is zero. 2. Implement x86 target hook which returns false when the number of bytes to push is no less than 16 (8 for 32-bit targets) if vector load and store can be used. 3. Remove target PUSH_ARGS definitions which return 0 as it is the same as the default. 4. Define TARGET_PUSH_ARGUMENT of cr16 and m32c to always return true. gcc/ PR target/100704 * calls.c (expand_call): Replace PUSH_ARGS with targetm.calls.push_argument (0). (emit_library_call_value_1): Likewise. * defaults.h (PUSH_ARGS): Removed. (PUSH_ARGS_REVERSED): Replace PUSH_ARGS with targetm.calls.push_argument (0). * expr.c (block_move_libcall_safe_for_call_parm): Likewise. (emit_push_insn): Pass the number bytes to push to targetm.calls.push_argument and pass 0 if ARGS_ADDR is 0. * hooks.c (hook_bool_uint_true): New. * hooks.h (hook_bool_uint_true): Likewise. * rtlanal.c (nonzero_bits1): Replace PUSH_ARGS with targetm.calls.push_argument (0). * target.def (push_argument): Add a targetm.calls hook. * targhooks.c (default_push_argument): New. * targhooks.h (default_push_argument): Likewise. * config/bpf/bpf.h (PUSH_ARGS): Removed. * config/cr16/cr16.c (TARGET_PUSH_ARGUMENT): New. * config/cr16/cr16.h (PUSH_ARGS): Removed. * config/i386/i386.c (ix86_push_argument): New. (TARGET_PUSH_ARGUMENT): Likewise. * config/i386/i386.h (PUSH_ARGS): Removed. * config/m32c/m32c.c (TARGET_PUSH_ARGUMENT): New. * config/m32c/m32c.h (PUSH_ARGS): Removed. * config/nios2/nios2.h (PUSH_ARGS): Likewise. * config/pru/pru.h (PUSH_ARGS): Likewise. * doc/tm.texi.in: Remove PUSH_ARGS documentation. Add TARGET_PUSH_ARGUMENT hook. * 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.target/i386/pr100704-3.c: Likewise.
This commit is contained in:
parent
20a2c8ace0
commit
967b465302
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
14
gcc/expr.c
14
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 (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);
|
||||
|
@ -4752,6 +4752,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 &);
|
||||
|
24
gcc/testsuite/gcc.target/i386/pr100704-1.c
Normal file
24
gcc/testsuite/gcc.target/i386/pr100704-1.c
Normal file
@ -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 } } */
|
23
gcc/testsuite/gcc.target/i386/pr100704-2.c
Normal file
23
gcc/testsuite/gcc.target/i386/pr100704-2.c
Normal file
@ -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 } } */
|
20
gcc/testsuite/gcc.target/i386/pr100704-3.c
Normal file
20
gcc/testsuite/gcc.target/i386/pr100704-3.c
Normal file
@ -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\+" } } */
|
Loading…
Reference in New Issue
Block a user