diff options
31 files changed, 724 insertions, 553 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 226c83b..72b5fe9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,47 @@ +Wed Mar 29 15:08:01 MET DST 2000 Jan Hubicka <jh@suse.cz> + + Convert ACCUMULATE_OUTGOING_ARGS to an expression. + * calls.c (PUSH_ARGS_REVERSED) Change to expression. + (ACCUMULATE_OUTGOING_ARGS, PUSH_ARGS): Provide default value. + (struct arg_data): Remove #ifdef ACCUMULATE_OUTGOING_ARGS. + (save_fixed_argument_area, restore_fixed_argument_area): + conditionize by #ifdef REG_PARM_STACK_SPACE only. + (emit_call): Change #ifdefs on ACCUMULATE_OUTGOING_ARGS + to conditions, handle RETURN_POPS_ARGS on ACCUMULATE_OUTGOING_ARGS. + (precompute_register_parameters): Avoid #ifdefs on + ACCUMULATE_OUTGOING_ARGS and PUSH_ARGS_REVERSED. + (stire_one_args): Likewise. + (expand_call): Likewise; conditionize PUSH_ROUNDING code by PUSH_ARGS. + (emit_library_call_value_1): Likewise. + (compute_argument_block_size): Align to STACK_BOUNDARY only for + ACCUMULATE_OUTGOING_ARGS. + * combine.c (ACCUMULATE_OUTGOING_ARGS, PUSH_ARGS): Provide default + value. + (nonzero_bits): Conditionize PUSH_ROUNDING code by USE_PUSH. + (use_crosses_set_p): Likewise. + * all targets (ACCUMULATE_OUTGOING_ARGS define): Change to + #define ACCUMULATE_OUTGOING_ARGS 1. + * i386.c (ix86_compute_frame_size): Handle ACCUMULATE_OUTGOING_ARGS + frames. + * i386.h (MASK_NO_PUSH_ARGS, MASK_ACCUMULATE_OUTGOING_ARGS): New + constants. + (TARGET_PUSH_ARGS, TARGET_ACCUMULATE_OUTGOING_ARGS): New macros. + (TARGET_SWITCHES): Add push-args, no-push-args, + accumulate-outgoing-args and no-accumulate-outgoing-args. + (ACCUMULATE_OUTGOING_ARGS, PUSH_ARGS): New macro. + * expr.c (ACCUMULATE_OUTGONG_ARGS, PUSH_ARGS): Provide default. + (push_block): Avoid ifdefs on ACCUMULATE_OUTGONG_ARGS + and PUSH_ROUNDING. + (emit_push_insn): Likewise. + * final.c (ACCUMULATE_OUTGOING_ARGS): Provide default. + (final_scan_insn): Avoid ifdefs on ACCUMULATE_OUTGOING_ARGS. + * function.c (ACCUMULATE_OUTGOING_ARGS): Provide default. + (STACK_DYNAMIC_OFFSET): Define correctly for both + ACCUMULATE_OUTGOING_ARGS and normal mode. + * invoke.texi (-mpush_args, -maccumulate-outgoing-args): Document. + * tm.texi (PUSH_ARGS): Document. + (ACCUMULATE_OUTGOING_ARGS, PUSH_ROUNDING): Update documentation. + Wed Mar 29 11:51:13 MET DST 2000 Jan Hubicka <jh@suse.cz> * flags.h (flag_optimize_sibling_calls): Declare. diff --git a/gcc/calls.c b/gcc/calls.c index a978dd4..b0a65f1 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -32,6 +32,19 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "tm_p.h" +#ifndef ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 0 +#endif + +/* Supply a default definition for PUSH_ARGS. */ +#ifndef PUSH_ARGS +#ifdef PUSH_ROUNDING +#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS +#else +#define PUSH_ARGS 0 +#endif +#endif + #if !defined FUNCTION_OK_FOR_SIBCALL #define FUNCTION_OK_FOR_SIBCALL(DECL) 1 #endif @@ -49,11 +62,15 @@ Boston, MA 02111-1307, USA. */ #ifdef PUSH_ROUNDING #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD) -#define PUSH_ARGS_REVERSED /* If it's last to first */ +#define PUSH_ARGS_REVERSED PUSH_ARGS #endif #endif +#ifndef PUSH_ARGS_REVERSED +#define PUSH_ARGS_REVERSED 0 +#endif + /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) @@ -101,10 +118,8 @@ struct arg_data differ from STACK if this arg pads downward. This location is known to be aligned to FUNCTION_ARG_BOUNDARY. */ rtx stack_slot; -#ifdef ACCUMULATE_OUTGOING_ARGS /* Place that this stack area has been saved, if needed. */ rtx save_area; -#endif /* If an argument's alignment does not permit direct copying into registers, copy in smaller-sized pieces into pseudos. These are stored in a block pointed to by this field. The next field says how many @@ -116,7 +131,6 @@ struct arg_data struct args_size alignment_pad; }; -#ifdef ACCUMULATE_OUTGOING_ARGS /* A vector of one char per byte of stack space. A byte if non-zero if the corresponding stack location has been used. This vector is used to prevent a function call within an argument from @@ -132,7 +146,6 @@ static int highest_outgoing_arg_in_use; to make sure the object being constructed does not overlap the argument list for the constructor call. */ int stack_arg_under_construction; -#endif static int calls_function PARAMS ((tree, int)); static int calls_function_1 PARAMS ((tree, int)); @@ -176,7 +189,7 @@ static rtx emit_library_call_value_1 PARAMS ((int, rtx, rtx, int, enum machine_mode, int, va_list)); -#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) +#ifdef REG_PARM_STACK_SPACE static rtx save_fixed_argument_area PARAMS ((int, rtx, int *, int *)); static void restore_fixed_argument_area PARAMS ((rtx, rtx, int, int)); #endif @@ -413,10 +426,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, rtx struct_value_size_rtx = GEN_INT (struct_value_size); #endif rtx call_insn; -#ifndef ACCUMULATE_OUTGOING_ARGS int already_popped = 0; HOST_WIDE_INT n_popped = RETURN_POPS_ARGS (fndecl, funtype, stack_size); -#endif /* Ensure address is valid. SYMBOL_REF is already valid, so no need, and we don't want to load it into a register as an optimization, @@ -424,7 +435,6 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, if (GET_CODE (funexp) != SYMBOL_REF) funexp = memory_address (FUNCTION_MODE, funexp); -#ifndef ACCUMULATE_OUTGOING_ARGS #if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop) if ((ecf_flags & ECF_SIBCALL) && HAVE_sibcall_pop && HAVE_sibcall_value_pop @@ -459,7 +469,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, even if the call has no arguments to pop. */ #if defined (HAVE_call) && defined (HAVE_call_value) if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop - && n_popped > 0) + && n_popped > 0) #else if (HAVE_call_pop && HAVE_call_value_pop) #endif @@ -483,7 +493,6 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, } else #endif -#endif #if defined (HAVE_sibcall) && defined (HAVE_sibcall_value) if ((ecf_flags & ECF_SIBCALL) @@ -559,18 +568,6 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, if the context of the call as a whole permits. */ inhibit_defer_pop = old_inhibit_defer_pop; -#ifndef ACCUMULATE_OUTGOING_ARGS - /* If returning from the subroutine does not automatically pop the args, - we need an instruction to pop them sooner or later. - Perhaps do it now; perhaps just record how much space to pop later. - - If returning from the subroutine does pop the args, indicate that the - stack pointer will be changed. */ - - /* The space for the args is no longer waiting for the call; either it - was popped by the call, or it'll be popped below. */ - arg_space_so_far -= rounded_stack_size; - if (n_popped > 0) { if (!already_popped) @@ -582,15 +579,41 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, rounded_stack_size_rtx = GEN_INT (rounded_stack_size); } - if (rounded_stack_size != 0) + if (!ACCUMULATE_OUTGOING_ARGS) { - if (flag_defer_pop && inhibit_defer_pop == 0 - && !(ecf_flags & ECF_IS_CONST)) - pending_stack_adjust += rounded_stack_size; - else - adjust_stack (rounded_stack_size_rtx); + /* If returning from the subroutine does not automatically pop the args, + we need an instruction to pop them sooner or later. + Perhaps do it now; perhaps just record how much space to pop later. + + If returning from the subroutine does pop the args, indicate that the + stack pointer will be changed. */ + + /* The space for the args is no longer waiting for the call; either it + was popped by the call, or it'll be popped below. */ + arg_space_so_far -= rounded_stack_size - n_popped; + + if (rounded_stack_size != 0) + { + if (flag_defer_pop && inhibit_defer_pop == 0 + && !(ecf_flags & ECF_IS_CONST)) + pending_stack_adjust += rounded_stack_size; + else + adjust_stack (rounded_stack_size_rtx); + } } -#endif + /* When we accumulate outgoing args, we must avoid any stack manipulations. + Restore the stack pointer to its original value now. Usually + ACCUMULATE_OUTGOING_ARGS targets don't get here, but there are exceptions. + On i386 ACCUMULATE_OUTGOING_ARGS can be enabled on demand, and + popping variants of functions exist as well. + + ??? We may optimize similar to defer_pop above, but it is + probably not worthwhile. + + ??? It will be worthwhile to enable combine_stack_adjustments even for + such machines. */ + else if (n_popped) + anti_adjust_stack (GEN_INT (n_popped)); } /* Determine if the function identified by NAME and FNDECL is one with @@ -774,7 +797,7 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen) } } -#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) +#ifdef REG_PARM_STACK_SPACE /* The argument list is the property of the called routine and it may clobber it. If the fixed area has been used for previous @@ -1013,13 +1036,16 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args, We fill up ARGS from the front or from the back if necessary so that in any case the first arg to be pushed ends up at the front. */ -#ifdef PUSH_ARGS_REVERSED - i = num_actuals - 1, inc = -1; - /* In this case, must reverse order of args - so that we compute and push the last arg first. */ -#else - i = 0, inc = 1; -#endif + if (PUSH_ARGS_REVERSED) + { + i = num_actuals - 1, inc = -1; + /* In this case, must reverse order of args + so that we compute and push the last arg first. */ + } + else + { + i = 0, inc = 1; + } /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++) @@ -1262,6 +1288,14 @@ compute_argument_block_size (reg_parm_stack_space, args_size, { int unadjusted_args_size = args_size->constant; + /* For accumulate outgoing args mode we don't need to align, since the frame + will be already aligned. Align to STACK_BOUNDARY in order to prevent + backends from generating missaligned frame sizes. */ +#ifdef STACK_BOUNDARY + if (ACCUMULATE_OUTGOING_ARGS && preferred_stack_boundary > STACK_BOUNDARY) + preferred_stack_boundary = STACK_BOUNDARY; +#endif + /* 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. */ @@ -1692,9 +1726,7 @@ expand_call (exp, target, ignore) or 0 if the function is computed (not known by name). */ tree fndecl = 0; char *name = 0; -#ifdef ACCUMULATE_OUTGOING_ARGS rtx before_call; -#endif rtx insn; int try_tail_call; int pass; @@ -1744,11 +1776,7 @@ expand_call (exp, target, ignore) So the entire argument block must then be preallocated (i.e., we ignore PUSH_ROUNDING in that case). */ -#ifdef PUSH_ROUNDING - int must_preallocate = 0; -#else - int must_preallocate = 1; -#endif + int must_preallocate = !PUSH_ARGS; /* Size of the stack reserved for parameter registers. */ int reg_parm_stack_space = 0; @@ -1777,18 +1805,16 @@ expand_call (exp, target, ignore) int is_volatile = 0; /* Nonzero if this is a call to a function that won't throw an exception. */ int nothrow = TREE_NOTHROW (exp); -#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) +#ifdef REG_PARM_STACK_SPACE /* Define the boundary of the register parm stack space that needs to be save, if any. */ int low_to_save = -1, high_to_save; rtx save_area = 0; /* Place that it is saved */ #endif -#ifdef ACCUMULATE_OUTGOING_ARGS int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; int old_stack_arg_under_construction = 0; -#endif rtx old_stack_level = 0; int old_pending_adj = 0; @@ -1866,8 +1892,8 @@ expand_call (exp, target, ignore) #endif #endif -#if defined(PUSH_ROUNDING) && ! defined(OUTGOING_REG_PARM_STACK_SPACE) - if (reg_parm_stack_space > 0) +#ifndef OUTGOING_REG_PARM_STACK_SPACE + if (reg_parm_stack_space > 0 && PUSH_ARGS) must_preallocate = 1; #endif @@ -1935,9 +1961,7 @@ expand_call (exp, target, ignore) { rtx temp; -#ifdef ACCUMULATE_OUTGOING_ARGS before_call = get_last_insn (); -#endif temp = expand_inline_function (fndecl, actparms, target, ignore, TREE_TYPE (exp), @@ -1946,64 +1970,65 @@ expand_call (exp, target, ignore) /* If inlining succeeded, return. */ if (temp != (rtx) (HOST_WIDE_INT) -1) { -#ifdef ACCUMULATE_OUTGOING_ARGS - /* If the outgoing argument list must be preserved, push - the stack before executing the inlined function if it - makes any calls. */ + if (ACCUMULATE_OUTGOING_ARGS) + { + /* If the outgoing argument list must be preserved, push + the stack before executing the inlined function if it + makes any calls. */ - for (i = reg_parm_stack_space - 1; i >= 0; i--) - if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0) - break; + for (i = reg_parm_stack_space - 1; i >= 0; i--) + if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0) + break; - if (stack_arg_under_construction || i >= 0) - { - rtx first_insn - = before_call ? NEXT_INSN (before_call) : get_insns (); - rtx insn = NULL_RTX, seq; + if (stack_arg_under_construction || i >= 0) + { + rtx first_insn + = before_call ? NEXT_INSN (before_call) : get_insns (); + rtx insn = NULL_RTX, seq; - /* Look for a call in the inline function code. - If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is - nonzero then there is a call and it is not necessary - to scan the insns. */ + /* Look for a call in the inline function code. + If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is + nonzero then there is a call and it is not necessary + to scan the insns. */ - if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0) - for (insn = first_insn; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN) - break; + if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0) + for (insn = first_insn; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == CALL_INSN) + break; - if (insn) - { - /* Reserve enough stack space so that the largest - argument list of any function call in the inline - function does not overlap the argument list being - evaluated. This is usually an overestimate because - allocate_dynamic_stack_space reserves space for an - outgoing argument list in addition to the requested - space, but there is no way to ask for stack space such - that an argument list of a certain length can be - safely constructed. - - Add the stack space reserved for register arguments, if - any, in the inline function. What is really needed is the - largest value of reg_parm_stack_space in the inline - function, but that is not available. Using the current - value of reg_parm_stack_space is wrong, but gives - correct results on all supported machines. */ - - int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size - + reg_parm_stack_space); - - start_sequence (); - emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); - allocate_dynamic_stack_space (GEN_INT (adjust), - NULL_RTX, BITS_PER_UNIT); - seq = get_insns (); - end_sequence (); - emit_insns_before (seq, first_insn); - emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); + if (insn) + { + /* Reserve enough stack space so that the largest + argument list of any function call in the inline + function does not overlap the argument list being + evaluated. This is usually an overestimate because + allocate_dynamic_stack_space reserves space for an + outgoing argument list in addition to the requested + space, but there is no way to ask for stack space such + that an argument list of a certain length can be + safely constructed. + + Add the stack space reserved for register arguments, if + any, in the inline function. What is really needed is the + largest value of reg_parm_stack_space in the inline + function, but that is not available. Using the current + value of reg_parm_stack_space is wrong, but gives + correct results on all supported machines. */ + + int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size + + reg_parm_stack_space); + + start_sequence (); + emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); + allocate_dynamic_stack_space (GEN_INT (adjust), + NULL_RTX, BITS_PER_UNIT); + seq = get_insns (); + end_sequence (); + emit_insns_before (seq, first_insn); + emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); + } } } -#endif /* If the result is equivalent to TARGET, return TARGET to simplify checks in store_expr. They can be equivalent but not equal in the @@ -2260,10 +2285,9 @@ expand_call (exp, target, ignore) If it is virtual_outgoing_args_rtx, we must copy it to another register in some cases. */ rtx temp = (GET_CODE (structure_value_addr) != REG -#ifdef ACCUMULATE_OUTGOING_ARGS - || (stack_arg_under_construction + || (ACCUMULATE_OUTGOING_ARGS + && stack_arg_under_construction && structure_value_addr == virtual_outgoing_args_rtx) -#endif ? copy_addr_to_reg (structure_value_addr) : structure_value_addr); @@ -2380,9 +2404,7 @@ expand_call (exp, target, ignore) || reg_mentioned_p (virtual_outgoing_args_rtx, structure_value_addr)) && (args_size.var -#ifndef ACCUMULATE_OUTGOING_ARGS - || args_size.constant -#endif + || (!ACCUMULATE_OUTGOING_ARGS && args_size.constant) )) structure_value_addr = copy_to_reg (structure_value_addr); @@ -2405,13 +2427,11 @@ expand_call (exp, target, ignore) emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); old_pending_adj = pending_stack_adjust; pending_stack_adjust = 0; -#ifdef ACCUMULATE_OUTGOING_ARGS /* 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; -#endif } argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0); } @@ -2433,85 +2453,87 @@ expand_call (exp, target, ignore) 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. + if (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. + 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. */ + Another approach might be to try to reorder the argument + evaluations to avoid this conflicting stack usage. */ #ifndef 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; - -#else /* not ACCUMULATE_OUTGOING_ARGS */ - if (inhibit_defer_pop == 0) + argblock = virtual_outgoing_args_rtx; + } + else { - /* 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; - } + 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); } - /* 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 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 */ } } @@ -2524,51 +2546,52 @@ expand_call (exp, target, ignore) argblock = force_reg (Pmode, force_operand (temp, NULL_RTX)); } -#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) - to initialize an argument. */ - if (stack_arg_under_construction) + if (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) + 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); + rtx push_size = GEN_INT (args_size.constant); #endif - if (old_stack_level == 0) - { - 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 = 0; - /* Make a new map for the new argument list. */ - 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; + if (old_stack_level == 0) + { + 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 = 0; + /* Make a new map for the new argument list. */ + 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. */ + for (i = 0; i < num_actuals; i++) + if (args[i].pass_on_stack) + { + argblock = copy_addr_to_reg (argblock); + break; + } } - /* 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) - { - argblock = copy_addr_to_reg (argblock); - break; - } -#endif compute_argument_addresses (args, argblock, num_actuals); -#ifdef PUSH_ARGS_REVERSED #ifdef PREFERRED_STACK_BOUNDARY /* If we push args individually in reverse order, perform stack alignment before the first push (the last arg). */ - if (args_size.constant != unadjusted_args_size) + if (PUSH_ARGS_REVERSED && argblock == 0 + && args_size.constant != unadjusted_args_size) { /* When the stack adjustment is pending, we get better code by combining the adjustments. */ @@ -2596,7 +2619,6 @@ expand_call (exp, target, ignore) NO_DEFER_POP; } #endif -#endif /* Don't try to defer pops if preallocating, not even from the first arg, since ARGBLOCK probably refers to the SP. */ @@ -2621,11 +2643,12 @@ expand_call (exp, target, ignore) once we have started filling any specific hard regs. */ precompute_register_parameters (num_actuals, args, ®_parm_seen); -#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) +#ifdef REG_PARM_STACK_SPACE /* Save the fixed argument area if it's part of the caller's frame and is clobbered by argument setup for this call. */ - save_area = save_fixed_argument_area (reg_parm_stack_space, argblock, - &low_to_save, &high_to_save); + if (ACCUMULATE_OUTGOING_ARGS) + save_area = save_fixed_argument_area (reg_parm_stack_space, argblock, + &low_to_save, &high_to_save); #endif /* Now store (and compute if necessary) all non-register parms. @@ -2654,22 +2677,21 @@ expand_call (exp, target, ignore) store_one_arg (&args[i], argblock, may_be_alloca, args_size.var != 0, reg_parm_stack_space); -#ifndef PUSH_ARGS_REVERSED #ifdef PREFERRED_STACK_BOUNDARY /* If we pushed args in forward order, perform stack alignment after pushing the last arg. */ /* ??? Fix for arg_space_so_far. */ - if (argblock == 0) + if (!PUSH_ARGS_REVERSED && argblock == 0) anti_adjust_stack (GEN_INT (args_size.constant - unadjusted_args_size)); #endif -#endif /* If register arguments require space on the stack and stack space was not preallocated, allocate stack space here for arguments passed in registers. */ -#if ! defined(ACCUMULATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE) - if (must_preallocate == 0 && reg_parm_stack_space > 0) +#ifdef OUTGOING_REG_PARM_STACK_SPACE + if (!ACCUMULATE_OUTGOING_ARGS + must_preallocate == 0 && reg_parm_stack_space > 0) anti_adjust_stack (GEN_INT (reg_parm_stack_space)); #endif @@ -2749,13 +2771,12 @@ expand_call (exp, target, ignore) /* Construct an "equal form" for the value which mentions all the arguments in order as well as the function name. */ -#ifdef PUSH_ARGS_REVERSED - for (i = 0; i < num_actuals; i++) - note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note); -#else - for (i = num_actuals - 1; i >= 0; i--) - note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note); -#endif + if (PUSH_ARGS_REVERSED) + for (i = 0; i < num_actuals; i++) + note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note); + else + for (i = num_actuals - 1; i >= 0; i--) + note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note); note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note); insns = get_insns (); @@ -2939,15 +2960,12 @@ expand_call (exp, target, ignore) { emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); pending_stack_adjust = old_pending_adj; -#ifdef ACCUMULATE_OUTGOING_ARGS stack_arg_under_construction = old_stack_arg_under_construction; highest_outgoing_arg_in_use = initial_highest_arg_in_use; stack_usage_map = initial_stack_usage_map; -#endif sibcall_failure = 1; } -#ifdef ACCUMULATE_OUTGOING_ARGS - else + else if (ACCUMULATE_OUTGOING_ARGS) { #ifdef REG_PARM_STACK_SPACE if (save_area) @@ -2981,7 +2999,6 @@ expand_call (exp, target, ignore) highest_outgoing_arg_in_use = initial_highest_arg_in_use; stack_usage_map = initial_stack_usage_map; } -#endif /* If this was alloca, record the new stack level for nonlocal gotos. Check for the handler slots since we might not have a save area @@ -3125,22 +3142,18 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p) int is_const; int reg_parm_stack_space = 0; int nothrow; -#ifdef ACCUMULATE_OUTGOING_ARGS int needed; -#endif -#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) +#ifdef REG_PARM_STACK_SPACE /* Define the boundary of the register parm stack space that needs to be save, if any. */ int low_to_save = -1, high_to_save = 0; rtx save_area = 0; /* Place that it is saved */ #endif -#ifdef ACCUMULATE_OUTGOING_ARGS /* Size of the stack reserved for parameter registers. */ int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; -#endif #ifdef REG_PARM_STACK_SPACE #ifdef MAYBE_REG_PARM_STACK_SPACE @@ -3336,133 +3349,139 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p) if (args_size.constant > current_function_outgoing_args_size) current_function_outgoing_args_size = args_size.constant; -#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. + if (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. + 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. - Another approach might be to try to reorder the argument - evaluations to avoid this conflicting stack usage. */ + Another approach might be to try to reorder the argument + evaluations to avoid this conflicting stack usage. */ - needed = args_size.constant; + needed = args_size.constant; #ifndef 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); -#endif - 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 != 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. - */ - - argblock = virtual_outgoing_args_rtx; -#else /* not ACCUMULATE_OUTGOING_ARGS */ -#ifndef PUSH_ROUNDING - argblock = push_block (GEN_INT (args_size.constant), 0, 0); -#endif + highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, + needed); #endif + 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 != 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. + */ + + argblock = virtual_outgoing_args_rtx; + } + else + { + if (!PUSH_ARGS) + argblock = push_block (GEN_INT (args_size.constant), 0, 0); + } -#ifdef PUSH_ARGS_REVERSED #ifdef PREFERRED_STACK_BOUNDARY /* If we push args individually in reverse order, perform stack alignment before the first push (the last arg). */ - if (argblock == 0) + if (argblock == 0 && PUSH_ARGS_REVERSED) anti_adjust_stack (GEN_INT (args_size.constant - original_args_size.constant)); #endif -#endif -#ifdef PUSH_ARGS_REVERSED - inc = -1; - argnum = nargs - 1; -#else - inc = 1; - argnum = 0; -#endif + if (PUSH_ARGS_REVERSED) + { + inc = -1; + argnum = nargs - 1; + } + else + { + inc = 1; + argnum = 0; + } -#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE) - /* The argument list is the property of the called routine and it - may clobber it. If the fixed area has been used for previous - parameters, we must save and restore it. +#ifdef REG_PARM_STACK_SPACE + if (ACCUMULATE_OUTGOING_ARGS) + { + /* The argument list is the property of the called routine and it + may clobber it. If the fixed area has been used for previous + parameters, we must save and restore it. - Here we compute the boundary of the that needs to be saved, if any. */ + Here we compute the boundary of the that needs to be saved, if any. */ #ifdef ARGS_GROW_DOWNWARD - for (count = 0; count < reg_parm_stack_space + 1; count++) + for (count = 0; count < reg_parm_stack_space + 1; count++) #else - for (count = 0; count < reg_parm_stack_space; count++) + for (count = 0; count < reg_parm_stack_space; count++) #endif - { - if (count >= highest_outgoing_arg_in_use - || stack_usage_map[count] == 0) - continue; + { + if (count >= highest_outgoing_arg_in_use + || stack_usage_map[count] == 0) + continue; - if (low_to_save == -1) - low_to_save = count; + if (low_to_save == -1) + low_to_save = count; - high_to_save = count; - } + high_to_save = count; + } - if (low_to_save >= 0) - { - int num_to_save = high_to_save - low_to_save + 1; - enum machine_mode save_mode - = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1); - rtx stack_area; + if (low_to_save >= 0) + { + int num_to_save = high_to_save - low_to_save + 1; + enum machine_mode save_mode + = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1); + rtx stack_area; - /* If we don't have the required alignment, must do this in BLKmode. */ - if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode), - BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1))) - save_mode = BLKmode; + /* If we don't have the required alignment, must do this in BLKmode. */ + if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode), + BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1))) + save_mode = BLKmode; #ifdef ARGS_GROW_DOWNWARD - stack_area = gen_rtx_MEM (save_mode, - memory_address (save_mode, - plus_constant (argblock, - - high_to_save))); + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); #else - stack_area = gen_rtx_MEM (save_mode, - memory_address (save_mode, - plus_constant (argblock, - low_to_save))); + stack_area = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + low_to_save))); #endif - if (save_mode == BLKmode) - { - save_area = assign_stack_temp (BLKmode, num_to_save, 0); - emit_block_move (validize_mem (save_area), stack_area, - GEN_INT (num_to_save), - PARM_BOUNDARY / BITS_PER_UNIT); - } - else - { - save_area = gen_reg_rtx (save_mode); - emit_move_insn (save_area, stack_area); + if (save_mode == BLKmode) + { + save_area = assign_stack_temp (BLKmode, num_to_save, 0); + emit_block_move (validize_mem (save_area), stack_area, + GEN_INT (num_to_save), + PARM_BOUNDARY / BITS_PER_UNIT); + } + else + { + save_area = gen_reg_rtx (save_mode); + emit_move_insn (save_area, stack_area); + } } } #endif @@ -3477,80 +3496,75 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p) register rtx val = argvec[argnum].value; rtx reg = argvec[argnum].reg; int partial = argvec[argnum].partial; -#ifdef ACCUMULATE_OUTGOING_ARGS - int lower_bound, upper_bound, i; -#endif + int lower_bound = 0, upper_bound = 0, i; if (! (reg != 0 && partial == 0)) { -#ifdef ACCUMULATE_OUTGOING_ARGS - /* If this is being stored into a pre-allocated, fixed-size, stack - area, save any previous data at that location. */ + if (ACCUMULATE_OUTGOING_ARGS) + { + /* If this is being stored into a pre-allocated, fixed-size, stack + area, save any previous data at that location. */ #ifdef ARGS_GROW_DOWNWARD - /* stack_slot is negative, but we want to index stack_usage_map - with positive values. */ - upper_bound = -argvec[argnum].offset.constant + 1; - lower_bound = upper_bound - argvec[argnum].size.constant; + /* stack_slot is negative, but we want to index stack_usage_map + with positive values. */ + upper_bound = -argvec[argnum].offset.constant + 1; + lower_bound = upper_bound - argvec[argnum].size.constant; #else - lower_bound = argvec[argnum].offset.constant; - upper_bound = lower_bound + argvec[argnum].size.constant; + lower_bound = argvec[argnum].offset.constant; + upper_bound = lower_bound + argvec[argnum].size.constant; #endif - for (i = lower_bound; i < upper_bound; i++) - if (stack_usage_map[i] - /* Don't store things in the fixed argument area at this point; - it has already been saved. */ - && i > reg_parm_stack_space) - break; + for (i = lower_bound; i < upper_bound; i++) + if (stack_usage_map[i] + /* Don't store things in the fixed argument area at this point; + it has already been saved. */ + && i > reg_parm_stack_space) + break; - if (i != upper_bound) - { - /* We need to make a save area. See what mode we can make it. */ - enum machine_mode save_mode - = mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT, - MODE_INT, 1); - rtx stack_area - = gen_rtx_MEM - (save_mode, - memory_address - (save_mode, - plus_constant (argblock, - argvec[argnum].offset.constant))); - argvec[argnum].save_area = gen_reg_rtx (save_mode); - - emit_move_insn (argvec[argnum].save_area, stack_area); + if (i != upper_bound) + { + /* We need to make a save area. See what mode we can make it. */ + enum machine_mode save_mode + = mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT, + MODE_INT, 1); + rtx stack_area + = gen_rtx_MEM + (save_mode, + memory_address + (save_mode, + plus_constant (argblock, + argvec[argnum].offset.constant))); + argvec[argnum].save_area = gen_reg_rtx (save_mode); + + emit_move_insn (argvec[argnum].save_area, stack_area); + } } -#endif emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0, argblock, GEN_INT (argvec[argnum].offset.constant), reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad)); -#ifdef ACCUMULATE_OUTGOING_ARGS /* Now mark the segment we just used. */ - for (i = lower_bound; i < upper_bound; i++) - stack_usage_map[i] = 1; -#endif + if (ACCUMULATE_OUTGOING_ARGS) + for (i = lower_bound; i < upper_bound; i++) + stack_usage_map[i] = 1; NO_DEFER_POP; } } -#ifndef PUSH_ARGS_REVERSED #ifdef PREFERRED_STACK_BOUNDARY /* If we pushed args in forward order, perform stack alignment after pushing the last arg. */ - if (argblock == 0) + if (argblock == 0 && !PUSH_ARGS_REVERSED) anti_adjust_stack (GEN_INT (args_size.constant - original_args_size.constant)); #endif -#endif -#ifdef PUSH_ARGS_REVERSED - argnum = nargs - 1; -#else - argnum = 0; -#endif + if (PUSH_ARGS_REVERSED) + argnum = nargs - 1; + else + argnum = 0; fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0); @@ -3647,50 +3661,51 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p) value = hard_libcall_value (outmode); } -#ifdef ACCUMULATE_OUTGOING_ARGS -#ifdef REG_PARM_STACK_SPACE - if (save_area) + if (ACCUMULATE_OUTGOING_ARGS) { - enum machine_mode save_mode = GET_MODE (save_area); +#ifdef REG_PARM_STACK_SPACE + if (save_area) + { + enum machine_mode save_mode = GET_MODE (save_area); #ifdef ARGS_GROW_DOWNWARD - rtx stack_area - = gen_rtx_MEM (save_mode, - memory_address (save_mode, - plus_constant (argblock, - - high_to_save))); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, + - high_to_save))); #else - rtx stack_area - = gen_rtx_MEM (save_mode, - memory_address (save_mode, - plus_constant (argblock, low_to_save))); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + plus_constant (argblock, low_to_save))); #endif - if (save_mode != BLKmode) - emit_move_insn (stack_area, save_area); - else - emit_block_move (stack_area, validize_mem (save_area), - GEN_INT (high_to_save - low_to_save + 1), - PARM_BOUNDARY / BITS_PER_UNIT); - } + if (save_mode != BLKmode) + emit_move_insn (stack_area, save_area); + else + emit_block_move (stack_area, validize_mem (save_area), + GEN_INT (high_to_save - low_to_save + 1), + PARM_BOUNDARY / BITS_PER_UNIT); + } #endif - - /* If we saved any argument areas, restore them. */ - for (count = 0; count < nargs; count++) - if (argvec[count].save_area) - { - enum machine_mode save_mode = GET_MODE (argvec[count].save_area); - rtx stack_area - = gen_rtx_MEM (save_mode, - memory_address - (save_mode, - plus_constant (argblock, - argvec[count].offset.constant))); - - emit_move_insn (stack_area, argvec[count].save_area); - } + + /* If we saved any argument areas, restore them. */ + for (count = 0; count < nargs; count++) + if (argvec[count].save_area) + { + enum machine_mode save_mode = GET_MODE (argvec[count].save_area); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address + (save_mode, + plus_constant (argblock, + argvec[count].offset.constant))); + + emit_move_insn (stack_area, argvec[count].save_area); + } - highest_outgoing_arg_in_use = initial_highest_arg_in_use; - stack_usage_map = initial_stack_usage_map; -#endif + highest_outgoing_arg_in_use = initial_highest_arg_in_use; + stack_usage_map = initial_stack_usage_map; + } return value; @@ -3847,9 +3862,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, rtx reg = 0; int partial = 0; int used = 0; -#ifdef ACCUMULATE_OUTGOING_ARGS int i, lower_bound = 0, upper_bound = 0; -#endif if (TREE_CODE (pval) == ERROR_MARK) return; @@ -3858,75 +3871,75 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, this argument. */ push_temp_slots (); -#ifdef ACCUMULATE_OUTGOING_ARGS - /* If this is being stored into a pre-allocated, fixed-size, stack area, - save any previous data at that location. */ - if (argblock && ! variable_size && arg->stack) + if (ACCUMULATE_OUTGOING_ARGS) { + /* If this is being stored into a pre-allocated, fixed-size, stack area, + save any previous data at that location. */ + if (argblock && ! variable_size && arg->stack) + { #ifdef ARGS_GROW_DOWNWARD - /* stack_slot is negative, but we want to index stack_usage_map - with positive values. */ - if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) - upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1; - else - upper_bound = 0; + /* stack_slot is negative, but we want to index stack_usage_map + with positive values. */ + if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) + upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1; + else + upper_bound = 0; - lower_bound = upper_bound - arg->size.constant; + lower_bound = upper_bound - arg->size.constant; #else - if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) - lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)); - else - lower_bound = 0; + if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS) + lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)); + else + lower_bound = 0; - upper_bound = lower_bound + arg->size.constant; + upper_bound = lower_bound + arg->size.constant; #endif - for (i = lower_bound; i < upper_bound; i++) - if (stack_usage_map[i] - /* Don't store things in the fixed argument area at this point; - it has already been saved. */ - && i > reg_parm_stack_space) - break; - - if (i != upper_bound) - { - /* We need to make a save area. See what mode we can make it. */ - enum machine_mode save_mode - = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1); - rtx stack_area - = gen_rtx_MEM (save_mode, - memory_address (save_mode, - XEXP (arg->stack_slot, 0))); + for (i = lower_bound; i < upper_bound; i++) + if (stack_usage_map[i] + /* Don't store things in the fixed argument area at this point; + it has already been saved. */ + && i > reg_parm_stack_space) + break; - if (save_mode == BLKmode) - { - arg->save_area = assign_stack_temp (BLKmode, - arg->size.constant, 0); - MEM_SET_IN_STRUCT_P (arg->save_area, - AGGREGATE_TYPE_P (TREE_TYPE - (arg->tree_value))); - preserve_temp_slots (arg->save_area); - emit_block_move (validize_mem (arg->save_area), stack_area, - GEN_INT (arg->size.constant), - PARM_BOUNDARY / BITS_PER_UNIT); - } - else + if (i != upper_bound) { - arg->save_area = gen_reg_rtx (save_mode); - emit_move_insn (arg->save_area, stack_area); + /* We need to make a save area. See what mode we can make it. */ + enum machine_mode save_mode + = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1); + rtx stack_area + = gen_rtx_MEM (save_mode, + memory_address (save_mode, + XEXP (arg->stack_slot, 0))); + + if (save_mode == BLKmode) + { + arg->save_area = assign_stack_temp (BLKmode, + arg->size.constant, 0); + MEM_SET_IN_STRUCT_P (arg->save_area, + AGGREGATE_TYPE_P (TREE_TYPE + (arg->tree_value))); + preserve_temp_slots (arg->save_area); + emit_block_move (validize_mem (arg->save_area), stack_area, + GEN_INT (arg->size.constant), + PARM_BOUNDARY / BITS_PER_UNIT); + } + else + { + arg->save_area = gen_reg_rtx (save_mode); + emit_move_insn (arg->save_area, stack_area); + } } } + /* Now that we have saved any slots that will be overwritten by this + store, mark all slots this store will use. We must do this before + we actually expand the argument since the expansion itself may + trigger library calls which might need to use the same stack slot. */ + if (argblock && ! variable_size && arg->stack) + for (i = lower_bound; i < upper_bound; i++) + stack_usage_map[i] = 1; } - /* Now that we have saved any slots that will be overwritten by this - store, mark all slots this store will use. We must do this before - we actually expand the argument since the expansion itself may - trigger library calls which might need to use the same stack slot. */ - if (argblock && ! variable_size && arg->stack) - for (i = lower_bound; i < upper_bound; i++) - stack_usage_map[i] = 1; -#endif - /* If this isn't going to be placed on both the stack and in registers, set up the register and number of words. */ if (! arg->pass_on_stack) @@ -3946,7 +3959,6 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, it directly into its stack slot. Otherwise, we can. */ if (arg->value == 0) { -#ifdef ACCUMULATE_OUTGOING_ARGS /* stack_arg_under_construction is nonzero if a function argument is being evaluated directly into the outgoing argument list and expand_call must take special action to preserve the argument list @@ -3967,7 +3979,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, if (arg->pass_on_stack) stack_arg_under_construction++; -#endif + arg->value = expand_expr (pval, (partial || TYPE_MODE (TREE_TYPE (pval)) != arg->mode) @@ -3981,10 +3993,8 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)), arg->value, arg->unsignedp); -#ifdef ACCUMULATE_OUTGOING_ARGS if (arg->pass_on_stack) stack_arg_under_construction--; -#endif } /* Don't allow anything left on stack from computation diff --git a/gcc/combine.c b/gcc/combine.c index 614a95d..2d46a69 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -93,6 +93,20 @@ Boston, MA 02111-1307, USA. */ #include "recog.h" #include "real.h" #include "toplev.h" +#include "defaults.h" + +#ifndef ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 0 +#endif + +/* Supply a default definition for PUSH_ARGS. */ +#ifndef PUSH_ARGS +#ifdef PUSH_ROUNDING +#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS +#else +#define PUSH_ARGS 0 +#endif +#endif /* It is not safe to use ordinary gen_lowpart in combine. Use gen_lowpart_for_combine instead. See comments there. */ @@ -7883,7 +7897,7 @@ nonzero_bits (x, mode) int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; #ifdef PUSH_ROUNDING - if (REGNO (x) == STACK_POINTER_REGNUM) + if (REGNO (x) == STACK_POINTER_REGNUM && PUSH_ARGS) sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment); #endif @@ -11422,7 +11436,7 @@ use_crosses_set_p (x, from_cuid) #ifdef PUSH_ROUNDING /* Don't allow uses of the stack pointer to be moved, because we don't know whether the move crosses a push insn. */ - if (regno == STACK_POINTER_REGNUM) + if (regno == STACK_POINTER_REGNUM && PUSH_ARGS) return 1; #endif for (; regno < endreg; regno++) diff --git a/gcc/config/a29k/a29k.h b/gcc/config/a29k/a29k.h index deca666..d7a2bd4 100644 --- a/gcc/config/a29k/a29k.h +++ b/gcc/config/a29k/a29k.h @@ -716,7 +716,7 @@ enum reg_class { NO_REGS, LR0_REGS, GENERAL_REGS, BP_REGS, FC_REGS, CR_REGS, /* Define this if the maximum size of all the outgoing args is to be accumulated and pushed during the prologue. The amount can be found in the variable current_function_outgoing_args_size. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Offset of first parameter from the argument pointer register value. */ diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 452899d..a420543 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -919,7 +919,7 @@ extern int alpha_memory_latency; /* Define this if the maximum size of all the outgoing args is to be accumulated and pushed during the prologue. The amount can be found in the variable current_function_outgoing_args_size. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Offset of first parameter from the argument pointer register value. */ diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h index 0689d2e..b71d762 100644 --- a/gcc/config/arc/arc.h +++ b/gcc/config/arc/arc.h @@ -643,7 +643,7 @@ extern enum reg_class arc_regno_reg_class[]; `current_function_outgoing_args_size'. No space will be pushed onto the stack for each call; instead, the function prologue should increase the stack frame size by this amount. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. diff --git a/gcc/config/clipper/clipper.h b/gcc/config/clipper/clipper.h index 4720f86..93e674d 100644 --- a/gcc/config/clipper/clipper.h +++ b/gcc/config/clipper/clipper.h @@ -368,7 +368,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS, LIM_REG_CLASSES}; /* we can't set this for clipper as library calls may have 3 args and we pass only 2 args in regs. */ -/* #define ACCUMULATE_OUTGOING_ARGS */ +/* #define ACCUMULATE_OUTGOING_ARGS 1*/ /* Offset of first parameter from the argument pointer register value. diff --git a/gcc/config/dsp16xx/dsp16xx.h b/gcc/config/dsp16xx/dsp16xx.h index 51d66c6..ce2016e 100644 --- a/gcc/config/dsp16xx/dsp16xx.h +++ b/gcc/config/dsp16xx/dsp16xx.h @@ -1071,7 +1071,7 @@ extern struct dsp16xx_frame_info current_frame_info; It is not proper to define both 'PUSH_ROUNDING' and 'ACCUMULATE_OUTGOING_ARGS'. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Offset of first parameter from the argument pointer register value. */ diff --git a/gcc/config/fr30/fr30.h b/gcc/config/fr30/fr30.h index b7ea8b2..4d934ba 100644 --- a/gcc/config/fr30/fr30.h +++ b/gcc/config/fr30/fr30.h @@ -837,7 +837,7 @@ enum reg_class Defining both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS' is not proper. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* A C expression that should indicate the number of bytes of its own arguments that a function pops on returning, or 0 if the function pops no arguments diff --git a/gcc/config/i370/i370.h b/gcc/config/i370/i370.h index 8ff7a6c..08ac644 100644 --- a/gcc/config/i370/i370.h +++ b/gcc/config/i370/i370.h @@ -520,7 +520,7 @@ enum reg_class /* Accumulate the outgoing argument count so we can request the right DSA size and determine stack offset. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Define offset from stack pointer, to location where a parm can be pushed. */ diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index d3f3a65..6696b8b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1797,6 +1797,9 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2) offset += nregs * UNITS_PER_WORD; + if (ACCUMULATE_OUTGOING_ARGS) + total_size += current_function_outgoing_args_size; + total_size += offset; /* Align start of frame for local function. */ @@ -1808,6 +1811,9 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2) padding2 = ((total_size + preferred_alignment - 1) & -preferred_alignment) - total_size; + if (ACCUMULATE_OUTGOING_ARGS) + padding2 += current_function_outgoing_args_size; + if (nregs_on_stack) *nregs_on_stack = nregs; if (rpadding1) diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index d042418..2a4c1ca 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -100,6 +100,8 @@ extern int target_flags; #define MASK_STACK_PROBE 0x00000100 /* Enable stack probing */ #define MASK_NO_ALIGN_STROPS 0x00001000 /* Enable aligning of string ops. */ #define MASK_INLINE_ALL_STROPS 0x00002000 /* Inline stringops in all cases */ +#define MASK_NO_PUSH_ARGS 0x00004000 /* Use push instructions */ +#define MASK_ACCUMULATE_OUTGOING_ARGS 0x00008000/* Accumulate outgoing args */ /* Temporary codegen switches */ #define MASK_INTEL_SYNTAX 0x00000200 @@ -119,6 +121,13 @@ extern int target_flags; faster code on the pentium. */ #define TARGET_ALIGN_DOUBLE (target_flags & MASK_ALIGN_DOUBLE) +/* Use push instructions to save outgoing args. */ +#define TARGET_PUSH_ARGS (!(target_flags & MASK_NO_PUSH_ARGS)) + +/* Accumulate stack adjustments to prologue/epilogue. */ +#define TARGET_ACCUMULATE_OUTGOING_ARGS \ + (target_flags & MASK_ACCUMULATE_OUTGOING_ARGS) + /* Put uninitialized locals into bss, not data. Meaningful only on svr3. */ #define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB) @@ -254,6 +263,14 @@ extern const int x86_promote_hi_regs; "Inline all known string operations" }, \ { "no-inline-all-stringops", -MASK_INLINE_ALL_STROPS, \ "Do not inline all known string operations" }, \ + { "push-args", -MASK_NO_PUSH_ARGS, \ + "Use push instructions to save outgoing arguments" }, \ + { "no-push-args", MASK_NO_PUSH_ARGS, "" \ + "UDo not use push instructions to save outgoing arguments" }, \ + { "accumulate-outgoing-args", MASK_ACCUMULATE_OUTGOING_ARGS, \ + "Use push instructions to save outgoing arguments" }, \ + { "no-accumulate-outgoing-args",-MASK_ACCUMULATE_OUTGOING_ARGS, "" \ + "Do not use push instructions to save outgoing arguments" }, \ SUBTARGET_SWITCHES \ { "", TARGET_DEFAULT, 0 }} @@ -1136,6 +1153,19 @@ enum reg_class #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & (-2)) +/* If defined, the maximum amount of space required for outgoing arguments will + be computed and placed into the variable + `current_function_outgoing_args_size'. No space will be pushed onto the + stack for each call; instead, the function prologue should increase the stack + frame size by this amount. */ + +#define ACCUMULATE_OUTGOING_ARGS TARGET_ACCUMULATE_OUTGOING_ARGS + +/* If defined, a C expression whose value is nonzero when we want to use PUSH + instructions to pass outgoing arguments. */ + +#define PUSH_ARGS (TARGET_PUSH_ARGS && !ACCUMULATE_OUTGOING_ARGS) + /* Offset of first parameter from the argument pointer register value. */ #define FIRST_PARM_OFFSET(FNDECL) 0 diff --git a/gcc/config/i960/i960.h b/gcc/config/i960/i960.h index 8ccd758..10cc665 100644 --- a/gcc/config/i960/i960.h +++ b/gcc/config/i960/i960.h @@ -833,7 +833,7 @@ enum reg_class { NO_REGS, GLOBAL_REGS, LOCAL_REGS, LOCAL_OR_GLOBAL_REGS, #define OUTGOING_REG_PARM_STACK_SPACE /* Keep the stack pointer constant throughout the function. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Value is 1 if returning from a function call automatically pops the arguments described by the number-of-args field in the call. diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index dd07ae1..579cdfd 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -1270,7 +1270,7 @@ extern int ia64_local_regs; be computed and placed into the variable `current_function_outgoing_args_size'. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* A C expression that should indicate the number of bytes of its own arguments that a function pops on returning, or 0 if the function pops no arguments diff --git a/gcc/config/m32r/m32r.h b/gcc/config/m32r/m32r.h index a195486..4f8645c 100644 --- a/gcc/config/m32r/m32r.h +++ b/gcc/config/m32r/m32r.h @@ -983,7 +983,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size) `current_function_outgoing_args_size'. No space will be pushed onto the stack for each call; instead, the function prologue should increase the stack frame size by this amount. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Define this macro if functions should assume that stack space has been allocated for arguments even when their values are passed in diff --git a/gcc/config/m88k/m88k.h b/gcc/config/m88k/m88k.h index 04bc245..5cbae71 100644 --- a/gcc/config/m88k/m88k.h +++ b/gcc/config/m88k/m88k.h @@ -872,7 +872,7 @@ enum reg_class { NO_REGS, AP_REG, XRF_REGS, GENERAL_REGS, AGRF_REGS, `current_function_outgoing_args_size'. No space will be pushed onto the stack for each call; instead, the function prologue should increase the stack frame size by this amount. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Offset from the stack pointer register to the first location at which outgoing arguments are placed. Use the default value zero. */ diff --git a/gcc/config/mcore/mcore.h b/gcc/config/mcore/mcore.h index a165004..94eeb94 100644 --- a/gcc/config/mcore/mcore.h +++ b/gcc/config/mcore/mcore.h @@ -673,7 +673,7 @@ extern enum reg_class reg_class_from_letter[]; `current_function_outgoing_args_size'. No space will be pushed onto the stack for each call; instead, the function prologue should increase the stack frame size by this amount. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Offset of first parameter from the argument pointer register value. */ #define FIRST_PARM_OFFSET(FNDECL) 0 diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 5e7039d..e8307e5 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2260,7 +2260,7 @@ extern struct mips_frame_info current_frame_info; It is not proper to define both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS'. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Offset from the argument pointer register to the first argument's address. On some machines it may depend on the data type of the diff --git a/gcc/config/mn10200/mn10200.h b/gcc/config/mn10200/mn10200.h index 60928c4..bc11832 100644 --- a/gcc/config/mn10200/mn10200.h +++ b/gcc/config/mn10200/mn10200.h @@ -401,7 +401,7 @@ enum reg_class { We allow frame pointers to be eliminated when not having one will not interfere with debugging. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 #define FRAME_POINTER_REQUIRED 0 #define CAN_DEBUG_WITHOUT_FP diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index 403091e..c1507c0 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -447,7 +447,7 @@ enum reg_class { for a register flushback area. */ #define REG_PARM_STACK_SPACE(DECL) 8 #define OUTGOING_REG_PARM_STACK_SPACE -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* So we can allocate space for return pointers once for the function instead of around every call. */ diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index 1a719f86..06571c9 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -556,7 +556,7 @@ extern int target_flags; This is both an optimization and a necessity: longjmp doesn't behave itself when the stack pointer moves within the function! */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* The weird HPPA calling conventions require a minimum of 48 bytes on the stack: 16 bytes for register saves, and 32 bytes for magic. diff --git a/gcc/config/romp/romp.h b/gcc/config/romp/romp.h index cc2914d..ec6602f 100644 --- a/gcc/config/romp/romp.h +++ b/gcc/config/romp/romp.h @@ -499,7 +499,7 @@ enum reg_class { NO_REGS, R0_REGS, R15_REGS, BASE_REGS, GENERAL_REGS, /* Define this if the maximum size of all the outgoing args is to be accumulated and pushed during the prologue. The amount can be found in the variable current_function_outgoing_args_size. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index ae712bc..0e0292a 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1283,7 +1283,7 @@ extern int rs6000_sysv_varargs_p; /* Define this if the maximum size of all the outgoing args is to be accumulated and pushed during the prologue. The amount can be found in the variable current_function_outgoing_args_size. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index c9368eb..12db17a 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -1606,7 +1606,7 @@ extern char leaf_reg_remap[]; This is both an optimization and a necessity: longjmp doesn't behave itself when the stack pointer moves within the function! */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. diff --git a/gcc/config/v850/v850.h b/gcc/config/v850/v850.h index c172c5d..1badc79 100644 --- a/gcc/config/v850/v850.h +++ b/gcc/config/v850/v850.h @@ -667,7 +667,7 @@ enum reg_class #define PROMOTE_PROTOTYPES 1 /* Keep the stack pointer constant throughout the function. */ -#define ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 1 /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. @@ -45,6 +45,19 @@ Boston, MA 02111-1307, USA. */ #include "intl.h" #include "tm_p.h" +#ifndef ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 0 +#endif + +/* Supply a default definition for PUSH_ARGS. */ +#ifndef PUSH_ARGS +#ifdef PUSH_ROUNDING +#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS +#else +#define PUSH_ARGS 0 +#endif +#endif + /* Decide whether a function's arguments should be processed from first to last or from last to first. @@ -2820,27 +2833,36 @@ push_block (size, extra, below) anti_adjust_stack (temp); } -#if defined (STACK_GROWS_DOWNWARD) \ - || (defined (ARGS_GROW_DOWNWARD) \ - && !defined (ACCUMULATE_OUTGOING_ARGS)) - - /* Return the lowest stack address when STACK or ARGS grow downward and - we are not aaccumulating outgoing arguments (the c4x port uses such - conventions). */ - temp = virtual_outgoing_args_rtx; - if (extra != 0 && below) - temp = plus_constant (temp, extra); +#ifndef STACK_GROWS_DOWNWARD +#ifdef ARGS_GROW_DOWNWARD + if (!ACCUMULATE_OUTGOING_ARGS) #else - if (GET_CODE (size) == CONST_INT) - temp = plus_constant (virtual_outgoing_args_rtx, - - INTVAL (size) - (below ? 0 : extra)); - else if (extra != 0 && !below) - temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx, - negate_rtx (Pmode, plus_constant (size, extra))); - else - temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx, - negate_rtx (Pmode, size)); + if (0) #endif +#else + if (1) +#endif + { + + /* Return the lowest stack address when STACK or ARGS grow downward and + we are not aaccumulating outgoing arguments (the c4x port uses such + conventions). */ + temp = virtual_outgoing_args_rtx; + if (extra != 0 && below) + temp = plus_constant (temp, extra); + } + else + { + if (GET_CODE (size) == CONST_INT) + temp = plus_constant (virtual_outgoing_args_rtx, + - INTVAL (size) - (below ? 0 : extra)); + else if (extra != 0 && !below) + temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx, + negate_rtx (Pmode, plus_constant (size, extra))); + else + temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx, + negate_rtx (Pmode, size)); + } return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp); } @@ -2971,6 +2993,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra, and if there is no difficulty with push insns that skip bytes on the stack for alignment purposes. */ if (args_addr == 0 + && PUSH_ARGS && GET_CODE (size) == CONST_INT && skip == 0 && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align)) @@ -3123,15 +3146,16 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra, } } -#ifndef ACCUMULATE_OUTGOING_ARGS - /* If the source is referenced relative to the stack pointer, - copy it to another register to stabilize it. We do not need - to do this if we know that we won't be changing sp. */ + if (!ACCUMULATE_OUTGOING_ARGS) + { + /* If the source is referenced relative to the stack pointer, + copy it to another register to stabilize it. We do not need + to do this if we know that we won't be changing sp. */ - if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp) - || reg_mentioned_p (virtual_outgoing_args_rtx, temp)) - temp = copy_to_reg (temp); -#endif + if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp) + || reg_mentioned_p (virtual_outgoing_args_rtx, temp)) + temp = copy_to_reg (temp); + } /* Make inhibit_defer_pop nonzero around the library call to force it to pop the bcopy-arguments right away. */ @@ -3227,7 +3251,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra, anti_adjust_stack (GEN_INT (extra)); #ifdef PUSH_ROUNDING - if (args_addr == 0) + if (args_addr == 0 && PUSH_ARGS) addr = gen_push_operand (); else #endif diff --git a/gcc/final.c b/gcc/final.c index 5693d46..34db2ae 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -80,6 +80,10 @@ Boston, MA 02111-1307, USA. */ #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ +#ifndef ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 0 +#endif + #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" #endif @@ -2279,10 +2283,10 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) break; case BARRIER: -#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS) +#if defined (DWARF2_UNWIND_INFO) /* If we push arguments, we need to check all insns for stack adjustments. */ - if (dwarf2out_do_frame ()) + if (!ACCUMULATE_OUTGOING_ARGS && dwarf2out_do_frame ()) dwarf2out_frame_debug (insn); #endif break; @@ -2885,9 +2889,10 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) debug_insn = insn; -#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS) +#if defined (DWARF2_UNWIND_INFO) /* If we push arguments, we want to know where the calls are. */ - if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) + if (!ACCUMULATE_OUTGOING_ARGS && GET_CODE (insn) == CALL_INSN + && dwarf2out_do_frame ()) dwarf2out_frame_debug (insn); #endif @@ -2934,19 +2939,22 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) output_asm_insn (template, recog_data.operand); #if defined (DWARF2_UNWIND_INFO) -#if !defined (ACCUMULATE_OUTGOING_ARGS) /* If we push arguments, we need to check all insns for stack adjustments. */ - if (GET_CODE (insn) == INSN && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); -#else + if (!ACCUMULATE_OUTGOING_ARGS) + { + if (GET_CODE (insn) == INSN && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn); + } + else + { #if defined (HAVE_prologue) - /* If this insn is part of the prologue, emit DWARF v2 - call frame info. */ - if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ()) - dwarf2out_frame_debug (insn); -#endif + /* If this insn is part of the prologue, emit DWARF v2 + call frame info. */ + if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ()) + dwarf2out_frame_debug (insn); #endif + } #endif #if 0 diff --git a/gcc/function.c b/gcc/function.c index 2de8ec1..0ec9e61 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -61,6 +61,10 @@ Boston, MA 02111-1307, USA. */ #include "ggc.h" #include "tm_p.h" +#ifndef ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 0 +#endif + #ifndef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY #endif @@ -2738,7 +2742,6 @@ static int cfa_offset; #ifndef STACK_DYNAMIC_OFFSET -#ifdef ACCUMULATE_OUTGOING_ARGS /* The bottom of the stack points to the actual arguments. If REG_PARM_STACK_SPACE is defined, this includes the space for the register parameters. However, if OUTGOING_REG_PARM_STACK space is not defined, @@ -2749,16 +2752,14 @@ static int cfa_offset; #if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE) #define STACK_DYNAMIC_OFFSET(FNDECL) \ -(current_function_outgoing_args_size \ - + REG_PARM_STACK_SPACE (FNDECL) + (STACK_POINTER_OFFSET)) +((ACCUMULATE_OUTGOING_ARGS \ + ? (current_function_outgoing_args_size + REG_PARM_STACK_SPACE (FNDECL)) : 0)\ + + (STACK_POINTER_OFFSET)) \ #else #define STACK_DYNAMIC_OFFSET(FNDECL) \ -(current_function_outgoing_args_size + (STACK_POINTER_OFFSET)) -#endif - -#else -#define STACK_DYNAMIC_OFFSET(FNDECL) STACK_POINTER_OFFSET +((ACCUMULATE_OUTGOING_ARGS ? current_function_outgoing_args_size : 0) \ + + (STACK_POINTER_OFFSET)) #endif #endif diff --git a/gcc/invoke.texi b/gcc/invoke.texi index eb26961..946abcc 100644 --- a/gcc/invoke.texi +++ b/gcc/invoke.texi @@ -362,6 +362,7 @@ in the following sections. -malign-jumps=@var{num} -malign-loops=@var{num} -malign-functions=@var{num} -mpreferred-stack-boundary=@var{num} -mthreads -mno-align-stringops -minline-all-stringops +-mpush-args -maccumulate-outgoing-args @emph{HPPA Options} -march=@var{architecture type} @@ -6024,6 +6025,21 @@ to stack space usage, such as embedded systems and operating system kernels, may want to reduce the preferred alignment to @samp{-mpreferred-stack-boundary=2}. +@item -mpush-args +@kindex -mpush-args +Use PUSH operations to store outgoing parameters. This method is shorter +and usually equally fast as method using SUB/MOV operations and is enabled +by default. In some cases disabling it may improve performance because of +improved scheduling and reduced dependencies. + +@item -maccumulate-outgoing-args +@kindex -maccumulate-outgoing-args +If enabled, the maximum amount of space required for outgoing arguments will be +computed in the function prologue. This in faster on most modern CPUs +because of reduced dependecies, improved scheduling and reduced stack usage +when preferred stack boundary is not equal to 2. The drawback is a notable +increase in code size. This switch implies -mno-push-args. + @item -mthreads @kindex -mthreads Support thread-safe exception handling on @samp{Mingw32}. Code that relies diff --git a/gcc/tm.texi b/gcc/tm.texi index 803e014..dac8911 100644 --- a/gcc/tm.texi +++ b/gcc/tm.texi @@ -2630,15 +2630,24 @@ errors in certain cases of mismatch, it also makes for better code on certain machines. If the macro is not defined in target header files, it defaults to 0. +@findex PUSH_ARGS +@item PUSH_ARGS +A C expression. If nonzero, push insns will be used to pass +outgoing arguments. +If the target machine does not have a push instruction, set it to zero. +That directs GCC to use an alternate strategy: to +allocate the entire argument block and then store the arguments into +it. When PUSH_ARGS is nonzero, PUSH_ROUNDING must be defined too. +On some machines, the definition + +@findex PUSH_ROUNDING +@item PUSH_ROUNDING (@var{npushed}) +A C expression that is the number of bytes actually pushed onto the +stack when an instruction attempts to push @var{npushed} bytes. @findex PUSH_ROUNDING @item PUSH_ROUNDING (@var{npushed}) A C expression that is the number of bytes actually pushed onto the stack when an instruction attempts to push @var{npushed} bytes. - -If the target machine does not have a push instruction, do not define -this macro. That directs GCC to use an alternate strategy: to -allocate the entire argument block and then store the arguments into -it. On some machines, the definition @@ -2658,13 +2667,13 @@ alignment. Then the definition should be @findex ACCUMULATE_OUTGOING_ARGS @findex current_function_outgoing_args_size @item ACCUMULATE_OUTGOING_ARGS -If defined, the maximum amount of space required for outgoing arguments +A C expression. If nonzero, the maximum amount of space required for outgoing arguments will be computed and placed into the variable @code{current_function_outgoing_args_size}. No space will be pushed onto the stack for each call; instead, the function prologue should increase the stack frame size by this amount. -Defining both @code{PUSH_ROUNDING} and @code{ACCUMULATE_OUTGOING_ARGS} +Setting both @code{PUSH_ARGS} and @code{ACCUMULATE_OUTGOING_ARGS} is not proper. @findex REG_PARM_STACK_SPACE diff --git a/gcc/toplev.c b/gcc/toplev.c index 0b06ae2..f91e488 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -61,6 +61,10 @@ Boston, MA 02111-1307, USA. */ #include "loop.h" #include "regs.h" +#ifndef ACCUMULATE_OUTGOING_ARGS +#define ACCUMULATE_OUTGOING_ARGS 0 +#endif + #ifdef DWARF_DEBUGGING_INFO #include "dwarfout.h" #endif @@ -3568,9 +3572,14 @@ rest_of_compilation (decl) life_analysis (insns, max_reg_num (), rtl_dump_file, 1); }); -#ifndef ACCUMULATE_OUTGOING_ARGS - TIMEVAR (flow2_time, { combine_stack_adjustments (); }); + /* This is kind of heruistics. We need to run combine_stack_adjustments + even for machines with possibly nonzero RETURN_POPS_ARGS + and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having + push instructions will have popping returns. */ +#ifndef PUSH_ROUNDING + if (!ACCUMULATE_OUTGOING_ARGS) #endif + TIMEVAR (flow2_time, { combine_stack_adjustments (); }); if (ggc_p) ggc_collect (); |