(expand_call, emit_library_call, emit_library_call_value):

Allways adjust current_function_outgoing_args_size, even #ifndef
ACCUMULATE_OUTGOING_ARGS.  (Useful for stack overflow checking.)

From-SVN: r8290
This commit is contained in:
Per Bothner 1994-10-17 16:08:37 -07:00
parent c199879dc7
commit 26a258fee2
1 changed files with 70 additions and 63 deletions

View File

@ -1353,98 +1353,103 @@ expand_call (exp, target, ignore)
}
argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);
}
else if (must_preallocate)
else
{
/* Note that we must go through the motions of allocating an argument
block even if the size is zero because we may be storing args
in the area reserved for register arguments, which may be part of
the stack frame. */
int needed = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Store the maximum argument space used. It will be pushed by the
prologue.
Since the stack pointer will never be pushed, it is possible for
the evaluation of a parm to clobber something we have already
written to the stack. Since most function calls on RISC machines
do not use the stack, this is uncommon, but must work correctly.
Therefore, we save any area of the stack that was already written
and that we are using. Here we set up to do this by making a new
stack usage map from the old one. The actual save will be done
by store_one_arg.
Another approach might be to try to reorder the argument
evaluations to avoid this conflicting stack usage. */
prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow checking). */
if (needed > current_function_outgoing_args_size)
current_function_outgoing_args_size = needed;
if (must_preallocate)
{
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Since the stack pointer will never be pushed, it is possible for
the evaluation of a parm to clobber something we have already
written to the stack. Since most function calls on RISC machines
do not use the stack, this is uncommon, but must work correctly.
Therefore, we save any area of the stack that was already written
and that we are using. Here we set up to do this by making a new
stack usage map from the old one. The actual save will be done
by store_one_arg.
Another approach might be to try to reorder the argument
evaluations to avoid this conflicting stack usage. */
#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
/* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */
needed += reg_parm_stack_space;
/* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */
needed += reg_parm_stack_space;
#endif
#ifdef ARGS_GROW_DOWNWARD
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed + 1);
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed + 1);
#else
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed);
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed);
#endif
stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
if (initial_highest_arg_in_use)
bcopy (initial_stack_usage_map, stack_usage_map,
initial_highest_arg_in_use);
if (initial_highest_arg_in_use)
bcopy (initial_stack_usage_map, stack_usage_map,
initial_highest_arg_in_use);
if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
bzero (&stack_usage_map[initial_highest_arg_in_use],
highest_outgoing_arg_in_use - initial_highest_arg_in_use);
needed = 0;
if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
bzero (&stack_usage_map[initial_highest_arg_in_use],
highest_outgoing_arg_in_use - initial_highest_arg_in_use);
needed = 0;
/* The address of the outgoing argument list must not be copied to a
register here, because argblock would be left pointing to the
wrong place after the call to allocate_dynamic_stack_space below. */
/* The address of the outgoing argument list must not be copied to a
register here, because argblock would be left pointing to the
wrong place after the call to allocate_dynamic_stack_space below.
*/
argblock = virtual_outgoing_args_rtx;
argblock = virtual_outgoing_args_rtx;
#else /* not ACCUMULATE_OUTGOING_ARGS */
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)
if (inhibit_defer_pop == 0)
{
needed -= pending_stack_adjust;
pending_stack_adjust = 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
{
pending_stack_adjust -= needed;
needed = 0;
}
}
/* Special case this because overhead of `push_block' in this
case is non-trivial. */
if (needed == 0)
argblock = virtual_outgoing_args_rtx;
else
{
pending_stack_adjust -= needed;
needed = 0;
}
}
/* Special case this because overhead of `push_block' in this
case is non-trivial. */
if (needed == 0)
argblock = virtual_outgoing_args_rtx;
else
argblock = push_block (GEN_INT (needed), 0, 0);
argblock = push_block (GEN_INT (needed), 0, 0);
/* We only really need to call `copy_to_reg' in the case where push
insns are going to be used to pass ARGBLOCK to a function
call in ARGS. In that case, the stack pointer changes value
from the allocation point to the call point, and hence
the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
But might as well always do it. */
argblock = copy_to_reg (argblock);
/* We only really need to call `copy_to_reg' in the case where push
insns are going to be used to pass ARGBLOCK to a function
call in ARGS. In that case, the stack pointer changes value
from the allocation point to the call point, and hence
the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
But might as well always do it. */
argblock = copy_to_reg (argblock);
#endif /* not ACCUMULATE_OUTGOING_ARGS */
}
}
#ifdef ACCUMULATE_OUTGOING_ARGS
/* The save/restore code in store_one_arg handles all cases except one:
a constructor call (including a C function returning a BLKmode struct)
@ -2276,9 +2281,10 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
#endif
#endif
#ifdef ACCUMULATE_OUTGOING_ARGS
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
args_size.constant = 0;
#endif
@ -2623,9 +2629,10 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
#endif
#endif
#ifdef ACCUMULATE_OUTGOING_ARGS
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
args_size.constant = 0;
#endif