From 2f21e1ba46762bceac682c433028627f6953ed50 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Thu, 6 Nov 2014 17:20:13 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 9 ++++ gcc/calls.c | 104 ++++++++++++++++++++++++++++----------------- gcc/doc/tm.texi | 23 ++++++++++ gcc/doc/tm.texi.in | 4 ++ gcc/hooks.c | 5 +++ gcc/hooks.h | 1 + gcc/target.def | 27 ++++++++++++ 7 files changed, 134 insertions(+), 39 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 085f0b1ec2a..75ab1fa7bbf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,14 @@ 2014-11-06 Bernd Schmidt + * 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 diff --git a/gcc/calls.c b/gcc/calls.c index 43ac5d2f6b3..06b8485ff7f 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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, ®_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 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 7af23e5247a..a55206d6c05 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -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 diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index f739fdfee91..e0c52c8a37a 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -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 diff --git a/gcc/hooks.c b/gcc/hooks.c index b5b158752c2..91e17cd70c2 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -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) { diff --git a/gcc/hooks.h b/gcc/hooks.h index 90b31fb5d18..4006cad3412 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -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); diff --git a/gcc/target.def b/gcc/target.def index 4c02c1113d1..d6198ad3569 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -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\ -- 2.30.2