gcc/
* target.def (call_args, end_call_args): New hooks.
* hooks.c (hook_void_rtx_tree): New empty function.
* hooks.h (hook_void_rtx_tree): Declare.
* doc/tm.texi.in (TARGET_CALL_ARGS, TARGET_END_CALL_ARGS): Add.
* doc/tm.texi: Regenerate.
* calls.c (expand_call): Slightly rearrange the code. Use the two new
hooks.
(expand_library_call_value_1): Use the two new hooks.
------------------------------------------------------------------------
===================================================================
@@ -4960,6 +4960,29 @@ 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})
+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.
+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.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_END_CALL_ARGS (void)
+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.
+Most ports do not need to implement anything for this hook.
+@end deftypefn
+
@deftypefn {Target Hook} bool TARGET_PRETEND_OUTGOING_VARARGS_NAMED (cumulative_args_t @var{ca})
If you need to conditionally change ABIs so that one works with
@code{TARGET_SETUP_INCOMING_VARARGS}, but the other works like neither
===================================================================
@@ -3856,6 +3856,10 @@ These machine description macros help im
@hook TARGET_STRICT_ARGUMENT_NAMING
+@hook TARGET_CALL_ARGS
+
+@hook TARGET_END_CALL_ARGS
+
@hook TARGET_PRETEND_OUTGOING_VARARGS_NAMED
@node Trampolines
===================================================================
@@ -245,6 +245,11 @@ hook_void_tree (tree a ATTRIBUTE_UNUSED)
}
void
+hook_void_rtx_tree (rtx, tree)
+{
+}
+
+void
hook_void_constcharptr (const char *a ATTRIBUTE_UNUSED)
{
}
===================================================================
@@ -71,6 +71,7 @@ extern void hook_void_constcharptr (cons
extern void hook_void_rtx_insn_int (rtx_insn *, int);
extern void hook_void_FILEptr_constcharptr (FILE *, const char *);
extern bool hook_bool_FILEptr_rtx_false (FILE *, rtx);
+extern void hook_void_rtx_tree (rtx, tree);
extern void hook_void_tree (tree);
extern void hook_void_tree_treeptr (tree, tree *);
extern void hook_void_int_int (int, int);
===================================================================
@@ -3816,6 +3816,33 @@ not generate any instructions in this ca
default_setup_incoming_varargs)
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\
+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)
+
+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\
+Most ports do not need to implement anything for this hook.",
+ void, (void),
+ hook_void_void)
+
+DEFHOOK
(strict_argument_naming,
"Define this hook to return @code{true} if the location where a function\n\
argument is passed depends on whether or not it is a named argument.\n\
===================================================================
@@ -2978,32 +2978,6 @@ expand_call (tree exp, rtx target, int i
funexp = rtx_for_function_call (fndecl, addr);
- /* Figure out the register where the value, if any, will come back. */
- valreg = 0;
- if (TYPE_MODE (rettype) != VOIDmode
- && ! structure_value_addr)
- {
- if (pcc_struct_value)
- valreg = hard_function_value (build_pointer_type (rettype),
- fndecl, NULL, (pass == 0));
- else
- valreg = hard_function_value (rettype, fndecl, fntype,
- (pass == 0));
-
- /* If VALREG is a PARALLEL whose first member has a zero
- offset, use that. This is for targets such as m68k that
- return the same value in multiple places. */
- if (GET_CODE (valreg) == PARALLEL)
- {
- rtx elem = XVECEXP (valreg, 0, 0);
- rtx where = XEXP (elem, 0);
- rtx offset = XEXP (elem, 1);
- if (offset == const0_rtx
- && GET_MODE (where) == GET_MODE (valreg))
- valreg = where;
- }
- }
-
/* Precompute all register parameters. It isn't safe to compute anything
once we have started filling any specific hard regs. */
precompute_register_parameters (num_actuals, args, ®_parm_seen);
@@ -3082,6 +3056,42 @@ expand_call (tree exp, rtx target, int i
sibcall_failure = 1;
}
+ 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);
+ }
+ if (!any_regs)
+ targetm.calls.call_args (pc_rtx, funtype);
+
+ /* Figure out the register where the value, if any, will come back. */
+ valreg = 0;
+ if (TYPE_MODE (rettype) != VOIDmode
+ && ! structure_value_addr)
+ {
+ if (pcc_struct_value)
+ valreg = hard_function_value (build_pointer_type (rettype),
+ fndecl, NULL, (pass == 0));
+ else
+ valreg = hard_function_value (rettype, fndecl, fntype,
+ (pass == 0));
+
+ /* If VALREG is a PARALLEL whose first member has a zero
+ offset, use that. This is for targets such as m68k that
+ return the same value in multiple places. */
+ if (GET_CODE (valreg) == PARALLEL)
+ {
+ rtx elem = XVECEXP (valreg, 0, 0);
+ rtx where = XEXP (elem, 0);
+ rtx offset = XEXP (elem, 1);
+ if (offset == const0_rtx
+ && GET_MODE (where) == GET_MODE (valreg))
+ valreg = where;
+ }
+ }
+
/* If register arguments require space on the stack and stack space
was not preallocated, allocate stack space here for arguments
passed in registers. */
@@ -3430,6 +3440,8 @@ expand_call (tree exp, rtx target, int i
for (i = 0; i < num_actuals; ++i)
free (args[i].aligned_regs);
+ targetm.calls.end_call_args ();
+
insns = get_insns ();
end_sequence ();
@@ -3956,6 +3968,18 @@ emit_library_call_value_1 (int retval, r
}
#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);
+
/* Push the args that need to be pushed. */
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
@@ -4196,6 +4220,8 @@ emit_library_call_value_1 (int retval, r
valreg = gen_rtx_REG (TYPE_MODE (tfom), REGNO (valreg));
}
+ targetm.calls.end_call_args ();
+
/* For calls to `setjmp', etc., inform function.c:setjmp_warnings
that it should complain if nonvolatile values are live. For
functions that cannot return, inform flow that control does not