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 fix / improve delete_prior_computation (version 2)


On Sun, 8 Apr 2001 13:06:45 -0700 Richard Henderson wrote:
> ... is a hack.  Use flow.c for proper dead code removal.

Perhaps this is easier to swallow. :-)

Currently delete_prior_computation only checks that a parallel
doesn't set other registers (it ignores other things that might
be present in the parallel) and doesn't handle a parallel which
contains unused sets.  The patch passes make bootstrap and check
on i386-pc-solaris2.7.  It also passes make and check on
arm-elf and powerpc-eabisim.

ChangeLog:

Sun Apr 22 23:12:52 EDT 2001  John Wehle  (john@feith.com)

	* jump.c: Include basic-block.h.
	(mark_live_reg): New function.
	(delete_prior_computation): Reimplement using flow.
	(delete_computation): Reimplement.
	(redirect_tablejump): Update delete_prior_computation call.
	* flow.c (propagate_one_insn): Respect reg notes when scanning
	dead code after flow2 has completed.

Enjoy!

-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/jump.c.ORIGINAL	Fri Apr 13 00:07:08 2001
--- gcc/jump.c	Sun Apr 22 13:53:23 2001
*************** Boston, MA 02111-1307, USA.  */
*** 57,62 ****
--- 57,63 ----
  #include "tm_p.h"
  #include "flags.h"
  #include "hard-reg-set.h"
+ #include "basic-block.h"
  #include "regs.h"
  #include "insn-config.h"
  #include "insn-attr.h"
*************** static void mark_modified_reg		PARAMS ((
*** 123,129 ****
  static void redirect_tablejump		PARAMS ((rtx, rtx));
  static void jump_optimize_1		PARAMS ((rtx, int, int, int, int, int));
  static int returnjump_p_1	        PARAMS ((rtx *, void *));
! static void delete_prior_computation    PARAMS ((rtx, rtx));
  
  /* Main external entry point into the jump optimizer.  See comments before
     jump_optimize_1 for descriptions of the arguments.  */
--- 124,131 ----
  static void redirect_tablejump		PARAMS ((rtx, rtx));
  static void jump_optimize_1		PARAMS ((rtx, int, int, int, int, int));
  static int returnjump_p_1	        PARAMS ((rtx *, void *));
! static void mark_live_reg		PARAMS ((rtx, rtx, void *));
! static void delete_prior_computation    PARAMS ((rtx));
  
  /* Main external entry point into the jump optimizer.  See comments before
     jump_optimize_1 for descriptions of the arguments.  */
*************** delete_barrier (insn)
*** 2606,2783 ****
    delete_insn (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
! 		    || GET_CODE (our_prev) == CALL_INSN);
!        our_prev = prev_nonnote_insn (our_prev))
!     {
!       rtx pat = PATTERN (our_prev);
  
!       /* If we reach a CALL which is not calling a const function
! 	 or the callee pops the arguments, then give up.  */
!       if (GET_CODE (our_prev) == CALL_INSN
! 	  && (! CONST_CALL_P (our_prev)
! 	      || GET_CODE (pat) != SET || GET_CODE (SET_SRC (pat)) != CALL))
! 	break;
! 
!       /* 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) && GET_CODE (our_prev) != CALL_INSN)
! 	    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)
  		{
! 		  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 dead code.  We also can't know if the registers being used are
!    dead or not at this point.
! 
!    Otherwise, look at all our REG_DEAD notes.  If a previous insn does
!    nothing other than set a register that dies in this insn, we can delete
!    that insn as well.
  
!    On machines with CC0, if CC0 is used in this insn, we may be able to
!    delete the insn that set it.  */
  
! static void
! delete_computation (insn)
!      rtx insn;
! {
!   rtx note, next;
  
! #ifdef HAVE_cc0
!   if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
!     {
!       rtx prev = prev_nonnote_insn (insn);
!       /* We assume that at this stage
! 	 CC's are always set explicitly
! 	 and always immediately before the jump that
! 	 will use them.  So if the previous insn
! 	 exists to set the CC's, delete it
! 	 (unless it performs auto-increments, etc.).  */
!       if (prev && GET_CODE (prev) == INSN
! 	  && 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.  */
! 	    REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_UNUSED,
! 						  cc0_rtx, REG_NOTES (prev));
! 	}
!     }
! #endif
  
!   for (note = REG_NOTES (insn); note; note = next)
      {
-       next = XEXP (note, 1);
- 
        if (REG_NOTE_KIND (note) != REG_DEAD
  	  /* Verify that the REG_NOTE is legitimate.  */
  	  || GET_CODE (XEXP (note, 0)) != REG)
  	continue;
  
!       delete_prior_computation (note, insn);
      }
  
    delete_insn (insn);
  }
  
--- 2608,2770 ----
    delete_insn (insn);
  }
  
