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]

Patch to improve delete_computation.


This patch improves delete_computation in a few areas.

  1) FIND_REG_INC_NOTE is used to determine if it is safe to delete
     an insn.  I don't believe that it's desirable to delete insns
     which contain a reference to volatile memory so it seems to me
     that side_effects_p is a better choice.

  2) The REG_DEAD note may be omitted for a register which is both
     set and used by the same insn.  When it's omitted delete_computation
     fails to delete all the insns.

  3) Multi-word hard registers are only deleted if the prior instruction
     sets the exact same multi-word hard register.  Situations where
     instructions are deleted which use different portitions of a
     multi-word register are not recognized by delete_computation.

For example using -O2 -fno-schedule-insns2 on a x86 platform to compile:

  long long
  subr(long long b)
    {
    long long c;

    c = b;

    c -= c;

    if (b)
      return c >> 3;
    return c;
    }

without the patch produces:

	pushl %ebp
	movl %esp,%ebp
	movl 8(%ebp),%edx
	movl 12(%ebp),%ecx
	movl %edx,%eax
	movl $0,%eax
	movl $0,%edx
	leave
	ret

with the patch:

	pushl %ebp
	movl %esp,%ebp
	movl $0,%eax
	movl $0,%edx
	leave
	ret

This patch passes make bootstrap and make check on FreeBSD-3.2 x86.

Note:

  1) This patch is a bit more useful if the earlier patch
     "Patch to fix sched2 REG_DEAD note handling" is
     installed (though it's not required).

ChangeLog:

Sun Aug  1 00:25:42 EDT 1999  John Wehle  (john@feith.com)

	* jump.c (delete_prior_computation): New function, broken
	out of delete_computation.  Check for side effects with
	side_effects_p instead of FIND_REG_INC_NOTE.  Handle
	multi-word hard registers.
	(delete_computation): Use it.  Check for side effects with
	side_effects_p instead of FIND_REG_INC_NOTE.  Synthesize a
	missing REG_DEAD note for a register which is both set and
	used by an insn.

Enjoy!

-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/jump.c.ORIGINAL	Sat Jul 24 00:27:45 1999
--- gcc/jump.c	Sun Aug  1 01:33:09 1999
*************** delete_jump (insn)
*** 3811,3816 ****
--- 3811,3922 ----
      delete_computation (insn);
  }
  
+ /* Recursively delete prior insns that compute the value (used only by INSN
+    which the caller is deleting) stored in the register mentioned by NOTE
+    which is a REG_DEAD note associated with INSN.  */
+ 
+ static void
+ delete_prior_computation (note, insn)
+      rtx note;
+      rtx insn;
+ {
+   rtx our_prev;
+   rtx reg = XEXP (note, 0);
+ 
+   for (our_prev = prev_nonnote_insn (insn);
+        our_prev && GET_CODE (our_prev) == INSN;
+        our_prev = prev_nonnote_insn (our_prev))
+     {
+       rtx pat = PATTERN (our_prev);
+ 
+       /* If we reach a SEQUENCE, it is too complex to try to
+ 	 do anything with it, so give up.  */
+       if (GET_CODE (pat) == SEQUENCE)
+ 	break;
+ 
+       if (GET_CODE (pat) == USE
+ 	  && GET_CODE (XEXP (pat, 0)) == INSN)
+ 	/* reorg creates USEs that look like this.  We leave them
+ 	   alone because reorg needs them for its own purposes.  */
+ 	break;
+ 
+       if (reg_set_p (reg, pat))
+ 	{
+ 	  if (side_effects_p (pat))
+ 	    break;
+ 
+ 	  if (GET_CODE (pat) == PARALLEL)
+ 	    {
+ 	      /* If we find a SET of something else, we can't
+ 		 delete the insn.  */
+ 
+ 	      int i;
+ 
+ 	      for (i = 0; i < XVECLEN (pat, 0); i++)
+ 		{
+ 		  rtx part = XVECEXP (pat, 0, i);
+ 
+ 		  if (GET_CODE (part) == SET
+ 		      && SET_DEST (part) != reg)
+ 		    break;
+ 		}
+ 
+ 	      if (i == XVECLEN (pat, 0))
+ 		delete_computation (our_prev);
+ 	    }
+ 	  else if (GET_CODE (pat) == SET
+ 		   && GET_CODE (SET_DEST (pat)) == REG)
+ 	    {
+ 	      int dest_regno = REGNO (SET_DEST (pat));
+ 	      int dest_endregno
+ 		    = dest_regno + (dest_regno < FIRST_PSEUDO_REGISTER 
+ 		      ? HARD_REGNO_NREGS (dest_regno,
+ 				GET_MODE (SET_DEST (pat))) : 1);
+ 	      int regno = REGNO (reg);
+ 	      int endregno = regno + (regno < FIRST_PSEUDO_REGISTER 
+ 			     ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1);
+ 
+ 	      if (dest_regno >= regno
+ 		  && dest_endregno <= endregno)
+ 		delete_computation (our_prev);
+ 
+ 	      /* We may have a multi-word hard register and some, but not
+ 		 all, of the words of the register are needed in subsequent
+ 		 insns.  Write REG_UNUSED notes for those parts that were not
+ 		 needed.  */
+ 	      else if (dest_regno <= regno
+ 		       && dest_endregno >= endregno
+ 		       && ! find_regno_note (our_prev, REG_UNUSED, REGNO(reg)))
+ 		{
+ 		  int i;
+ 
+ 		  REG_NOTES (our_prev)
+ 		    = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (our_prev));
+ 
+ 		  for (i = dest_regno; i < dest_endregno; i++)
+ 		    if (! find_regno_note (our_prev, REG_UNUSED, i))
+ 		      break;
+ 
+ 		  if (i == dest_endregno)
+ 		    delete_computation (our_prev);
+ 		}
+ 	    }
+ 
+ 	  break;
+ 	}
+ 
+       /* If PAT references the register that dies here, it is an
+ 	 additional use.  Hence any prior SET isn't dead.  However, this
+ 	 insn becomes the new place for the REG_DEAD note.  */
+       if (reg_overlap_mentioned_p (reg, pat))
+ 	{
+ 	  XEXP (note, 1) = REG_NOTES (our_prev);
+ 	  REG_NOTES (our_prev) = note;
+ 	  break;
+ 	}
+     }
+ }
+ 
  /* Delete INSN and recursively delete insns that compute values used only
     by INSN.  This uses the REG_DEAD notes computed during flow analysis.
     If we are running before flow.c, we need do nothing since flow.c will
*************** delete_computation (insn)
*** 3829,3834 ****
--- 3935,3941 ----
       rtx insn;
  {
    rtx note, next;
+   rtx set;
  
  #ifdef HAVE_cc0
    if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
*************** delete_computation (insn)
*** 3844,3850 ****
  	  && sets_cc0_p (PATTERN (prev)))
  	{
  	  if (sets_cc0_p (PATTERN (prev)) > 0
! 	      && !FIND_REG_INC_NOTE (prev, NULL_RTX))
  	    delete_computation (prev);
  	  else
  	    /* Otherwise, show that cc0 won't be used.  */
