static int flags_from_decl_or_type PARAMS ((tree));
static rtx try_to_integrate PARAMS ((tree, tree, rtx,
int, tree, rtx));
-static void combine_pending_stack_adjustment_and_call
+static int combine_pending_stack_adjustment_and_call
PARAMS ((int, struct args_size *, int));
#ifdef REG_PARM_STACK_SPACE
/* We need to pop PENDING_STACK_ADJUST bytes. But, if the arguments
wouldn't fill up an even multiple of PREFERRED_UNIT_STACK_BOUNDARY
bytes, then we would need to push some additional bytes to pad the
- arguments. So, we adjust the stack pointer by an amount that will
- leave the stack under-aligned by UNADJUSTED_ARGS_SIZE bytes. Then,
- when the arguments are pushed the stack will be perfectly aligned.
- ARGS_SIZE->CONSTANT is set to the number of bytes that should be
- popped after the call. */
+ arguments. So, we compute an adjust to the stack pointer for an
+ amount that will leave the stack under-aligned by UNADJUSTED_ARGS_SIZE
+ bytes. Then, when the arguments are pushed the stack will be perfectly
+ aligned. ARGS_SIZE->CONSTANT is set to the number of bytes that should
+ be popped after the call. Returns the adjustment. */
-static void
+static int
combine_pending_stack_adjustment_and_call (unadjusted_args_size,
args_size,
preferred_unit_stack_boundary)
args_size->constant
= pending_stack_adjust - adjustment + unadjusted_args_size;
- /* Push the right number of bytes. */
- pending_stack_adjust = adjustment;
- do_pending_stack_adjust ();
+ return adjustment;
}
/* Generate all the code for a function 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
- pattern, do not round up, since we'll be re-using whatever space our
- caller provided. */
- unadjusted_args_size
- = compute_argument_block_size (reg_parm_stack_space, &args_size,
- (pass == 0 ? 0
- : preferred_stack_boundary));
-
/* If the callee pops its own arguments, then it must pop exactly
the same number of arguments as the current function. */
- if (RETURN_POPS_ARGS (fndecl, funtype, unadjusted_args_size)
+ if (RETURN_POPS_ARGS (fndecl, funtype, args_size.constant)
!= RETURN_POPS_ARGS (current_function_decl,
TREE_TYPE (current_function_decl),
current_function_args_size))
if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
start_sequence ();
+ /* 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
+ pattern, do not round up, since we'll be re-using whatever space our
+ caller provided. */
+ unadjusted_args_size
+ = compute_argument_block_size (reg_parm_stack_space, &args_size,
+ (pass == 0 ? 0
+ : preferred_stack_boundary));
+
old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
+
/* The argument block when performing a sibling call is the
incoming argument block. */
if (pass == 0)
argblock = virtual_incoming_args_rtx;
+
/* If we have no actual push instructions, or shouldn't use them,
make space for all args right now. */
-
else if (args_size.var != 0)
{
if (old_stack_level == 0)
if (inhibit_defer_pop == 0)
{
/* Try to reuse some or all of the pending_stack_adjust
- to get this space. Maybe we can avoid any pushing. */
- if (needed > pending_stack_adjust)
- {
- needed -= pending_stack_adjust;
- pending_stack_adjust = 0;
- }
- else
+ to get this space. */
+ needed
+ = (combine_pending_stack_adjustment_and_call
+ (unadjusted_args_size,
+ &args_size,
+ preferred_unit_stack_boundary));
+
+ /* combine_pending_stack_adjustment_and_call computes
+ an adjustment before the arguments are allocated.
+ Account for them and see whether or not the stack
+ needs to go up or down. */
+ needed = unadjusted_args_size - needed;
+
+ if (needed < 0)
{
- pending_stack_adjust -= needed;
+ /* We're releasing stack space. */
+ /* ??? We can avoid any adjustment at all if we're
+ already aligned. FIXME. */
+ pending_stack_adjust = -needed;
+ do_pending_stack_adjust ();
needed = 0;
}
+ else
+ /* We need to allocate space. We'll do that in
+ push_block below. */
+ pending_stack_adjust = 0;
}
- /* Special case this because overhead of `push_block' in this
- case is non-trivial. */
+
+ /* Special case this because overhead of `push_block' in
+ this case is non-trivial. */
if (needed == 0)
argblock = virtual_outgoing_args_rtx;
else
argblock = copy_to_reg (argblock);
/* The save/restore code in store_one_arg handles all
- cases except one:
- a constructor call (including a C function returning
- a BLKmode struct) to initialize an argument. */
+ cases except one: a constructor call (including a C
+ function returning a BLKmode struct) to initialize
+ an argument. */
if (stack_arg_under_construction)
{
#ifndef OUTGOING_REG_PARM_STACK_SPACE
- rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);
+ rtx push_size = GEN_INT (reg_parm_stack_space
+ + args_size.constant);
#else
rtx push_size = GEN_INT (args_size.constant);
#endif
if (old_stack_level == 0)
{
- emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+ emit_stack_save (SAVE_BLOCK, &old_stack_level,
+ NULL_RTX);
old_pending_adj = pending_stack_adjust;
pending_stack_adjust = 0;
- /* stack_arg_under_construction says whether a stack arg is
- being constructed at the old stack level. Pushing the stack
- gets a clean outgoing argument block. */
- old_stack_arg_under_construction = stack_arg_under_construction;
+ /* stack_arg_under_construction says whether a stack
+ arg is being constructed at the old stack level.
+ Pushing the stack gets a clean outgoing argument
+ block. */
+ old_stack_arg_under_construction
+ = stack_arg_under_construction;
stack_arg_under_construction = 0;
/* Make a new map for the new argument list. */
- stack_usage_map = (char *)alloca (highest_outgoing_arg_in_use);
+ stack_usage_map = (char *)
+ alloca (highest_outgoing_arg_in_use);
bzero (stack_usage_map, highest_outgoing_arg_in_use);
highest_outgoing_arg_in_use = 0;
}
- allocate_dynamic_stack_space (push_size, NULL_RTX, BITS_PER_UNIT);
+ allocate_dynamic_stack_space (push_size, NULL_RTX,
+ BITS_PER_UNIT);
}
- /* If argument evaluation might modify the stack pointer, copy the
- address of the argument list to a register. */
+ /* If argument evaluation might modify the stack pointer,
+ copy the address of the argument list to a register. */
for (i = 0; i < num_actuals; i++)
if (args[i].pass_on_stack)
{
if (pending_stack_adjust
&& ! (flags & (ECF_CONST | ECF_PURE))
&& ! inhibit_defer_pop)
- combine_pending_stack_adjustment_and_call
- (unadjusted_args_size,
- &args_size,
- preferred_unit_stack_boundary);
+ {
+ pending_stack_adjust
+ = (combine_pending_stack_adjustment_and_call
+ (unadjusted_args_size,
+ &args_size,
+ preferred_unit_stack_boundary));
+ do_pending_stack_adjust ();
+ }
else if (argblock == 0)
anti_adjust_stack (GEN_INT (args_size.constant
- unadjusted_args_size));
now! */
#ifdef PREFERRED_STACK_BOUNDARY
- /* Stack must to be properly aligned now. */
- if (stack_pointer_delta & (preferred_stack_boundary / BITS_PER_UNIT - 1))
+ /* Stack must be properly aligned now. */
+ if (pass && stack_pointer_delta % preferred_unit_stack_boundary)
abort();
#endif
? hard_libcall_value (outmode) : NULL_RTX);
#ifdef PREFERRED_STACK_BOUNDARY
- /* Stack must to be properly aligned now. */
+ /* Stack must be properly aligned now. */
if (stack_pointer_delta & (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1))
abort();
#endif