! /* Mark register REG set by SETTER as alive in regset LIVE.
!    This is called via note_stores.  */
  
  static void
! mark_live_reg (reg, setter, live)
!      rtx reg, setter;
!      void *live;
  {
!   int regno;
!   int n;
  
!   if (GET_CODE (reg) == SUBREG)
!     reg = SUBREG_REG (reg);
  
!   if (GET_CODE (reg) != REG
!       || GET_CODE (setter) != SET)
!     return;
!   
!   regno = REGNO (reg);
!   n = regno < FIRST_PSEUDO_REGISTER
!       ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (reg, 0))) : 1;
!   while (n-- > 0)
!     SET_REGNO_REG_SET ((regset)live, regno + n);
! }
  
! /* Delete prior insns that compute values used only by INSN which the
!    caller is deleting.  This uses the REG_DEAD notes computed during
!    flow analysis.  If we are running before flow2, we need do nothing
!    since flow2 will delete dead code.  We also can't know if the
!    registers being used are dead or not at this point.
  
!    On machines with CC0, if CC0 is used in this insn, we may be able to
!    delete the insn that set it.  */
  
! static void
! delete_prior_computation (insn)
!      rtx insn;
! {
!   int i;
!   int max_reg = max_reg_num ();
!   int n;
!   int regno;
!   regset_head live_head;
!   regset live;
!   struct propagate_block_info *pbi;
!   rtx prev;
!   rtx note;
  
!   if (! flow2_completed)
!     {
! #ifdef HAVE_cc0
!       if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
! 	{
! 	  prev = prev_nonnote_insn (insn);
! 	  /* We assume that at this stage
! 	     CC's are always set explicitly
! 	     and always immediately before the jump that
! 	     will use them.  So if the previous insn
! 	     exists to set the CC's, delete it
! 	     (unless it performs auto-increments, etc.).  */
! 	  if (prev && GET_CODE (prev) == INSN
! 	      && sets_cc0_p (PATTERN (prev)))
  	    {
! 	      if (sets_cc0_p (PATTERN (prev)) > 0
! 		  && ! side_effects_p (PATTERN (prev)))
  		{
! 		  delete_prior_computation (prev);
! 		  delete_insn (prev);
  		}
+ 	      else
+ 		/* Otherwise, show that cc0 won't be used.  */
+ 		REG_NOTES (prev)
+ 		  = gen_rtx_EXPR_LIST (REG_UNUSED, cc0_rtx, REG_NOTES (prev));
  	    }
  	}
+ #endif
+       return;
      }
  
!   /* Unfortunately BLOCK_FOR_INSN isn't necessarily valid.  */
!   for (prev = PREV_INSN (insn);
!        prev && ! NOTE_INSN_BASIC_BLOCK_P (prev);
!        prev = PREV_INSN (prev))
!     ;
  
!   if (! prev)
!     return;
  
!   live = INITIALIZE_REG_SET (live_head);
  
!   /* Start by assuming that all the registers
!      are alive after this insn.  */
!   for (i = 0; i < max_reg; i++)
!     SET_REGNO_REG_SET (live, i);
  
!   /* Remove the ones known to be dead.  */
!   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
      {
        if (REG_NOTE_KIND (note) != REG_DEAD
  	  /* Verify that the REG_NOTE is legitimate.  */
  	  || GET_CODE (XEXP (note, 0)) != REG)
  	continue;
  
!       regno = REGNO (XEXP (note, 0));
!       n = regno < FIRST_PSEUDO_REGISTER
! 	  ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1;
!       while (n-- > 0)
! 	CLEAR_REGNO_REG_SET (live, regno + n);
!     }
! 
!   /* Assume that registers which are set are alive
!      even if there is a REG_DEAD note present since
!      the insn may be a no-op move.  */
!   note_stores (PATTERN (insn), mark_live_reg, live);
! 
!   /* Remove the ones known to be unused.  */
!   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
!     {
!       if (REG_NOTE_KIND (note) != REG_UNUSED
! 	  /* Verify that the REG_NOTE is legitimate.  */
! 	  || GET_CODE (XEXP (note, 0)) != REG)
! 	continue;
! 
!       regno = REGNO (XEXP (note, 0));
!       n = regno < FIRST_PSEUDO_REGISTER
! 	  ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1;
!       while (n-- > 0)
! 	CLEAR_REGNO_REG_SET (live, regno + n);
!     }
! 
!   pbi = init_propagate_block_info (NOTE_BASIC_BLOCK (prev), live, NULL, NULL,
! 				   PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
! 				   | PROP_KILL_DEAD_CODE);
! 
!   for (prev = PREV_INSN (insn);
!        prev && ! NOTE_INSN_BASIC_BLOCK_P (prev);
!        prev = propagate_one_insn (pbi, prev))
!     {
!       /* If we reach a SEQUENCE, give up since flow doesn't handle them.  */
!       if (INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
! 	break;
      }
  
+ 
+   free_propagate_block_info (pbi);
+ 
+   FREE_REG_SET (live);
+ }
+ 
+ /* Delete INSN and insns that compute values used only by INSN.  */
+ 
+ static void
+ delete_computation (insn)
+      rtx insn;
+ {
+ 
+   delete_prior_computation (insn);
    delete_insn (insn);
  }
  
*************** redirect_tablejump (jump, nlabel)
*** 3390,3396 ****
       rtx jump, nlabel;
  {
    register rtx olabel = JUMP_LABEL (jump);
-   rtx *notep, note, next;
  
    /* Add this jump to the jump_chain of NLABEL.  */
    if (jump_chain && INSN_UID (nlabel) < max_jump_chain
--- 3377,3382 ----
*************** redirect_tablejump (jump, nlabel)
*** 3400,3420 ****
        jump_chain[INSN_UID (nlabel)] = jump;
      }
  
!   for (notep = &REG_NOTES (jump), note = *notep; note; note = next)
!     {
!       next = XEXP (note, 1);
! 
!       if (REG_NOTE_KIND (note) != REG_DEAD
! 	  /* Verify that the REG_NOTE is legitimate.  */
! 	  || GET_CODE (XEXP (note, 0)) != REG
! 	  || ! reg_mentioned_p (XEXP (note, 0), PATTERN (jump)))
! 	notep = &XEXP (note, 1);
!       else
! 	{
! 	  delete_prior_computation (note, jump);
! 	  *notep = next;
! 	}
!     }
  
    PATTERN (jump) = gen_jump (nlabel);
    JUMP_LABEL (jump) = nlabel;
--- 3386,3392 ----
        jump_chain[INSN_UID (nlabel)] = jump;
      }
  
!   delete_prior_computation (jump);
  
    PATTERN (jump) = gen_jump (nlabel);
    JUMP_LABEL (jump) = nlabel;
*** gcc/flow.c.ORIGINAL	Fri Apr 13 00:01:33 2001
--- gcc/flow.c	Sun Apr 22 03:39:43 2001
*************** propagate_one_insn (pbi, insn)
*** 3691,3707 ****
    int insn_is_dead = 0;
    int libcall_is_dead = 0;
    rtx note;
    int i;
  
    if (! INSN_P (insn))
      return prev;
  
!   note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
    if (flags & PROP_SCAN_DEAD_CODE)
      {
        insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0, REG_NOTES (insn));
!       libcall_is_dead = (insn_is_dead && note != 0
! 			 && libcall_dead_p (pbi, note, insn));
      }
  
    /* If an instruction consists of just dead store(s) on final pass,
--- 3691,3728 ----
    int insn_is_dead = 0;
    int libcall_is_dead = 0;
    rtx note;
+   rtx retval_note;
    int i;
  
    if (! INSN_P (insn))
      return prev;
  
!   retval_note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
    if (flags & PROP_SCAN_DEAD_CODE)
      {
+       /* Note which registers are unused after this insn since they are
+ 	 not alive after this insn.  */
+       if (flow2_completed)
+ 	for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ 	  {
+ 	    int regno;
+ 	    int n;
+ 
+ 	    if (REG_NOTE_KIND (note) != REG_UNUSED
+ 		/* Verify that the REG_NOTE is legitimate.  */
+ 		|| GET_CODE (XEXP (note, 0)) != REG)
+ 	      continue;
+ 
+ 	    regno = REGNO (XEXP (note, 0));
+ 	    n = regno < FIRST_PSEUDO_REGISTER
+ 		? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1;
+ 	    while (n-- > 0)
+ 	      CLEAR_REGNO_REG_SET (pbi->reg_live, regno + n);
+ 	    }
+ 
        insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0, REG_NOTES (insn));
