Add a new target hook: TARGET_START_CALL_ARGS

Message ID mptbkpdsbev.fsf@arm.com
State Accepted
Headers
Series Add a new target hook: TARGET_START_CALL_ARGS |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Richard Sandiford Nov. 11, 2022, 4:28 p.m. UTC
  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?

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

Comments

Richard Biener Nov. 18, 2022, 1:17 p.m. UTC | #1
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
>
  

Patch

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