aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c59
1 files changed, 44 insertions, 15 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index dfb38ee..0a8688c 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -165,7 +165,7 @@ static void initialize_argument_information PARAMS ((int,
int, tree, tree,
CUMULATIVE_ARGS *,
int, rtx *, int *,
- int *, int *));
+ int *, int *, int));
static void compute_argument_addresses PARAMS ((struct arg_data *,
rtx, int));
static rtx rtx_for_function_call PARAMS ((tree, tree));
@@ -980,7 +980,8 @@ static void
initialize_argument_information (num_actuals, args, args_size, n_named_args,
actparms, fndecl, args_so_far,
reg_parm_stack_space, old_stack_level,
- old_pending_adj, must_preallocate, is_const)
+ old_pending_adj, must_preallocate, is_const,
+ ecf_flags)
int num_actuals ATTRIBUTE_UNUSED;
struct arg_data *args;
struct args_size *args_size;
@@ -993,6 +994,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
int *old_pending_adj;
int *must_preallocate;
int *is_const;
+ int ecf_flags;
{
/* 1 if scanning parms front to back, -1 if scanning back to front. */
int inc;
@@ -1150,8 +1152,19 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
args[i].unsignedp = unsignedp;
args[i].mode = mode;
- args[i].reg = FUNCTION_ARG (*args_so_far, mode, type,
- argpos < n_named_args);
+
+#ifdef FUNCTION_INCOMING_ARG
+ /* If this is a sibling call and the machine has register windows, the
+ register window has to be unwinded before calling the routine, so
+ arguments have to go into the incoming registers. */
+ if (ecf_flags & ECF_SIBCALL)
+ args[i].reg = FUNCTION_INCOMING_ARG (*args_so_far, mode, type,
+ argpos < n_named_args);
+ else
+#endif
+ args[i].reg = FUNCTION_ARG (*args_so_far, mode, type,
+ argpos < n_named_args);
+
#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (args[i].reg)
args[i].partial
@@ -2131,7 +2144,7 @@ expand_call (exp, target, ignore)
call expansion. */
int save_pending_stack_adjust;
rtx insns;
- rtx before_call;
+ rtx before_call, next_arg_reg;
if (pass == 0)
{
@@ -2284,7 +2297,8 @@ expand_call (exp, target, ignore)
n_named_args, actparms, fndecl,
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
- &must_preallocate, &is_const);
+ &must_preallocate, &is_const,
+ (pass == 0) ? ECF_SIBCALL : 0);
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
@@ -2305,6 +2319,13 @@ expand_call (exp, target, ignore)
sibcall_failure = 1;
}
+ if (args_size.constant > current_function_args_size)
+ {
+ /* If this function requires more stack slots than the current
+ function, we cannot change it into a sibling call. */
+ sibcall_failure = 1;
+ }
+
/* Compute the actual size of the argument block required. The variable
and constant sizes must be combined, the size may have to be rounded,
and there may be a minimum required size. When generating a sibcall
@@ -2569,9 +2590,9 @@ expand_call (exp, target, ignore)
{
if (pcc_struct_value)
valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
- fndecl, 0);
+ fndecl, (pass == 0));
else
- valreg = hard_function_value (TREE_TYPE (exp), fndecl, 0);
+ valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0));
}
/* Precompute all register parameters. It isn't safe to compute anything
@@ -2665,14 +2686,24 @@ expand_call (exp, target, 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. */
+#ifdef FUNCTION_INCOMING_ARG
+ if (pass == 0)
+ next_arg_reg = FUNCTION_INCOMING_ARG (args_so_far, VOIDmode,
+ void_type_node, 1);
+ else
+#endif
+ next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode,
+ void_type_node, 1);
+
/* All arguments and registers used for the call must be set up by
now! */
/* Generate the actual call instruction. */
emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
args_size.constant, struct_value_size,
- FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
- valreg, old_inhibit_defer_pop, call_fusage,
+ next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
((is_const ? ECF_IS_CONST : 0)
| (nothrow ? ECF_NOTHROW : 0)
| (pass == 0 ? ECF_SIBCALL : 0)));
@@ -2956,11 +2987,9 @@ expand_call (exp, target, ignore)
{
tail_call_insns = insns;
- /* If the current function's argument block is not large enough
- to hold the outoing arguments, or we encountered some other
- situation we couldn't handle, zero out the sequence. */
- if (current_function_args_size < args_size.constant
- || sibcall_failure)
+ /* If something prevents making this a sibling call,
+ zero out the sequence. */
+ if (sibcall_failure)
tail_call_insns = NULL_RTX;
/* Restore the pending stack adjustment now that we have