diff --git a/gcc/calls.c b/gcc/calls.c index 35e600e0982..2002322afa4 100644 --- a/gcc/calls.c +++ b/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