(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); 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 /* 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 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 in the area reserved for register arguments, which may be part of
the stack frame. */ the stack frame. */
int needed = args_size.constant; int needed = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Store the maximum argument space used. It will be pushed by the /* Store the maximum argument space used. It will be pushed by the
prologue. prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow checking). */
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 (needed > current_function_outgoing_args_size) if (needed > current_function_outgoing_args_size)
current_function_outgoing_args_size = needed; 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) #if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
/* Since we will be writing into the entire argument area, the /* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */ is the responsibility of the caller. */
needed += reg_parm_stack_space; needed += reg_parm_stack_space;
#endif #endif
#ifdef ARGS_GROW_DOWNWARD #ifdef ARGS_GROW_DOWNWARD
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed + 1); needed + 1);
#else #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 #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) if (initial_highest_arg_in_use)
bcopy (initial_stack_usage_map, stack_usage_map, bcopy (initial_stack_usage_map, stack_usage_map,
initial_highest_arg_in_use); initial_highest_arg_in_use);
if (initial_highest_arg_in_use != highest_outgoing_arg_in_use) if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
bzero (&stack_usage_map[initial_highest_arg_in_use], bzero (&stack_usage_map[initial_highest_arg_in_use],
highest_outgoing_arg_in_use - initial_highest_arg_in_use); highest_outgoing_arg_in_use - initial_highest_arg_in_use);
needed = 0; needed = 0;
/* The address of the outgoing argument list must not be copied to a /* The address of the outgoing argument list must not be copied to a
register here, because argblock would be left pointing to the register here, because argblock would be left pointing to the
wrong place after the call to allocate_dynamic_stack_space below. */ 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 */ #else /* not ACCUMULATE_OUTGOING_ARGS */
if (inhibit_defer_pop == 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; /* Try to reuse some or all of the pending_stack_adjust
pending_stack_adjust = 0; 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 else
{ argblock = push_block (GEN_INT (needed), 0, 0);
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);
/* We only really need to call `copy_to_reg' in the case where push /* 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 insns are going to be used to pass ARGBLOCK to a function
call in ARGS. In that case, the stack pointer changes value call in ARGS. In that case, the stack pointer changes value
from the allocation point to the call point, and hence from the allocation point to the call point, and hence
the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well. the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
But might as well always do it. */ But might as well always do it. */
argblock = copy_to_reg (argblock); argblock = copy_to_reg (argblock);
#endif /* not ACCUMULATE_OUTGOING_ARGS */ #endif /* not ACCUMULATE_OUTGOING_ARGS */
}
} }
#ifdef ACCUMULATE_OUTGOING_ARGS #ifdef ACCUMULATE_OUTGOING_ARGS
/* The save/restore code in store_one_arg handles all cases except one: /* The save/restore code in store_one_arg handles all cases except one:
a constructor call (including a C function returning a BLKmode struct) 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
#endif #endif
#ifdef ACCUMULATE_OUTGOING_ARGS
if (args_size.constant > current_function_outgoing_args_size) if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant; current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
args_size.constant = 0; args_size.constant = 0;
#endif #endif
@ -2623,9 +2629,10 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
#endif #endif
#endif #endif
#ifdef ACCUMULATE_OUTGOING_ARGS
if (args_size.constant > current_function_outgoing_args_size) if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant; current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
args_size.constant = 0; args_size.constant = 0;
#endif #endif