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]

Combine_stack_adjustements fix



Hi
This patch fixes bug in regmove noticed by Jakub - in case you adjust
stack, store sp value and then use it, regmove may combine two adjacent
stack adjustments and remove the allocated area.

This patch avoids this problem by changing regmove to do only the
safe transformations - when second adjustemnt is allocating instruction,
it is allways safe to combine it into the first and when both adjustments
are deallocating, it is safe to combine them to the second.
Allocation followed by deallocation is never combined, but it is not
common anyway, except for functions that do have unreferenced local arrays,
so create dummy stack frame. I've measured code size increase of about
50 bytes on cc1 executable, but that is mostly cost of the code itself.

I was experimenting with patch converting all the stack references to
ADDRESSOF expression that should avoid such unnecesary stack frames,
but it was increasing the code size at average probably due to untunned
rtx_cost in cse, so I didn't finished it.

Honza

Mon Aug 16 12:18:29 CEST 2004  Jan Hubicka  <jh@suse.cz>
	* regmove.c (try_apply_stack_adjustment): Remove unnecesary sanity
	checking.
	(combine_stack_adjustments_for_block): Do only the safe adjustemnts.
*** /c/egcs/gcc/regmove.c	Wed Aug 23 00:09:09 2000
--- regmove.c	Mon Aug 16 11:27:55 2004
*************** try_apply_stack_adjustment (insn, memlis
*** 2171,2184 ****
    struct csa_memlist *ml;
    rtx set;
  
-   /* We know INSN matches single_set_for_csa, because that's what we
-      recognized earlier.  However, if INSN is not single_set, it is
-      doing double duty as a barrier for frame pointer memory accesses,
-      which we are not recording.  Therefore, an adjust insn that is not
-      single_set may not have a positive delta applied.  */
- 
-   if (delta > 0 && ! single_set (insn))
-     return 0;
    set = single_set_for_csa (insn);
    validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
  
--- 2171,2176 ----
*************** try_apply_stack_adjustment (insn, memlis
*** 2188,2200 ****
        rtx new = gen_rtx_MEM (GET_MODE (*ml->mem),
  			     plus_constant (stack_pointer_rtx, c));
  
-       /* Don't reference memory below the stack pointer.  */
-       if (c < 0)
- 	{
- 	  cancel_changes (0);
- 	  return 0;
- 	}
- 
        MEM_COPY_ATTRIBUTES (new, *ml->mem);
        validate_change (ml->insn, ml->mem, new, 1);
      }
--- 2180,2185 ----
*************** combine_stack_adjustments_for_block (bb)
*** 2292,2297 ****
--- 2277,2283 ----
  	      && GET_CODE (XEXP (src, 1)) == CONST_INT)
  	    {
  	      HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
+ 	      int fail = 0;
  
  	      /* If we've not seen an adjustment previously, record
  		 it now and continue.  */
*************** combine_stack_adjustments_for_block (bb)
*** 2304,2313 ****
  
  	      /* If not all recorded memrefs can be adjusted, or the
  		 adjustment is now too large for a constant addition,
! 		 we cannot merge the two stack adjustments.  */
! 	      if (! try_apply_stack_adjustment (last_sp_set, memlist,
! 						last_sp_adjust + this_adjust,
! 						this_adjust))
  		{
  		  free_csa_memlist (memlist);
  		  memlist = NULL;
--- 2290,2349 ----
  
  	      /* If not all recorded memrefs can be adjusted, or the
  		 adjustment is now too large for a constant addition,
! 		 we cannot merge the two stack adjustments.
! 
! 		 Also we need to be curefull to not move stack pointer
! 		 in the wrong way that may cause accessess to stack
! 		 outside allocated area.  We always combine two adjustements
! 		 where the second is allocating stack to the first instruction
! 		 and two adjustements deallocating stack to the second
! 		 instruction.  We never combine allocating instruction
! 		 followed by deallocating, that should not happen often
! 		 anyway.
! 
! 		 The only case where they do happen known to author are
! 		 function allocating stack frame but never using it.
! 		 We will need to analyze rtl stream to be sure that
! 		 allocated area is unused then.  This means not only
! 		 checking the memory references in between, but also
! 		 all registers or memory references possibly containing
! 		 (modified) copy of stack pointer.
! 
! 		 Better way to handle this problem is probably teaching
! 		 gcc to not allocate stack for objects never used.  */
! 	      if (this_adjust <= 0)
! 		{
! 		  if (! try_apply_stack_adjustment (last_sp_set, memlist,
! 						    last_sp_adjust + this_adjust,
! 						    this_adjust))
! 		    fail = 1;
! 		  else
! 		    {
! 		      /* It worked!  */
! 		      pending_delete = insn;
! 		      last_sp_adjust += this_adjust;
! 		    }
! 		}
! 	      else if (last_sp_adjust >= 0 && this_adjust >= 0)
! 		{
! 		  if (! try_apply_stack_adjustment (insn, memlist,
! 						    last_sp_adjust + this_adjust,
! 						    - last_sp_adjust))
! 		    fail = 1;
! 		  else
! 		    {
! 		      /* It worked!  */
! 		      flow_delete_insn (last_sp_set);
! 		      last_sp_set = insn;
! 		      last_sp_adjust += this_adjust;
! 		      free_csa_memlist (memlist);
! 		      memlist = NULL;
! 		    }
! 		}
! 	      else
! 		fail = 1;
! 
! 	      if (fail)
  		{
  		  free_csa_memlist (memlist);
  		  memlist = NULL;
*************** combine_stack_adjustments_for_block (bb)
*** 2315,2324 ****
  		  last_sp_adjust = this_adjust;
  		  goto processed;
  		}
- 
- 	      /* It worked!  */
- 	      pending_delete = insn;
- 	      last_sp_adjust += this_adjust;
  
  	      /* If, by some accident, the adjustments cancel out,
  		 delete both insns and start from scratch.  */
--- 2351,2356 ----

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