!       libcall_is_dead = (insn_is_dead && retval_note != 0
! 			 && libcall_dead_p (pbi, retval_note, insn));
      }
  
    /* If an instruction consists of just dead store(s) on final pass,
*************** propagate_one_insn (pbi, insn)
*** 3733,3741 ****
  	 so the next insn can't use it.  */
        pbi->cc0_live = 0;
  
        if (libcall_is_dead)
  	{
! 	  prev = propagate_block_delete_libcall (pbi->bb, insn, note);
  	  insn = NEXT_INSN (prev);
  	}
        else
--- 3754,3782 ----
  	 so the next insn can't use it.  */
        pbi->cc0_live = 0;
  
+       /* Note which registers died in this insn since they no longer
+ 	 need to be alive prior to this insn.  */
+       if (flow2_completed)
+ 	for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ 	  {
+ 	    int regno;
+ 	    int n;
+ 
+ 	    if (REG_NOTE_KIND (note) != REG_DEAD
+ 		/* Verify that the REG_NOTE is legitimate.  */
+ 		|| GET_CODE (XEXP (note, 0)) != REG)
+ 	      continue;
+ 
+ 	    regno = REGNO (XEXP (note, 0));
+ 	    n = regno < FIRST_PSEUDO_REGISTER
+ 		? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) : 1;
+ 	    while (n-- > 0)
+ 	      CLEAR_REGNO_REG_SET (pbi->reg_live, regno + n);
+ 	    }
+ 
        if (libcall_is_dead)
  	{
! 	  prev = propagate_block_delete_libcall (pbi->bb, insn, retval_note);
  	  insn = NEXT_INSN (prev);
  	}
        else
