Message ID | mptbkpdsbev.fsf@arm.com |
---|---|
State | New |
Headers | show |
Series | Add a new target hook: TARGET_START_CALL_ARGS | expand |
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 >
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