This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Yet another PREFERRED_STACK_BOUNDARY/nested calls fix
- To: egcs-patches at egcs dot cygnus dot com, rth at cygnus dot com
- Subject: Yet another PREFERRED_STACK_BOUNDARY/nested calls fix
- From: Jan Hubicka <hubicka at atrey dot karlin dot mff dot cuni dot cz>
- Date: Wed, 22 Mar 2000 16:15:41 +0100
Hi
This is my attempt to fix the problems with stack adjustments.
I've killed the arg_size_so_far and use stack_delta instead. It is updated
in lowlevel functions (emit_push_insn, adjust_stack and anti_adjust_stack)
and used by calls.c to generate proper alignment.
I expect there will be less problems with target macros such
as ACCUMULATE_OUTGOING_ARGS compared to arg_size_so_far.
The patch has some sanity checking and passes bootstrap/testsuite
on i386. With missalignment in builtins.c fixed.
I hope there will not be big problems on other machines as well.
I would welcome bootstrap results on other CPUs. Thanks.
Honza
Wed Mar 22 16:05:38 MET 2000 Jan Hubicka <jh@suse.cz>
* builtins.c (expand_builtin_apply): Pass proper parameters to
allocate_dynamic_stack_space.
* calls.c (emit_call_1): Do not adjust stack pointer for SIB,
update stack_pointer_delta; do not update arg_size_so_far.
(compute_argument_block_size): Use stack_delta instead of
stack_pointer_pending and arg_size_so_far.
(expand_call): Add sanity checking for stack_pointer_delta;
save and restore stack_pointer_delta for SIB, use
stack_pointer_delta for alignment; do not update arg_space_so_far.
(emit_library_call_value): Use stack_pointer_delta for alignment.
(store_one_arg): Do not update arg_space_so_far.
* explow.c (adjust_stack, anti_adjust_stack): Update
stack_pointer_delta.
(allocate_dynamic_stack_space): Add sanity checking for
stack_pointer_delta.
* expr.c (init_expr, clear_pending_stack_adjust): Clear
stack_pointer_delta.
(emit_push_insn): Update stack_pointer_delta.
* function.h (struct expr_status): Add x_stack_pointer_delta;
remove x_arg_space_so_far.
(arg_space_so_far): Remove.
(stack_pointer_delta): New macro.
Index: egcs/gcc/builtins.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/builtins.c,v
retrieving revision 1.36
diff -c -3 -p -r1.36 builtins.c
*** builtins.c 2000/03/11 00:30:06 1.36
--- builtins.c 2000/03/22 14:57:17
*************** expand_builtin_apply (function, argument
*** 882,889 ****
/* Create a block where the return registers can be saved. */
result = assign_stack_local (BLKmode, apply_result_size (), -1);
- /* ??? The argsize value should be adjusted here. */
-
/* Fetch the arg pointer from the ARGUMENTS block. */
incoming_args = gen_reg_rtx (Pmode);
emit_move_insn (incoming_args,
--- 882,887 ----
*************** expand_builtin_apply (function, argument
*** 912,918 ****
haven't figured out how the calling convention macros effect this,
but it's likely that the source and/or destination addresses in
the block copy will need updating in machine specific ways. */
! dest = allocate_dynamic_stack_space (argsize, 0, 0);
emit_block_move (gen_rtx_MEM (BLKmode, dest),
gen_rtx_MEM (BLKmode, incoming_args),
argsize,
--- 910,916 ----
haven't figured out how the calling convention macros effect this,
but it's likely that the source and/or destination addresses in
the block copy will need updating in machine specific ways. */
! dest = allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
emit_block_move (gen_rtx_MEM (BLKmode, dest),
gen_rtx_MEM (BLKmode, incoming_args),
argsize,
Index: egcs/gcc/calls.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/calls.c,v
retrieving revision 1.100
diff -c -3 -p -r1.100 calls.c
*** calls.c 2000/03/22 10:51:10 1.100
--- calls.c 2000/03/22 14:57:18
*************** emit_call_1 (funexp, fndecl, funtype, st
*** 560,595 ****
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)
! CALL_INSN_FUNCTION_USAGE (call_insn)
! = gen_rtx_EXPR_LIST (VOIDmode,
! gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx),
! CALL_INSN_FUNCTION_USAGE (call_insn));
! rounded_stack_size -= n_popped;
! rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
! }
! 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
}
--- 560,597 ----
inhibit_defer_pop = old_inhibit_defer_pop;
#ifndef ACCUMULATE_OUTGOING_ARGS
! /* Don't do any cleanups after SIBCALL. */
! if (!(ecf_flags & ECF_SIBCALL))
! {
! /* 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. */
! stack_pointer_delta -= n_popped;
! if (n_popped > 0)
! {
! if (!already_popped)
! CALL_INSN_FUNCTION_USAGE (call_insn)
! = gen_rtx_EXPR_LIST (VOIDmode,
! gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx),
! CALL_INSN_FUNCTION_USAGE (call_insn));
! rounded_stack_size -= n_popped;
! rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
! }
! 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
}
*************** compute_argument_block_size (reg_parm_st
*** 1263,1269 ****
#ifdef PREFERRED_STACK_BOUNDARY
preferred_stack_boundary /= BITS_PER_UNIT;
if (preferred_stack_boundary > 1)
! args_size->var = round_up (args_size->var, preferred_stack_boundary);
#endif
if (reg_parm_stack_space > 0)
--- 1265,1278 ----
#ifdef PREFERRED_STACK_BOUNDARY
preferred_stack_boundary /= BITS_PER_UNIT;
if (preferred_stack_boundary > 1)
! {
! /* We don't handle this case yet. To handle it correctly we have
! to add the delta, round and substract the delta.
! Currently no machine description requires this support. */
! if (stack_pointer_delta)
! abort();
! args_size->var = round_up (args_size->var, preferred_stack_boundary);
! }
#endif
if (reg_parm_stack_space > 0)
*************** compute_argument_block_size (reg_parm_st
*** 1288,1300 ****
if (preferred_stack_boundary < 1)
preferred_stack_boundary = 1;
args_size->constant = (((args_size->constant
! + arg_space_so_far
! + pending_stack_adjust
+ preferred_stack_boundary - 1)
/ preferred_stack_boundary
* preferred_stack_boundary)
! - arg_space_so_far
! - pending_stack_adjust);
#endif
args_size->constant = MAX (args_size->constant,
--- 1297,1307 ----
if (preferred_stack_boundary < 1)
preferred_stack_boundary = 1;
args_size->constant = (((args_size->constant
! + stack_pointer_delta
+ preferred_stack_boundary - 1)
/ preferred_stack_boundary
* preferred_stack_boundary)
! - stack_pointer_delta);
#endif
args_size->constant = MAX (args_size->constant,
*************** expand_call (exp, target, ignore)
*** 1782,1787 ****
--- 1789,1795 ----
rtx old_stack_level = 0;
int old_pending_adj = 0;
int old_inhibit_defer_pop = inhibit_defer_pop;
+ int old_stack_allocated;
rtx call_fusage;
register tree p;
register int i;
*************** expand_call (exp, target, ignore)
*** 2062,2067 ****
--- 2070,2076 ----
recursion call can be ignored if we indeed use the tail recursion
call expansion. */
int save_pending_stack_adjust = pending_stack_adjust;
+ int save_stack_pointer_delta = stack_pointer_delta;
rtx last;
/* Use a new sequence to hold any RTL we generate. We do not even
*************** expand_call (exp, target, ignore)
*** 2087,2092 ****
--- 2096,2102 ----
/* Restore the original pending stack adjustment for the sibling and
normal call cases below. */
pending_stack_adjust = save_pending_stack_adjust;
+ stack_pointer_delta = save_stack_pointer_delta;
}
function_call_count++;
*************** expand_call (exp, target, ignore)
*** 2132,2137 ****
--- 2142,2148 ----
recursion call can be ignored if we indeed use the tail recursion
call expansion. */
int save_pending_stack_adjust;
+ int save_stack_pointer_delta;
rtx insns;
rtx before_call;
*************** expand_call (exp, target, ignore)
*** 2165,2170 ****
--- 2176,2182 ----
/* State variables we need to save and restore between
iterations. */
save_pending_stack_adjust = pending_stack_adjust;
+ save_stack_pointer_delta = stack_pointer_delta;
}
/* Other state variables that we must reinitialize each time
*************** expand_call (exp, target, ignore)
*** 2354,2359 ****
--- 2366,2373 ----
if (is_const || is_malloc)
start_sequence ();
+ old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
+
/* If we have no actual push instructions, or shouldn't use them,
make space for all args right now. */
*************** expand_call (exp, target, ignore)
*** 2534,2555 ****
if (pending_stack_adjust && ! is_const
&& ! inhibit_defer_pop)
{
args_size.constant = (unadjusted_args_size
+ ((pending_stack_adjust
+ args_size.constant
- + arg_space_so_far
- unadjusted_args_size)
% (preferred_stack_boundary
/ BITS_PER_UNIT)));
! pending_stack_adjust -= (args_size.constant
! - unadjusted_args_size);
! do_pending_stack_adjust ();
}
else if (argblock == 0)
anti_adjust_stack (GEN_INT (args_size.constant
- unadjusted_args_size));
- arg_space_so_far += args_size.constant - unadjusted_args_size;
-
/* Now that the stack is properly aligned, pops can't safely
be deferred during the evaluation of the arguments. */
NO_DEFER_POP;
--- 2548,2568 ----
if (pending_stack_adjust && ! is_const
&& ! inhibit_defer_pop)
{
+ int adjust;
args_size.constant = (unadjusted_args_size
+ ((pending_stack_adjust
+ args_size.constant
- unadjusted_args_size)
% (preferred_stack_boundary
/ BITS_PER_UNIT)));
! adjust = (pending_stack_adjust - args_size.constant
! + unadjusted_args_size);
! adjust_stack (GEN_INT (adjust));
! pending_stack_adjust = 0;
}
else if (argblock == 0)
anti_adjust_stack (GEN_INT (args_size.constant
- unadjusted_args_size));
/* Now that the stack is properly aligned, pops can't safely
be deferred during the evaluation of the arguments. */
NO_DEFER_POP;
*************** expand_call (exp, target, ignore)
*** 2617,2623 ****
#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)
anti_adjust_stack (GEN_INT (args_size.constant
- unadjusted_args_size));
--- 2630,2635 ----
*************** expand_call (exp, target, ignore)
*** 2679,2684 ****
--- 2691,2701 ----
| (nothrow ? ECF_NOTHROW : 0)
| (pass == 0 ? ECF_SIBCALL : 0)));
+ /* Verify that we've deallocated all the stack we used. */
+ if (pass
+ && old_stack_allocated != stack_pointer_delta - pending_stack_adjust)
+ abort();
+
/* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
*************** expand_call (exp, target, ignore)
*** 2956,2965 ****
if (current_function_args_size < args_size.constant
|| sibcall_failure)
tail_call_insns = NULL_RTX;
-
/* Restore the pending stack adjustment now that we have
finished generating the sibling call sequence. */
pending_stack_adjust = save_pending_stack_adjust;
}
else
normal_call_insns = insns;
--- 2973,2983 ----
if (current_function_args_size < args_size.constant
|| sibcall_failure)
tail_call_insns = NULL_RTX;
/* Restore the pending stack adjustment now that we have
finished generating the sibling call sequence. */
+
pending_stack_adjust = save_pending_stack_adjust;
+ stack_pointer_delta = save_stack_pointer_delta;
}
else
normal_call_insns = insns;
*************** emit_library_call_value_1 (retval, orgfu
*** 3262,3269 ****
original_args_size = args_size;
#ifdef PREFERRED_STACK_BOUNDARY
! args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
! / STACK_BYTES) * STACK_BYTES);
#endif
args_size.constant = MAX (args_size.constant,
--- 3280,3291 ----
original_args_size = args_size;
#ifdef PREFERRED_STACK_BOUNDARY
! args_size.constant = (((args_size.constant
! + stack_pointer_delta
! + STACK_BYTES - 1)
! / STACK_BYTES
! * STACK_BYTES)
! - stack_pointer_delta);
#endif
args_size.constant = MAX (args_size.constant,
*************** store_one_arg (arg, argblock, may_be_all
*** 3981,3988 ****
partial, reg, used - size, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
-
- arg_space_so_far += used;
}
else
{
--- 4003,4008 ----
*************** store_one_arg (arg, argblock, may_be_all
*** 4010,4016 ****
excess = (arg->size.constant - int_size_in_bytes (TREE_TYPE (pval))
+ partial * UNITS_PER_WORD);
size_rtx = expr_size (pval);
- arg_space_so_far += excess + INTVAL (size_rtx);
}
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
--- 4030,4035 ----
Index: egcs/gcc/explow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/explow.c,v
retrieving revision 1.42
diff -c -3 -p -r1.42 explow.c
*** explow.c 2000/02/26 06:04:48 1.42
--- explow.c 2000/03/22 14:57:18
*************** adjust_stack (adjust)
*** 852,857 ****
--- 852,862 ----
if (adjust == const0_rtx)
return;
+ /* We expect all variable sized adjustments to be multiple of
+ PREFERRED_STACK_BOUNDARY. */
+ if (GET_CODE (adjust) == CONST_INT)
+ stack_pointer_delta -= INTVAL (adjust);
+
temp = expand_binop (Pmode,
#ifdef STACK_GROWS_DOWNWARD
add_optab,
*************** anti_adjust_stack (adjust)
*** 878,883 ****
--- 883,893 ----
if (adjust == const0_rtx)
return;
+ /* We expect all variable sized adjustments to be multiple of
+ PREFERRED_STACK_BOUNDARY. */
+ if (GET_CODE (adjust) == CONST_INT)
+ stack_pointer_delta += INTVAL (adjust);
+
temp = expand_binop (Pmode,
#ifdef STACK_GROWS_DOWNWARD
sub_optab,
*************** allocate_dynamic_stack_space (size, targ
*** 1294,1299 ****
--- 1304,1316 ----
#endif
do_pending_stack_adjust ();
+
+ /* We ought to be called always on the toplevel and stack ought to be aligned
+ propertly. */
+ #ifdef PREFERRED_STACK_BOUNDARY
+ if (stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))
+ abort ();
+ #endif
/* If needed, check that we have the required amount of stack. Take into
account what has already been checked. */
Index: egcs/gcc/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expr.c,v
retrieving revision 1.217
diff -c -3 -p -r1.217 expr.c
*** expr.c 2000/03/21 18:10:39 1.217
--- expr.c 2000/03/22 14:57:25
*************** init_expr ()
*** 289,295 ****
pending_chain = 0;
pending_stack_adjust = 0;
! arg_space_so_far = 0;
inhibit_defer_pop = 0;
saveregs_value = 0;
apply_args_value = 0;
--- 289,295 ----
pending_chain = 0;
pending_stack_adjust = 0;
! stack_pointer_delta = 0;
inhibit_defer_pop = 0;
saveregs_value = 0;
apply_args_value = 0;
*************** emit_push_insn (x, mode, type, size, ali
*** 2985,2990 ****
--- 2985,2991 ----
&& where_pad != none && where_pad != stack_direction)
anti_adjust_stack (GEN_INT (extra));
+ stack_pointer_delta += INTVAL (size) - used;
move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
INTVAL (size) - used, align);
*************** emit_push_insn (x, mode, type, size, ali
*** 3224,3230 ****
#ifdef PUSH_ROUNDING
if (args_addr == 0)
! addr = gen_push_operand ();
else
#endif
{
--- 3225,3234 ----
#ifdef PUSH_ROUNDING
if (args_addr == 0)
! {
! addr = gen_push_operand ();
! stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
! }
else
#endif
{
*************** clear_pending_stack_adjust ()
*** 9146,9152 ****
&& EXIT_IGNORE_STACK
&& ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
&& ! flag_inline_functions)
! pending_stack_adjust = 0;
#endif
}
--- 9150,9159 ----
&& EXIT_IGNORE_STACK
&& ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
&& ! flag_inline_functions)
! {
! stack_pointer_delta -= pending_stack_adjust,
! pending_stack_adjust = 0;
! }
#endif
}
Index: egcs/gcc/function.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.h,v
retrieving revision 1.51
diff -c -3 -p -r1.51 function.h
*** function.h 2000/03/19 05:26:47 1.51
--- function.h 2000/03/22 14:57:25
*************** struct expr_status
*** 130,139 ****
These are the arguments to function calls that have already returned. */
int x_pending_stack_adjust;
- /* Number of units that we should eventually pop off the stack.
- These are the arguments to function calls that have not happened yet. */
- int x_arg_space_so_far;
-
/* Under some ABIs, it is the caller's responsibility to pop arguments
pushed for function calls. A naive implementation would simply pop
the arguments immediately after each call. However, if several
--- 130,135 ----
*************** struct expr_status
*** 151,156 ****
--- 147,158 ----
NO_DEFER_POP and OK_DEFER_POP. */
int x_inhibit_defer_pop;
+ /* If PREFERRED_STACK_BOUNDARY and PUSH_ROUNDING are defined, the stack
+ boundary can be momentairly unaligned while pushing the arguments.
+ Record the delta since last aligned boundary here in order to get
+ stack alignment in the nested function calls working right. */
+ int x_stack_pointer_delta;
+
/* Nonzero means __builtin_saveregs has already been done in this function.
The value is the pseudoreg containing the value __builtin_saveregs
returned. */
*************** struct expr_status
*** 167,178 ****
};
#define pending_stack_adjust (cfun->expr->x_pending_stack_adjust)
- #define arg_space_so_far (cfun->expr->x_arg_space_so_far)
#define inhibit_defer_pop (cfun->expr->x_inhibit_defer_pop)
#define saveregs_value (cfun->expr->x_saveregs_value)
#define apply_args_value (cfun->expr->x_apply_args_value)
#define forced_labels (cfun->expr->x_forced_labels)
#define pending_chain (cfun->expr->x_pending_chain)
/* This structure can save all the important global and static variables
describing the status of the current function. */
--- 169,180 ----
};
#define pending_stack_adjust (cfun->expr->x_pending_stack_adjust)
#define inhibit_defer_pop (cfun->expr->x_inhibit_defer_pop)
#define saveregs_value (cfun->expr->x_saveregs_value)
#define apply_args_value (cfun->expr->x_apply_args_value)
#define forced_labels (cfun->expr->x_forced_labels)
#define pending_chain (cfun->expr->x_pending_chain)
+ #define stack_pointer_delta (cfun->expr->x_stack_pointer_delta)
/* This structure can save all the important global and static variables
describing the status of the current function. */