aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog44
-rw-r--r--gcc/calls.c956
-rw-r--r--gcc/combine.c18
-rw-r--r--gcc/config/a29k/a29k.h2
-rw-r--r--gcc/config/alpha/alpha.h2
-rw-r--r--gcc/config/arc/arc.h2
-rw-r--r--gcc/config/clipper/clipper.h2
-rw-r--r--gcc/config/dsp16xx/dsp16xx.h2
-rw-r--r--gcc/config/fr30/fr30.h2
-rw-r--r--gcc/config/i370/i370.h2
-rw-r--r--gcc/config/i386/i386.c6
-rw-r--r--gcc/config/i386/i386.h30
-rw-r--r--gcc/config/i960/i960.h2
-rw-r--r--gcc/config/ia64/ia64.h2
-rw-r--r--gcc/config/m32r/m32r.h2
-rw-r--r--gcc/config/m88k/m88k.h2
-rw-r--r--gcc/config/mcore/mcore.h2
-rw-r--r--gcc/config/mips/mips.h2
-rw-r--r--gcc/config/mn10200/mn10200.h2
-rw-r--r--gcc/config/mn10300/mn10300.h2
-rw-r--r--gcc/config/pa/pa.h2
-rw-r--r--gcc/config/romp/romp.h2
-rw-r--r--gcc/config/rs6000/rs6000.h2
-rw-r--r--gcc/config/sparc/sparc.h2
-rw-r--r--gcc/config/v850/v850.h2
-rw-r--r--gcc/expr.c80
-rw-r--r--gcc/final.c34
-rw-r--r--gcc/function.c17
-rw-r--r--gcc/invoke.texi16
-rw-r--r--gcc/tm.texi23
-rw-r--r--gcc/toplev.c13
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, &reg_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.
diff --git a/gcc/expr.c b/gcc/expr.c
index 447382b..8036963 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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 ();