diff --git a/gcc/calls.cc b/gcc/calls.cc index cc4210cd456..4a1aea1cf01 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -3563,15 +3563,26 @@ expand_call (tree exp, rtx target, int ignore) sibcall_failure = true; } + /* 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; @@ -3634,15 +3645,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; @@ -3941,7 +3943,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 (); @@ -4499,17 +4501,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. */ @@ -4627,6 +4621,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 @@ -4733,10 +4741,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) @@ -4756,7 +4761,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 992d005e5b6..ae20802c879 100644 --- a/gcc/config/nvptx/nvptx.cc +++ b/gcc/config/nvptx/nvptx.cc @@ -1791,7 +1791,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) { @@ -1819,7 +1819,7 @@ nvptx_call_args (rtx arg, tree fntype) information we recorded. */ static void -nvptx_end_call_args (void) +nvptx_end_call_args (cumulative_args_t) { cfun->machine->doing_call = false; free_EXPR_LIST_list (&cfun->machine->call_args); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index bc8ee04d7d5..1246ed12ca5 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -5503,26 +5503,59 @@ except the last are treated as named. You need not define this hook if it always returns @code{false}. @end deftypefn -@deftypefn {Target Hook} void TARGET_CALL_ARGS (rtx, @var{tree}) +@deftypefn {Target Hook} void TARGET_START_CALL_ARGS (cumulative_args_t @var{complete_args}) +This target hook is invoked while generating RTL for a function call, +after the argument values have been computed, and after stack arguments +have been initialized, but before register arguments have been moved into +their ABI-defined hard register locations. It precedes calls to the related +hooks @code{TARGET_CALL_ARGS} and @code{TARGET_END_CALL_ARGS}. +The significance of this position in the call expansion is that: + +@itemize @bullet +@item +No argument registers are live. +@item +Although a call sequence can in general involve subcalls (such as using +@code{memcpy} to copy large arguments), no such subcall will occur between +the call to this hook and the generation of the main call instruction. +@end itemize + +The single argument @var{complete_args} is the state of the target +function's cumulative argument information after the final call to +@code{TARGET_FUNCTION_ARG}. + +The hook can be used for things like switching processor mode, in cases +where different calls need different processor modes. Most ports do not +need to implement anything for this hook. +@end deftypefn + +@deftypefn {Target Hook} void TARGET_CALL_ARGS (cumulative_args_t @var{complete_args}, rtx @var{loc}, tree @var{type}) While generating RTL for a function call, this target hook is invoked once for each argument passed to the function, either a register returned by @code{TARGET_FUNCTION_ARG} or a memory location. It is called just -before the point where argument registers are stored. The type of the -function to be called is also passed as the second argument; it is -@code{NULL_TREE} for libcalls. The @code{TARGET_END_CALL_ARGS} hook is -invoked just after the code to copy the return reg has been emitted. -This functionality can be used to perform special setup of call argument -registers if a target needs it. +before the point where argument registers are stored. + +@var{complete_args} is the state of the target function's cumulative +argument information after the final call to @code{TARGET_FUNCTION_ARG}. +@var{loc} is the location of the argument. @var{type} is the type of +the function being called, or @code{NULL_TREE} for libcalls. + For functions without arguments, the hook is called once with @code{pc_rtx} passed instead of an argument register. -Most ports do not need to implement anything for this hook. + +This functionality can be used to perform special setup of call argument +registers, if a target needs it. Most ports do not need to implement +anything for this hook. @end deftypefn -@deftypefn {Target Hook} void TARGET_END_CALL_ARGS (void) +@deftypefn {Target Hook} void TARGET_END_CALL_ARGS (cumulative_args_t @var{complete_args}) This target hook is invoked while generating RTL for a function call, just after the point where the return reg is copied into a pseudo. It signals that all the call argument and return registers for the just -emitted call are now no longer in use. +emitted call are now no longer in use. @var{complete_args} is the +state of the target function's cumulative argument information after +the final call to @code{TARGET_FUNCTION_ARG}. + Most ports do not need to implement anything for this hook. @end deftypefn diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 5f636abf9fc..2b4d2839c1f 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3837,6 +3837,8 @@ These machine description macros help implement varargs: @hook TARGET_STRICT_ARGUMENT_NAMING +@hook TARGET_START_CALL_ARGS + @hook TARGET_CALL_ARGS @hook TARGET_END_CALL_ARGS diff --git a/gcc/hooks.cc b/gcc/hooks.cc index e83add43289..fe59bbd7d26 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 6aa01fc23cc..3a02b6c8ac5 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 427fe526b5a..4addee1ab03 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4819,32 +4819,67 @@ not generate any instructions in this case.", int *pretend_args_size, int second_time), default_setup_incoming_varargs) +DEFHOOK +(start_call_args, + "This target hook is invoked while generating RTL for a function call,\n\ +after the argument values have been computed, and after stack arguments\n\ +have been initialized, but before register arguments have been moved into\n\ +their ABI-defined hard register locations. It precedes calls to the related\n\ +hooks @code{TARGET_CALL_ARGS} and @code{TARGET_END_CALL_ARGS}.\n\ +The significance of this position in the call expansion is that:\n\ +\n\ +@itemize @bullet\n\ +@item\n\ +No argument registers are live.\n\ +@item\n\ +Although a call sequence can in general involve subcalls (such as using\n\ +@code{memcpy} to copy large arguments), no such subcall will occur between\n\ +the call to this hook and the generation of the main call instruction.\n\ +@end itemize\n\ +\n\ +The single argument @var{complete_args} is the state of the target\n\ +function's cumulative argument information after the final call to\n\ +@code{TARGET_FUNCTION_ARG}.\n\ +\n\ +The hook can be used for things like switching processor mode, in cases\n\ +where different calls need different processor modes. Most ports do not\n\ +need to implement anything for this hook.", + void, (cumulative_args_t complete_args), + hook_void_CUMULATIVE_ARGS) + DEFHOOK (call_args, "While generating RTL for a function call, this target hook is invoked once\n\ for each argument passed to the function, either a register returned by\n\ @code{TARGET_FUNCTION_ARG} or a memory location. It is called just\n\ -before the point where argument registers are stored. The type of the\n\ -function to be called is also passed as the second argument; it is\n\ -@code{NULL_TREE} for libcalls. The @code{TARGET_END_CALL_ARGS} hook is\n\ -invoked just after the code to copy the return reg has been emitted.\n\ -This functionality can be used to perform special setup of call argument\n\ -registers if a target needs it.\n\ +before the point where argument registers are stored.\n\ +\n\ +@var{complete_args} is the state of the target function's cumulative\n\ +argument information after the final call to @code{TARGET_FUNCTION_ARG}.\n\ +@var{loc} is the location of the argument. @var{type} is the type of\n\ +the function being called, or @code{NULL_TREE} for libcalls.\n\ +\n\ For functions without arguments, the hook is called once with @code{pc_rtx}\n\ passed instead of an argument register.\n\ -Most ports do not need to implement anything for this hook.", - void, (rtx, tree), - hook_void_rtx_tree) +\n\ +This functionality can be used to perform special setup of call argument\n\ +registers, if a target needs it. Most ports do not need to implement\n\ +anything for this hook.", + void, (cumulative_args_t complete_args, rtx loc, tree type), + hook_void_CUMULATIVE_ARGS_rtx_tree) DEFHOOK (end_call_args, "This target hook is invoked while generating RTL for a function call,\n\ just after the point where the return reg is copied into a pseudo. It\n\ signals that all the call argument and return registers for the just\n\ -emitted call are now no longer in use.\n\ +emitted call are now no longer in use. @var{complete_args} is the\n\ +state of the target function's cumulative argument information after\n\ +the final call to @code{TARGET_FUNCTION_ARG}.\n\ +\n\ Most ports do not need to implement anything for this hook.", - void, (void), - hook_void_void) + void, (cumulative_args_t complete_args), + hook_void_CUMULATIVE_ARGS) DEFHOOK (push_argument, diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc index a2dc7331c24..afe91fe1d17 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -780,12 +780,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 26695abe41e..5a39e8e6d54 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -142,8 +142,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