public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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
>

  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).