Yet another PREFERRED_STACK_BOUNDARY/nested calls fix

Jan Hubicka hubicka@atrey.karlin.mff.cuni.cz
Wed Mar 22 07:15:00 GMT 2000


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.  */


More information about the Gcc-patches mailing list