(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:
parent
c199879dc7
commit
26a258fee2
133
gcc/calls.c
133
gcc/calls.c
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue