462 lines
18 KiB
Diff
462 lines
18 KiB
Diff
From 58adede22d9ff2368b5c24ec3fc0e53bd3ddc8bd Mon Sep 17 00:00:00 2001
|
|
From: Richard Sandiford <richard.sandiford@arm.com>
|
|
Date: Tue, 5 Dec 2023 09:44:52 +0000
|
|
Subject: [PATCH 051/157] [Backport][SME] Add a new target hook:
|
|
TARGET_START_CALL_ARGS
|
|
|
|
Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=672fad57c1f99ff893019e2da4620e26b9b31dd2
|
|
|
|
We have the following two hooks into the call expansion code:
|
|
|
|
- TARGET_CALL_ARGS is called for each argument before arguments
|
|
are moved into hard registers.
|
|
|
|
- TARGET_END_CALL_ARGS is called after the end of the call
|
|
sequence (specifically, after any return value has been
|
|
moved to a pseudo).
|
|
|
|
This patch adds a TARGET_START_CALL_ARGS hook that is called before
|
|
the TARGET_CALL_ARGS sequence. This means that TARGET_START_CALL_REGS
|
|
and TARGET_END_CALL_REGS bracket the region in which argument registers
|
|
might be live. They also bracket a region in which the only call
|
|
emiitted by target-independent code is the call to the target function
|
|
itself. (For example, TARGET_START_CALL_ARGS happens after any use of
|
|
memcpy to copy arguments, and TARGET_END_CALL_ARGS happens before any
|
|
use of memcpy to copy the result.)
|
|
|
|
Also, the patch adds the cumulative argument structure as an argument
|
|
to the hooks, so that the target can use it to record and retrieve
|
|
information about the call as a whole.
|
|
|
|
The TARGET_CALL_ARGS docs said:
|
|
|
|
While generating RTL for a function call, this target hook is invoked once
|
|
for each argument passed to the function, either a register returned by
|
|
``TARGET_FUNCTION_ARG`` or a memory location. It is called just
|
|
- before the point where argument registers are stored.
|
|
|
|
The last bit was true for normal calls, but for libcalls the hook was
|
|
invoked earlier, before stack arguments have been copied. I don't think
|
|
this caused a practical difference for nvptx (the only port to use the
|
|
hooks) since I wouldn't expect any libcalls to take stack parameters.
|
|
|
|
gcc/
|
|
* doc/tm.texi.in: Add TARGET_START_CALL_ARGS.
|
|
* doc/tm.texi: Regenerate.
|
|
* target.def (start_call_args): New hook.
|
|
(call_args, end_call_args): Add a parameter for the cumulative
|
|
argument information.
|
|
* hooks.h (hook_void_rtx_tree): Delete.
|
|
* hooks.cc (hook_void_rtx_tree): Likewise.
|
|
* targhooks.h (hook_void_CUMULATIVE_ARGS): Declare.
|
|
(hook_void_CUMULATIVE_ARGS_rtx_tree): Likewise.
|
|
* targhooks.cc (hook_void_CUMULATIVE_ARGS): New function.
|
|
(hook_void_CUMULATIVE_ARGS_rtx_tree): Likewise.
|
|
* calls.cc (expand_call): Call start_call_args before computing
|
|
and storing stack parameters. Pass the cumulative argument
|
|
information to call_args and end_call_args.
|
|
(emit_library_call_value_1): Likewise.
|
|
* config/nvptx/nvptx.cc (nvptx_call_args): Add a cumulative
|
|
argument parameter.
|
|
(nvptx_end_call_args): Likewise.
|
|
---
|
|
gcc/calls.cc | 61 +++++++++++++++++++++------------------
|
|
gcc/config/nvptx/nvptx.cc | 4 +--
|
|
gcc/doc/tm.texi | 53 +++++++++++++++++++++++++++-------
|
|
gcc/doc/tm.texi.in | 2 ++
|
|
gcc/hooks.cc | 5 ----
|
|
gcc/hooks.h | 1 -
|
|
gcc/target.def | 59 +++++++++++++++++++++++++++++--------
|
|
gcc/targhooks.cc | 10 +++++++
|
|
gcc/targhooks.h | 5 ++--
|
|
9 files changed, 140 insertions(+), 60 deletions(-)
|
|
|
|
diff --git a/gcc/calls.cc b/gcc/calls.cc
|
|
index c1db66883..4a8535cc6 100644
|
|
--- a/gcc/calls.cc
|
|
+++ b/gcc/calls.cc
|
|
@@ -3507,15 +3507,26 @@ expand_call (tree exp, rtx target, int ignore)
|
|
sibcall_failure = 1;
|
|
}
|
|
|
|
+ /* Set up the next argument register. For sibling calls on machines
|
|
+ with register windows this should be the incoming register. */
|
|
+ if (pass == 0)
|
|
+ next_arg_reg = targetm.calls.function_incoming_arg
|
|
+ (args_so_far, function_arg_info::end_marker ());
|
|
+ else
|
|
+ next_arg_reg = targetm.calls.function_arg
|
|
+ (args_so_far, function_arg_info::end_marker ());
|
|
+
|
|
+ targetm.calls.start_call_args (args_so_far);
|
|
+
|
|
bool any_regs = false;
|
|
for (i = 0; i < num_actuals; i++)
|
|
if (args[i].reg != NULL_RTX)
|
|
{
|
|
any_regs = true;
|
|
- targetm.calls.call_args (args[i].reg, funtype);
|
|
+ targetm.calls.call_args (args_so_far, args[i].reg, funtype);
|
|
}
|
|
if (!any_regs)
|
|
- targetm.calls.call_args (pc_rtx, funtype);
|
|
+ targetm.calls.call_args (args_so_far, pc_rtx, funtype);
|
|
|
|
/* Figure out the register where the value, if any, will come back. */
|
|
valreg = 0;
|
|
@@ -3578,15 +3589,6 @@ expand_call (tree exp, rtx target, int ignore)
|
|
later safely search backwards to find the CALL_INSN. */
|
|
before_call = get_last_insn ();
|
|
|
|
- /* Set up next argument register. For sibling calls on machines
|
|
- with register windows this should be the incoming register. */
|
|
- if (pass == 0)
|
|
- next_arg_reg = targetm.calls.function_incoming_arg
|
|
- (args_so_far, function_arg_info::end_marker ());
|
|
- else
|
|
- next_arg_reg = targetm.calls.function_arg
|
|
- (args_so_far, function_arg_info::end_marker ());
|
|
-
|
|
if (pass == 1 && (return_flags & ERF_RETURNS_ARG))
|
|
{
|
|
int arg_nr = return_flags & ERF_RETURN_ARG_MASK;
|
|
@@ -3879,7 +3881,7 @@ expand_call (tree exp, rtx target, int ignore)
|
|
for (i = 0; i < num_actuals; ++i)
|
|
free (args[i].aligned_regs);
|
|
|
|
- targetm.calls.end_call_args ();
|
|
+ targetm.calls.end_call_args (args_so_far);
|
|
|
|
insns = get_insns ();
|
|
end_sequence ();
|
|
@@ -4437,17 +4439,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|
}
|
|
#endif
|
|
|
|
- /* When expanding a normal call, args are stored in push order,
|
|
- which is the reverse of what we have here. */
|
|
- bool any_regs = false;
|
|
- for (int i = nargs; i-- > 0; )
|
|
- if (argvec[i].reg != NULL_RTX)
|
|
- {
|
|
- targetm.calls.call_args (argvec[i].reg, NULL_TREE);
|
|
- any_regs = true;
|
|
- }
|
|
- if (!any_regs)
|
|
- targetm.calls.call_args (pc_rtx, NULL_TREE);
|
|
+ rtx call_cookie
|
|
+ = targetm.calls.function_arg (args_so_far,
|
|
+ function_arg_info::end_marker ());
|
|
|
|
/* Push the args that need to be pushed. */
|
|
|
|
@@ -4565,6 +4559,20 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|
|
|
fun = prepare_call_address (NULL, fun, NULL, &call_fusage, 0, 0);
|
|
|
|
+ targetm.calls.start_call_args (args_so_far);
|
|
+
|
|
+ /* When expanding a normal call, args are stored in push order,
|
|
+ which is the reverse of what we have here. */
|
|
+ bool any_regs = false;
|
|
+ for (int i = nargs; i-- > 0; )
|
|
+ if (argvec[i].reg != NULL_RTX)
|
|
+ {
|
|
+ targetm.calls.call_args (args_so_far, argvec[i].reg, NULL_TREE);
|
|
+ any_regs = true;
|
|
+ }
|
|
+ if (!any_regs)
|
|
+ targetm.calls.call_args (args_so_far, pc_rtx, NULL_TREE);
|
|
+
|
|
/* Now load any reg parms into their regs. */
|
|
|
|
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
|
|
@@ -4671,10 +4679,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|
get_identifier (XSTR (orgfun, 0)),
|
|
build_function_type (tfom, NULL_TREE),
|
|
original_args_size.constant, args_size.constant,
|
|
- struct_value_size,
|
|
- targetm.calls.function_arg (args_so_far,
|
|
- function_arg_info::end_marker ()),
|
|
- valreg,
|
|
+ struct_value_size, call_cookie, valreg,
|
|
old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
|
|
|
|
if (flag_ipa_ra)
|
|
@@ -4694,7 +4699,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|
|
valreg = gen_rtx_REG (TYPE_MODE (tfom), REGNO (valreg));
|
|
}
|
|
|
|
- targetm.calls.end_call_args ();
|
|
+ targetm.calls.end_call_args (args_so_far);
|
|
|
|
/* For calls to `setjmp', etc., inform function.cc:setjmp_warnings
|
|
that it should complain if nonvolatile values are live. For
|
|
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
|
|
index 3634a49de..7f2103ba6 100644
|
|
--- a/gcc/config/nvptx/nvptx.cc
|
|
+++ b/gcc/config/nvptx/nvptx.cc
|
|
@@ -1780,7 +1780,7 @@ nvptx_get_drap_rtx (void)
|
|
argument to the next call. */
|
|
|
|
static void
|
|
-nvptx_call_args (rtx arg, tree fntype)
|
|
+nvptx_call_args (cumulative_args_t, rtx arg, tree fntype)
|
|
{
|
|
if (!cfun->machine->doing_call)
|
|
{
|
|
@@ -1808,7 +1808,7 @@ nvptx_call_args (rtx arg, tree fntype)
|
|
information we recorded. */
|
|
|
|
static void
|
|
-nvptx_end_call_args (void)
|
|
+nvptx_end_call_args (cumulative_args_t)
|
|
{
|
|
cfun->machine->doing_call = false;
|
|
free_EXPR_LIST_list (&cfun->machine->call_args);
|
|
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
|
|
index 369f4b8da..357c29a4d 100644
|
|
--- a/gcc/doc/tm.texi
|
|
+++ b/gcc/doc/tm.texi
|
|
@@ -5392,26 +5392,59 @@ except the last are treated as named.
|
|
You need not define this hook if it always returns @code{false}.
|
|
@end deftypefn
|
|
|
|
-@deftypefn {Target Hook} void TARGET_CALL_ARGS (rtx, @var{tree})
|
|
+@deftypefn {Target Hook} void TARGET_START_CALL_ARGS (cumulative_args_t @var{complete_args})
|
|
+This target hook is invoked while generating RTL for a function call,
|
|
+after the argument values have been computed, and after stack arguments
|
|
+have been initialized, but before register arguments have been moved into
|
|
+their ABI-defined hard register locations. It precedes calls to the related
|
|
+hooks @code{TARGET_CALL_ARGS} and @code{TARGET_END_CALL_ARGS}.
|
|
+The significance of this position in the call expansion is that:
|
|
+
|
|
+@itemize @bullet
|
|
+@item
|
|
+No argument registers are live.
|
|
+@item
|
|
+Although a call sequence can in general involve subcalls (such as using
|
|
+@code{memcpy} to copy large arguments), no such subcall will occur between
|
|
+the call to this hook and the generation of the main call instruction.
|
|
+@end itemize
|
|
+
|
|
+The single argument @var{complete_args} is the state of the target
|
|
+function's cumulative argument information after the final call to
|
|
+@code{TARGET_FUNCTION_ARG}.
|
|
+
|
|
+The hook can be used for things like switching processor mode, in cases
|
|
+where different calls need different processor modes. Most ports do not
|
|
+need to implement anything for this hook.
|
|
+@end deftypefn
|
|
+
|
|
+@deftypefn {Target Hook} void TARGET_CALL_ARGS (cumulative_args_t @var{complete_args}, rtx @var{loc}, tree @var{type})
|
|
While generating RTL for a function call, this target hook is invoked once
|
|
for each argument passed to the function, either a register returned by
|
|
@code{TARGET_FUNCTION_ARG} or a memory location. It is called just
|
|
-before the point where argument registers are stored. The type of the
|
|
-function to be called is also passed as the second argument; it is
|
|
-@code{NULL_TREE} for libcalls. The @code{TARGET_END_CALL_ARGS} hook is
|
|
-invoked just after the code to copy the return reg has been emitted.
|
|
-This functionality can be used to perform special setup of call argument
|
|
-registers if a target needs it.
|
|
+before the point where argument registers are stored.
|
|
+
|
|
+@var{complete_args} is the state of the target function's cumulative
|
|
+argument information after the final call to @code{TARGET_FUNCTION_ARG}.
|
|
+@var{loc} is the location of the argument. @var{type} is the type of
|
|
+the function being called, or @code{NULL_TREE} for libcalls.
|
|
+
|
|
For functions without arguments, the hook is called once with @code{pc_rtx}
|
|
passed instead of an argument register.
|
|
-Most ports do not need to implement anything for this hook.
|
|
+
|
|
+This functionality can be used to perform special setup of call argument
|
|
+registers, if a target needs it. Most ports do not need to implement
|
|
+anything for this hook.
|
|
@end deftypefn
|
|
|
|
-@deftypefn {Target Hook} void TARGET_END_CALL_ARGS (void)
|
|
+@deftypefn {Target Hook} void TARGET_END_CALL_ARGS (cumulative_args_t @var{complete_args})
|
|
This target hook is invoked while generating RTL for a function call,
|
|
just after the point where the return reg is copied into a pseudo. It
|
|
signals that all the call argument and return registers for the just
|
|
-emitted call are now no longer in use.
|
|
+emitted call are now no longer in use. @var{complete_args} is the
|
|
+state of the target function's cumulative argument information after
|
|
+the final call to @code{TARGET_FUNCTION_ARG}.
|
|
+
|
|
Most ports do not need to implement anything for this hook.
|
|
@end deftypefn
|
|
|
|
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
|
|
index 748b0777a..4ebc9afbf 100644
|
|
--- a/gcc/doc/tm.texi.in
|
|
+++ b/gcc/doc/tm.texi.in
|
|
@@ -3774,6 +3774,8 @@ These machine description macros help implement varargs:
|
|
|
|
@hook TARGET_STRICT_ARGUMENT_NAMING
|
|
|
|
+@hook TARGET_START_CALL_ARGS
|
|
+
|
|
@hook TARGET_CALL_ARGS
|
|
|
|
@hook TARGET_END_CALL_ARGS
|
|
diff --git a/gcc/hooks.cc b/gcc/hooks.cc
|
|
index b29233f4f..0f4e7ce10 100644
|
|
--- a/gcc/hooks.cc
|
|
+++ b/gcc/hooks.cc
|
|
@@ -280,11 +280,6 @@ hook_void_FILEptr_tree (FILE *, tree)
|
|
{
|
|
}
|
|
|
|
-void
|
|
-hook_void_rtx_tree (rtx, tree)
|
|
-{
|
|
-}
|
|
-
|
|
void
|
|
hook_void_constcharptr (const char *)
|
|
{
|
|
diff --git a/gcc/hooks.h b/gcc/hooks.h
|
|
index 1056e1e9e..e2a742f43 100644
|
|
--- a/gcc/hooks.h
|
|
+++ b/gcc/hooks.h
|
|
@@ -83,7 +83,6 @@ extern void hook_void_FILEptr_constcharptr (FILE *, const char *);
|
|
extern void hook_void_FILEptr_constcharptr_const_tree (FILE *, const char *,
|
|
const_tree);
|
|
extern bool hook_bool_FILEptr_rtx_false (FILE *, rtx);
|
|
-extern void hook_void_rtx_tree (rtx, tree);
|
|
extern void hook_void_FILEptr_tree (FILE *, tree);
|
|
extern void hook_void_tree (tree);
|
|
extern void hook_void_tree_treeptr (tree, tree *);
|
|
diff --git a/gcc/target.def b/gcc/target.def
|
|
index cf9f96eba..a57e51b0d 100644
|
|
--- a/gcc/target.def
|
|
+++ b/gcc/target.def
|
|
@@ -4784,32 +4784,67 @@ not generate any instructions in this case.",
|
|
int *pretend_args_size, int second_time),
|
|
default_setup_incoming_varargs)
|
|
|
|
+DEFHOOK
|
|
+(start_call_args,
|
|
+ "This target hook is invoked while generating RTL for a function call,\n\
|
|
+after the argument values have been computed, and after stack arguments\n\
|
|
+have been initialized, but before register arguments have been moved into\n\
|
|
+their ABI-defined hard register locations. It precedes calls to the related\n\
|
|
+hooks @code{TARGET_CALL_ARGS} and @code{TARGET_END_CALL_ARGS}.\n\
|
|
+The significance of this position in the call expansion is that:\n\
|
|
+\n\
|
|
+@itemize @bullet\n\
|
|
+@item\n\
|
|
+No argument registers are live.\n\
|
|
+@item\n\
|
|
+Although a call sequence can in general involve subcalls (such as using\n\
|
|
+@code{memcpy} to copy large arguments), no such subcall will occur between\n\
|
|
+the call to this hook and the generation of the main call instruction.\n\
|
|
+@end itemize\n\
|
|
+\n\
|
|
+The single argument @var{complete_args} is the state of the target\n\
|
|
+function's cumulative argument information after the final call to\n\
|
|
+@code{TARGET_FUNCTION_ARG}.\n\
|
|
+\n\
|
|
+The hook can be used for things like switching processor mode, in cases\n\
|
|
+where different calls need different processor modes. Most ports do not\n\
|
|
+need to implement anything for this hook.",
|
|
+ void, (cumulative_args_t complete_args),
|
|
+ hook_void_CUMULATIVE_ARGS)
|
|
+
|
|
DEFHOOK
|
|
(call_args,
|
|
"While generating RTL for a function call, this target hook is invoked once\n\
|
|
for each argument passed to the function, either a register returned by\n\
|
|
@code{TARGET_FUNCTION_ARG} or a memory location. It is called just\n\
|
|
-before the point where argument registers are stored. The type of the\n\
|
|
-function to be called is also passed as the second argument; it is\n\
|
|
-@code{NULL_TREE} for libcalls. The @code{TARGET_END_CALL_ARGS} hook is\n\
|
|
-invoked just after the code to copy the return reg has been emitted.\n\
|
|
-This functionality can be used to perform special setup of call argument\n\
|
|
-registers if a target needs it.\n\
|
|
+before the point where argument registers are stored.\n\
|
|
+\n\
|
|
+@var{complete_args} is the state of the target function's cumulative\n\
|
|
+argument information after the final call to @code{TARGET_FUNCTION_ARG}.\n\
|
|
+@var{loc} is the location of the argument. @var{type} is the type of\n\
|
|
+the function being called, or @code{NULL_TREE} for libcalls.\n\
|
|
+\n\
|
|
For functions without arguments, the hook is called once with @code{pc_rtx}\n\
|
|
passed instead of an argument register.\n\
|
|
-Most ports do not need to implement anything for this hook.",
|
|
- void, (rtx, tree),
|
|
- hook_void_rtx_tree)
|
|
+\n\
|
|
+This functionality can be used to perform special setup of call argument\n\
|
|
+registers, if a target needs it. Most ports do not need to implement\n\
|
|
+anything for this hook.",
|
|
+ void, (cumulative_args_t complete_args, rtx loc, tree type),
|
|
+ hook_void_CUMULATIVE_ARGS_rtx_tree)
|
|
|
|
DEFHOOK
|
|
(end_call_args,
|
|
"This target hook is invoked while generating RTL for a function call,\n\
|
|
just after the point where the return reg is copied into a pseudo. It\n\
|
|
signals that all the call argument and return registers for the just\n\
|
|
-emitted call are now no longer in use.\n\
|
|
+emitted call are now no longer in use. @var{complete_args} is the\n\
|
|
+state of the target function's cumulative argument information after\n\
|
|
+the final call to @code{TARGET_FUNCTION_ARG}.\n\
|
|
+\n\
|
|
Most ports do not need to implement anything for this hook.",
|
|
- void, (void),
|
|
- hook_void_void)
|
|
+ void, (cumulative_args_t complete_args),
|
|
+ hook_void_CUMULATIVE_ARGS)
|
|
|
|
DEFHOOK
|
|
(push_argument,
|
|
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
|
|
index 399d6f874..c88afa5db 100644
|
|
--- a/gcc/targhooks.cc
|
|
+++ b/gcc/targhooks.cc
|
|
@@ -772,12 +772,22 @@ hook_int_CUMULATIVE_ARGS_arg_info_0 (cumulative_args_t,
|
|
return 0;
|
|
}
|
|
|
|
+void
|
|
+hook_void_CUMULATIVE_ARGS (cumulative_args_t)
|
|
+{
|
|
+}
|
|
+
|
|
void
|
|
hook_void_CUMULATIVE_ARGS_tree (cumulative_args_t ca ATTRIBUTE_UNUSED,
|
|
tree ATTRIBUTE_UNUSED)
|
|
{
|
|
}
|
|
|
|
+void
|
|
+hook_void_CUMULATIVE_ARGS_rtx_tree (cumulative_args_t, rtx, tree)
|
|
+{
|
|
+}
|
|
+
|
|
/* Default implementation of TARGET_PUSH_ARGUMENT. */
|
|
|
|
bool
|
|
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
|
|
index ecce55ebe..c6e12fc2e 100644
|
|
--- a/gcc/targhooks.h
|
|
+++ b/gcc/targhooks.h
|
|
@@ -138,8 +138,9 @@ extern bool hook_bool_CUMULATIVE_ARGS_arg_info_true
|
|
(cumulative_args_t, const function_arg_info &);
|
|
extern int hook_int_CUMULATIVE_ARGS_arg_info_0
|
|
(cumulative_args_t, const function_arg_info &);
|
|
-extern void hook_void_CUMULATIVE_ARGS_tree
|
|
- (cumulative_args_t, tree);
|
|
+extern void hook_void_CUMULATIVE_ARGS (cumulative_args_t);
|
|
+extern void hook_void_CUMULATIVE_ARGS_tree (cumulative_args_t, tree);
|
|
+extern void hook_void_CUMULATIVE_ARGS_rtx_tree (cumulative_args_t, rtx, tree);
|
|
extern const char *hook_invalid_arg_for_unprototyped_fn
|
|
(const_tree, const_tree, const_tree);
|
|
extern void default_function_arg_advance
|
|
--
|
|
2.33.0
|
|
|