This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Fix bug in cleaning parameters after function call


Hello,

when compiling attached testcase on i686 I noticed that the stack adjustment
in the block containing the last call to foo2 is different when
reached from different edges.

The problem is that when there is one call immediatelly followed by the second
and the second call has 16 bytes (= stack alignment)
the arguments of the first call are not cleaned up.

The reason is that the condition in expand_call is wrong.
The code emitting stack cleanup is in a block
where adjusted_args_size.constant != unadjusted_args_size.
When emiting the second call (which has 16 bytes of parameters)
adjusted_args_size.constant == unadjusted_args_size == 16
and thus the block is not entered.
My patch fixes the logic to emit the stack cleanup when pending_stack_adjust>0
even when adjusted_args_size.constant == unadjusted_args_size.

Interesting part of example in detail:
pseudo code as it is now:          as it should be:
sp -= 12;                          sp -= 12
pushl arg1                         pushl arg1
call foo1                          call foo1
// cleanup missing                 sp += 16     // cleanup stack
pushl arg4                                      // because of call
pushl arg3                         sp -= 0      // aligning
pushl arg2                         pushl arg4
pushl arg1                         pushl arg3
call foo3                          pushl arg2
                                   pushl arg1
                                   call foo3

                           // sp += 16 and sp -= 0 is emitted combined together

Bootstrapped/regtested mainline and 3.3 branch on i686 and x86-64.
OK for mainline and 3.3 branch?

Josef

extern void *foo1(void *a);
extern void *foo4(const char *a, int b);
__attribute__ ((__noreturn__))
     extern void foo2 (char *expr, char *file, int line, char *fn);
int foo (const char *name)
{
  void *dm, *status;

  dm = foo4 (name, 1);
  if (dm == 0)
    foo2 ("0", "c", 3907, __PRETTY_FUNCTION__);

  status = foo1 (dm);
  if (status)
    {
      foo1 (dm);
      foo2 ("0", "c", 3918, __PRETTY_FUNCTION__);
    }
  return 0;
}

2003-12-12  Josef Zlomek  <zlomekj@suse.cz>

	* calls.c (expand_call): Fix logic to emit stack cleanup when
	pending_stack_adjust > 0.

Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.308
diff -c -7 -p -r1.308 calls.c
*** calls.c	8 Dec 2003 10:33:46 -0000	1.308
--- calls.c	12 Dec 2003 08:10:43 -0000
*************** expand_call (tree exp, rtx target, int i
*** 2955,2985 ****
  	      }
  	}
  
        compute_argument_addresses (args, argblock, num_actuals);
  
        /* If we push args individually in reverse order, perform stack alignment
  	 before the first push (the last arg).  */
!       if (PUSH_ARGS_REVERSED && argblock == 0
! 	  && adjusted_args_size.constant != unadjusted_args_size)
  	{
  	  /* When the stack adjustment is pending, we get better code
  	     by combining the adjustments.  */
  	  if (pending_stack_adjust
  	      && ! (flags & ECF_LIBCALL_BLOCK)
  	      && ! inhibit_defer_pop)
  	    {
  	      pending_stack_adjust
  		= (combine_pending_stack_adjustment_and_call
  		   (unadjusted_args_size,
  		    &adjusted_args_size,
  		    preferred_unit_stack_boundary));
  	      do_pending_stack_adjust ();
  	    }
! 	  else if (argblock == 0)
  	    anti_adjust_stack (GEN_INT (adjusted_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;
  
--- 2955,2985 ----
  	      }
  	}
  
        compute_argument_addresses (args, argblock, num_actuals);
  
        /* If we push args individually in reverse order, perform stack alignment
  	 before the first push (the last arg).  */
!       if (PUSH_ARGS_REVERSED && argblock == 0)
  	{
  	  /* When the stack adjustment is pending, we get better code
  	     by combining the adjustments.  */
  	  if (pending_stack_adjust
  	      && ! (flags & ECF_LIBCALL_BLOCK)
  	      && ! inhibit_defer_pop)
  	    {
  	      pending_stack_adjust
  		= (combine_pending_stack_adjustment_and_call
  		   (unadjusted_args_size,
  		    &adjusted_args_size,
  		    preferred_unit_stack_boundary));
  	      do_pending_stack_adjust ();
  	    }
! 	  else if (argblock == 0
! 		   && adjusted_args_size.constant != unadjusted_args_size)
  	    anti_adjust_stack (GEN_INT (adjusted_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;
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]