Add a hook to inform a port about call arguments.

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

From-SVN: r217199
This commit is contained in:
Bernd Schmidt 2014-11-06 17:20:13 +00:00 committed by Bernd Schmidt
parent 11717c64bf
commit 2f21e1ba46
7 changed files with 134 additions and 39 deletions

View File

@ -1,5 +1,14 @@
2014-11-06 Bernd Schmidt <bernds@codesourcery.com>
* 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.
* expr.c (use_reg_mode): Just return for pseudo registers.
* combine.c (try_combine): Don't allow a call as one of the source

View File

@ -3103,45 +3103,6 @@ expand_call (tree exp, rtx target, int ignore)
funexp = rtx_for_function_call (fndecl, addr);
/* Figure out the register where the value, if any, will come back. */
valreg = 0;
valbnd = 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));
if (CALL_WITH_BOUNDS_P (exp))
valbnd = targetm.calls.
chkp_function_value_bounds (build_pointer_type (rettype),
fndecl, (pass == 0));
}
else
{
valreg = hard_function_value (rettype, fndecl, fntype,
(pass == 0));
if (CALL_WITH_BOUNDS_P (exp))
valbnd = targetm.calls.chkp_function_value_bounds (rettype,
fndecl,
(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, &reg_parm_seen);
@ -3223,6 +3184,55 @@ expand_call (tree exp, rtx target, int ignore)
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;
valbnd = 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));
if (CALL_WITH_BOUNDS_P (exp))
valbnd = targetm.calls.
chkp_function_value_bounds (build_pointer_type (rettype),
fndecl, (pass == 0));
}
else
{
valreg = hard_function_value (rettype, fndecl, fntype,
(pass == 0));
if (CALL_WITH_BOUNDS_P (exp))
valbnd = targetm.calls.chkp_function_value_bounds (rettype,
fndecl,
(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;
}
}
/* Store all bounds not passed in registers. */
for (i = 0; i < num_actuals; i++)
{
@ -3582,6 +3592,8 @@ 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 ();
insns = get_insns ();
end_sequence ();
@ -4111,6 +4123,18 @@ 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);
/* Push the args that need to be pushed. */
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
@ -4351,6 +4375,8 @@ 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 ();
/* 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

View File

@ -4976,6 +4976,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

View File

@ -3860,6 +3860,10 @@ These machine description macros help implement varargs:
@hook TARGET_STRICT_ARGUMENT_NAMING
@hook TARGET_CALL_ARGS
@hook TARGET_END_CALL_ARGS
@hook TARGET_PRETEND_OUTGOING_VARARGS_NAMED
@hook TARGET_LOAD_BOUNDS_FOR_ARG

View File

@ -244,6 +244,11 @@ hook_void_tree (tree a ATTRIBUTE_UNUSED)
{
}
void
hook_void_rtx_tree (rtx, tree)
{
}
void
hook_void_constcharptr (const char *a ATTRIBUTE_UNUSED)
{

View File

@ -71,6 +71,7 @@ extern void hook_void_constcharptr (const char *);
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);

View File

@ -4001,6 +4001,33 @@ into the stack. Arguments meaning is similar to\n\
int *pretend_args_size, int second_time),
default_setup_incoming_vararg_bounds)
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\