--- 3951,3957 ----
  	  && sets_cc0_p (PATTERN (prev)))
  	{
  	  if (sets_cc0_p (PATTERN (prev)) > 0
! 	      && ! side_effects_p (PATTERN (prev)))
  	    delete_computation (prev);
  	  else
  	    /* Otherwise, show that cc0 won't be used.  */
*************** delete_computation (insn)
*** 3865,3874 ****
      }
  #endif
  
    for (note = REG_NOTES (insn); note; note = next)
      {
-       rtx our_prev;
- 
        next = XEXP (note, 1);
  
        if (REG_NOTE_KIND (note) != REG_DEAD
--- 3972,3981 ----
      }
  #endif
  
+   set = single_set (insn);
+ 
    for (note = REG_NOTES (insn); note; note = next)
      {
        next = XEXP (note, 1);
  
        if (REG_NOTE_KIND (note) != REG_DEAD
*************** delete_computation (insn)
*** 3876,3938 ****
  	  || GET_CODE (XEXP (note, 0)) != REG)
  	continue;
  
!       for (our_prev = prev_nonnote_insn (insn);
! 	   our_prev && GET_CODE (our_prev) == INSN;
! 	   our_prev = prev_nonnote_insn (our_prev))
! 	{
! 	  /* If we reach a SEQUENCE, it is too complex to try to
! 	     do anything with it, so give up.  */
! 	  if (GET_CODE (PATTERN (our_prev)) == SEQUENCE)
! 	    break;
! 
! 	  if (GET_CODE (PATTERN (our_prev)) == USE
! 	      && GET_CODE (XEXP (PATTERN (our_prev), 0)) == INSN)
! 	    /* reorg creates USEs that look like this.  We leave them
! 	       alone because reorg needs them for its own purposes.  */
! 	    break;
! 
! 	  if (reg_set_p (XEXP (note, 0), PATTERN (our_prev)))
! 	    {
! 	      if (FIND_REG_INC_NOTE (our_prev, NULL_RTX))
! 		break;
  
! 	      if (GET_CODE (PATTERN (our_prev)) == PARALLEL)
! 		{
! 		  /* If we find a SET of something else, we can't
! 		     delete the insn.  */
! 
! 		  int i;
! 
! 		  for (i = 0; i < XVECLEN (PATTERN (our_prev), 0); i++)
! 		    {
! 		      rtx part = XVECEXP (PATTERN (our_prev), 0, i);
! 
! 		      if (GET_CODE (part) == SET
! 			  && SET_DEST (part) != XEXP (note, 0))
! 			break;
! 		    }
! 
! 		  if (i == XVECLEN (PATTERN (our_prev), 0))
! 		    delete_computation (our_prev);
! 		}
! 	      else if (GET_CODE (PATTERN (our_prev)) == SET
! 		       && SET_DEST (PATTERN (our_prev)) == XEXP (note, 0))
! 		delete_computation (our_prev);
! 
! 	      break;
! 	    }
  
! 	  /* If OUR_PREV references the register that dies here, it is an
! 	     additional use.  Hence any prior SET isn't dead.  However, this
! 	     insn becomes the new place for the REG_DEAD note.  */
! 	  if (reg_overlap_mentioned_p (XEXP (note, 0),
! 				       PATTERN (our_prev)))
! 	    {
! 	      XEXP (note, 1) = REG_NOTES (our_prev);
! 	      REG_NOTES (our_prev) = note;
! 	      break;
! 	    }
! 	}
      }
  
    delete_insn (insn);
--- 3983,4002 ----
  	  || GET_CODE (XEXP (note, 0)) != REG)
  	continue;
  
!       if (set && reg_overlap_mentioned_p (SET_DEST (set), XEXP (note, 0)))
! 	set = NULL_RTX;
  
!       delete_prior_computation (note, insn);
!     }
  
!   /* The REG_DEAD note may have been omitted for a register
!      which is both set and used by the insn.  */
!   if (set
!       && GET_CODE (SET_DEST (set)) == REG
!       && reg_mentioned_p (SET_DEST (set), SET_SRC (set)))
!     {
!       note = gen_rtx_EXPR_LIST (REG_DEAD, SET_DEST (set), NULL_RTX);
!       delete_prior_computation (note, insn);
      }
  
    delete_insn (insn);
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------


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