*************** propagate_one_insn (pbi, insn)
*** 3777,3783 ****
        /* Record the death of the dest reg.  */
        mark_set_regs (pbi, PATTERN (insn), insn);
  
!       insn = XEXP (note, 0);
        return PREV_INSN (insn);
      }
    else if (GET_CODE (PATTERN (insn)) == SET
--- 3818,3824 ----
        /* Record the death of the dest reg.  */
        mark_set_regs (pbi, PATTERN (insn), insn);
  
!       insn = XEXP (retval_note, 0);
        return PREV_INSN (insn);
      }
    else if (GET_CODE (PATTERN (insn)) == SET
*************** propagate_one_insn (pbi, insn)
*** 3807,3813 ****
        if (GET_CODE (insn) == CALL_INSN)
  	{
  	  register int i;
! 	  rtx note, cond;
  
  	  cond = NULL_RTX;
  	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
--- 3848,3854 ----
        if (GET_CODE (insn) == CALL_INSN)
  	{
  	  register int i;
! 	  rtx cond;
  
  	  cond = NULL_RTX;
  	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
*************** propagate_one_insn (pbi, insn)
*** 3858,3864 ****
        if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
  	{
  	  register int i;
! 	  rtx note, cond;
  
  	  cond = NULL_RTX;
  	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
--- 3899,3905 ----
        if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
  	{
  	  register int i;
! 	  rtx cond;
  
  	  cond = NULL_RTX;
  	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
-------------------------------------------------------------------------
|   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]