From: Richard Biener <richard.guenther@gmail.com>
To: Richard Sandiford <richard.sandiford@arm.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] Add a new target hook: TARGET_START_CALL_ARGS
Date: Fri, 18 Nov 2022 14:17:30 +0100 [thread overview]
Message-ID: <CAFiYyc3H6h23pBuADx41V9hDi2jKp6=PBfL8oEbqcpMtuQnq4g@mail.gmail.com> (raw)
In-Reply-To: <mptbkpdsbev.fsf@arm.com>
On Fri, Nov 11, 2022 at 5:29 PM Richard Sandiford via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> 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 pseudos
> 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.
>
> Tested on aarch64-linux-gnu and x86_64-linux-gnu. Also tested by
> building cc1 for nvptx-none. OK to install?
OK.
Thanks,
Richard.
> Richard
>
>
> gcc/
> * doc/gccint/target-macros/implementing-the-varargs-macros.rst:
> Add TARGET_START_CALL_ARGS.
> * doc/gccint/target-macros/tm.rst.in: 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 +-
> .../implementing-the-varargs-macros.rst | 5 ++
> gcc/doc/gccint/target-macros/tm.rst.in | 53 +++++++++++++---
> gcc/hooks.cc | 5 --
> gcc/hooks.h | 1 -
> gcc/target.def | 56 +++++++++++++----
> 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 51b664f1b4d..d3287bcc277 100644
> --- a/gcc/calls.cc
> +++ b/gcc/calls.cc
> @@ -3542,15 +3542,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;
> @@ -3613,15 +3624,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;
> @@ -3920,7 +3922,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 ();
> @@ -4478,17 +4480,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. */
>
> @@ -4606,6 +4600,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
> @@ -4712,10 +4720,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)
> @@ -4735,7 +4740,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 2fe120b3873..0fa0aefe613 100644
> --- a/gcc/config/nvptx/nvptx.cc
> +++ b/gcc/config/nvptx/nvptx.cc
> @@ -1790,7 +1790,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)
> {
> @@ -1818,7 +1818,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/gccint/target-macros/implementing-the-varargs-macros.rst b/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst
> index 1c940945056..8dd1ffab1b4 100644
> --- a/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst
> +++ b/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst
> @@ -91,6 +91,11 @@ These machine description macros help implement varargs:
> :end-before: [TARGET_STRICT_ARGUMENT_NAMING]
>
>
> +.. include:: tm.rst.in
> + :start-after: [TARGET_START_CALL_ARGS]
> + :end-before: [TARGET_START_CALL_ARGS]
> +
> +
> .. include:: tm.rst.in
> :start-after: [TARGET_CALL_ARGS]
> :end-before: [TARGET_CALL_ARGS]
> diff --git a/gcc/doc/gccint/target-macros/tm.rst.in b/gcc/doc/gccint/target-macros/tm.rst.in
> index a19fa38b811..04be4bda3f6 100644
> --- a/gcc/doc/gccint/target-macros/tm.rst.in
> +++ b/gcc/doc/gccint/target-macros/tm.rst.in
> @@ -4346,31 +4346,64 @@
>
> [TARGET_SETUP_INCOMING_VARARGS]
>
> +[TARGET_START_CALL_ARGS]
> +.. function:: void TARGET_START_CALL_ARGS (cumulative_args_t 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 ``TARGET_CALL_ARGS`` and ``TARGET_END_CALL_ARGS``. The significance
> + of this position in the call expansion is that:
> +
> + * No argument registers are live.
> +
> + * Although a call sequence can in general involve subcalls (such as using
> + ``memcpy`` to copy large arguments), no such subcall will occur between
> + the call to this hook and the generation of the main call instruction.
> +
> + The single argument :samp:`complete_args` is the state of the target
> + function's cumulative argument information after the final call to
> + ``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.
> +
> +[TARGET_START_CALL_ARGS]
> +
> [TARGET_CALL_ARGS]
> -.. function:: void TARGET_CALL_ARGS (rtx, tree)
> +.. function:: void TARGET_CALL_ARGS (cumulative_args_t complete_args, rtx loc, tree 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
> ``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
> - ``NULL_TREE`` for libcalls. The ``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.
> +
> + :samp:`complete_args` is the state of the target function's cumulative
> + argument information after the final call to ``TARGET_FUNCTION_ARG``.
> + :samp:`loc` is the location of the argument. :samp:`type` is the type of
> + the function being called, or ``NULL_TREE`` for libcalls.
> +
> For functions without arguments, the hook is called once with ``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.
>
> [TARGET_CALL_ARGS]
>
> [TARGET_END_CALL_ARGS]
> -.. function:: void TARGET_END_CALL_ARGS (void)
> +.. function:: void TARGET_END_CALL_ARGS (cumulative_args_t 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. :samp:`complete_args` is the
> + state of the target function's cumulative argument information after
> + the final call to ``TARGET_FUNCTION_ARG``.
> +
> Most ports do not need to implement anything for this hook.
>
> [TARGET_END_CALL_ARGS]
> diff --git a/gcc/hooks.cc b/gcc/hooks.cc
> index b29233f4f85..0f4e7ce1047 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 1056e1e9e4d..e2a742f4325 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 15fd939200b..e6a388f9675 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -4732,32 +4732,64 @@ 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 ``TARGET_CALL_ARGS`` and ``TARGET_END_CALL_ARGS``. The significance\n\
> +of this position in the call expansion is that:\n\
> +\n\
> +* No argument registers are live.\n\
> +\n\
> +* Although a call sequence can in general involve subcalls (such as using\n\
> + ``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\
> +\n\
> +The single argument :samp:`complete_args` is the state of the target\n\
> +function's cumulative argument information after the final call to\n\
> +``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\
> ``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\
> -``NULL_TREE`` for libcalls. The ``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\
> +:samp:`complete_args` is the state of the target function's cumulative\n\
> +argument information after the final call to ``TARGET_FUNCTION_ARG``.\n\
> +:samp:`loc` is the location of the argument. :samp:`type` is the type of\n\
> +the function being called, or ``NULL_TREE`` for libcalls.\n\
> +\n\
> For functions without arguments, the hook is called once with ``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. :samp:`complete_args` is the\n\
> +state of the target function's cumulative argument information after\n\
> +the final call to ``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 12a58456b39..f8b9a01b817 100644
> --- a/gcc/targhooks.cc
> +++ b/gcc/targhooks.cc
> @@ -773,12 +773,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 a6a423c1abb..1c43cefdcae 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.25.1
>
next prev parent reply other threads:[~2022-11-18 13:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-11 16:28 Richard Sandiford
2022-11-18 13:17 ` Richard Biener [this message]
2023-12-05 9:45 Richard Sandiford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAFiYyc3H6h23pBuADx41V9hDi2jKp6=PBfL8oEbqcpMtuQnq4g@mail.gmail.com' \
--to=richard.guenther@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=richard.sandiford@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).