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]

ia32: resources


This patch is prep work for the peephole2 pass.  It unifies the two
copies of update_flow_info from the two schedulers and extends the
interface to be able to handle multiple source instructions.  I.e.
the old update_flow_info would only handle the one->many case of
redistributing reg notes for split_block_insns.  The new code 
handles the many->many case that ocurrs in rtl->rtl peepholes.


r~



	* haifa-sched.c (split_hard_reg_notes): Move to flow.c
	(new_insn_dead_notes): Likewise.
	(update_n_sets): Likewise.
	(update_flow_info): Move to flow.c, renamed to update_life_info;
	extend to handle multiple source insns.
	* flow.c: Include resource.h
	(unlink_insn_chain): New.
	(split_hard_reg_notes): New.
	(maybe_add_dead_note): New.
	(maybe_add_dead_note_use): New.
	(find_insn_with_note): New.
	(new_insn_dead_notes): New.
	(update_n_sets): New.
	(sets_reg_or_subreg_1, sets_reg_or_subreg): New.
	(maybe_remove_dead_notes): New.
	(update_life_info): New.
	(prepend_reg_notes): New.
	(replace_insns): New.
	* output.h (update_life_info): Declare.
	* recog.c (split_block_insns): Use update_life_info.
	* resource.c (find_free_register): Use reg_alloc_order, don't use
	fixed regs, make sure the mode is supported, don't use new regs.
	(reg_dead_p): New.
	* rtl.h (replace_insns): Declare.
	* sched.c (split_hard_reg_notes): Delete.
	(new_insn_dead_notes): Delete.
	(update_n_sets): Delete.
	(update_flow_info): Delete.

Index: flow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flow.c,v
retrieving revision 1.129
diff -c -p -d -r1.129 flow.c
*** flow.c	1999/08/09 13:59:44	1.129
--- flow.c	1999/08/09 23:25:54
*************** Boston, MA 02111-1307, USA.  */
*** 132,137 ****
--- 132,138 ----
  #include "toplev.h"
  #include "recog.h"
  #include "insn-flags.h"
+ #include "resource.h"
  
  #include "obstack.h"
  #define obstack_chunk_alloc xmalloc
*************** static void count_reg_sets		PROTO ((rtx)
*** 333,338 ****
--- 334,346 ----
  static void count_reg_references	PROTO ((rtx));
  static void notice_stack_pointer_modification PROTO ((rtx, rtx));
  static void invalidate_mems_from_autoinc	PROTO ((rtx));
+ static void maybe_remove_dead_notes	PROTO ((rtx, rtx, rtx, rtx,
+ 						rtx, rtx));
+ static int maybe_add_dead_note_use	PROTO ((rtx, rtx));
+ static int maybe_add_dead_note		PROTO ((rtx, rtx, rtx));
+ static int sets_reg_or_subreg		PROTO ((rtx, rtx));
+ static void update_n_sets 		PROTO ((rtx, int));
+ static void new_insn_dead_notes		PROTO ((rtx, rtx, rtx, rtx, rtx, rtx));
  void verify_flow_info			PROTO ((void));
  
  /* Find basic blocks of the current function.
*************** set_block_num (insn, bb)
*** 5029,5034 ****
--- 5037,6083 ----
       int bb;
  {
    set_block_for_insn (insn, BASIC_BLOCK (bb));
+ }
+ 
+ /* Unlink a chain of insns between START and FINISH inclusive, leaving notes
+    that must be paired, and return the new chain.  */
+ 
+ rtx
+ unlink_insn_chain (start, finish)
+      rtx start, finish;
+ {
+   rtx insert_point = PREV_INSN (start);
+   rtx chain = NULL_RTX, curr;
+ 
+   /* Unchain the insns one by one.  It would be quicker to delete all
+      of these with a single unchaining, rather than one at a time, but
+      we need to keep the NOTE's.  */
+ 
+   while (1)
+     {
+       rtx next = NEXT_INSN (start);
+ 
+       remove_insn (start);
+ 
+       /* ??? Despite the fact that we're patching out the insn, it's
+ 	 still referenced in LOG_LINKS.  Rather than try and track
+ 	 them all down and remove them, just mark the insn deleted.  */
+       INSN_DELETED_P (start) = 1;
+ 
+       if (GET_CODE (start) == NOTE && ! can_delete_note_p (start))
+ 	{
+ 	  add_insn_after (start, insert_point);
+ 	  insert_point = start;
+ 	}
+       else
+ 	{
+ 	  if (chain != NULL)
+ 	    {
+ 	      NEXT_INSN (curr) = start;
+ 	      PREV_INSN (start) = curr;
+ 	      curr = start;
+ 	    }
+ 	  else
+ 	    {
+ 	      chain = start;
+ 	      curr = start;
+ 	      PREV_INSN (chain) = NULL_RTX;
+ 	    }
+ 	}
+ 
+       if (start == finish)
+ 	break;
+       start = next;
+     }
+ 
+   if (chain != NULL_RTX)
+     NEXT_INSN (curr) = NULL_RTX;
+ 
+   return chain;
+ }
+ 
+ /* Subroutine of update_life_info.  Determines whether multiple
+    REG_NOTEs need to be distributed for the hard register mentioned in
+    NOTE.  This can happen if a reference to a hard register in the
+    original insns was split into several smaller hard register
+    references in the new insns.  */
+ 
+ static void
+ split_hard_reg_notes (curr_insn, note, first, last)
+      rtx curr_insn, note, first, last;
+ {
+   rtx reg, temp, link;
+   rtx insn;
+   int n_regs, i, new_reg;
+ 
+   reg = XEXP (note, 0);
+ 
+   if (REG_NOTE_KIND (note) != REG_DEAD
+       || GET_CODE (reg) != REG
+       || REGNO (reg) >= FIRST_PSEUDO_REGISTER
+       || HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) == 1)
+     {
+       XEXP (note, 1) = REG_NOTES (curr_insn);
+       REG_NOTES (curr_insn) = note;
+       return;
+     }
+ 
+   n_regs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
+ 
+   for (i = 0; i < n_regs; i++)
+     {
+       new_reg = REGNO (reg) + i;
+ 
+       /* Check for references to new_reg in the split insns.  */
+       for (insn = last; ; insn = PREV_INSN (insn))
+ 	{
+ 	  if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 	      && (temp = regno_use_in (new_reg, PATTERN (insn))))
+ 	    {
+ 	      /* Create a new reg dead note here.  */
+ 	      link = rtx_alloc (EXPR_LIST);
+ 	      PUT_REG_NOTE_KIND (link, REG_DEAD);
+ 	      XEXP (link, 0) = temp;
+ 	      XEXP (link, 1) = REG_NOTES (insn);
+ 	      REG_NOTES (insn) = link;
+ 
+ 	      /* If killed multiple registers here, then add in the excess.  */
+ 	      i += HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) - 1;
+ 
+ 	      break;
+ 	    }
+ 	  /* It isn't mentioned anywhere, so no new reg note is needed for
+ 	     this register.  */
+ 	  if (insn == first)
+ 	    break;
+ 	}
+     }
+ }
+ 
+ /* SET_INSN kills REG; add a REG_DEAD note mentioning REG to the last
+    use of REG in the insns after SET_INSN and before or including
+    LAST, if necessary.
+ 
+    A non-zero value is returned if we added a REG_DEAD note, or if we
+    determined that a REG_DEAD note because of this particular SET
+    wasn't necessary. */
+ 
+ static int
+ maybe_add_dead_note (reg, set_insn, last)
+      rtx reg, set_insn, last;
+ {
+   rtx insn;
+ 
+   for (insn = last; insn != set_insn; insn = PREV_INSN (insn))
+     {
+       rtx set;
+ 
+       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 	  && reg_overlap_mentioned_p (reg, PATTERN (insn))
+ 	  && (set = single_set (insn)))
+ 	{
+ 	  rtx insn_dest = SET_DEST (set);
+ 
+ 	  while (GET_CODE (insn_dest) == ZERO_EXTRACT
+ 		 || GET_CODE (insn_dest) == SUBREG
+ 		 || GET_CODE (insn_dest) == STRICT_LOW_PART
+ 		 || GET_CODE (insn_dest) == SIGN_EXTRACT)
+ 	    insn_dest = XEXP (insn_dest, 0);
+ 
+ 	  if (! rtx_equal_p (insn_dest, reg))
+ 	    {
+ 	      /* Use the same scheme as combine.c, don't put both REG_DEAD
+ 		 and REG_UNUSED notes on the same insn.  */
+ 	      if (! find_regno_note (insn, REG_UNUSED, REGNO (reg))
+ 		  && ! find_regno_note (insn, REG_DEAD, REGNO (reg)))
+ 		{
+ 		  rtx note = rtx_alloc (EXPR_LIST);
+ 		  PUT_REG_NOTE_KIND (note, REG_DEAD);
+ 		  XEXP (note, 0) = reg;
+ 		  XEXP (note, 1) = REG_NOTES (insn);
+ 		  REG_NOTES (insn) = note;
+ 		}
+ 	      return 1;
+ 	    }
+ 	  else if (reg_overlap_mentioned_p (reg, SET_SRC (set)))
+ 	    {
+ 	      /* We found an instruction that both uses the register and
+ 		 sets it, so no new REG_NOTE is needed for the previous
+ 		 set.  */
+ 	      return 0;
+ 	    }
+ 	}
+     }
+   return 0;
+ }
+ 
+ static int
+ maybe_add_dead_note_use (insn, dest)
+      rtx insn, dest;
+ {
+   rtx set;
+ 
+   /* We need to add a REG_DEAD note to the last place DEST is
+      referenced. */
+ 
+   if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+       && reg_mentioned_p (dest, PATTERN (insn))
+       && (set = single_set (insn)))
+     {
+       rtx insn_dest = SET_DEST (set);
+ 
+       while (GET_CODE (insn_dest) == ZERO_EXTRACT
+ 	     || GET_CODE (insn_dest) == SUBREG
+ 	     || GET_CODE (insn_dest) == STRICT_LOW_PART
+ 	     || GET_CODE (insn_dest) == SIGN_EXTRACT)
+ 	insn_dest = XEXP (insn_dest, 0);
+ 
+       if (! rtx_equal_p (insn_dest, dest))
+ 	{
+ 	  /* Use the same scheme as combine.c, don't put both REG_DEAD
+ 	     and REG_UNUSED notes on the same insn.  */
+ 	  if (! find_regno_note (insn, REG_UNUSED, REGNO (dest))
+ 	      && ! find_regno_note (insn, REG_DEAD, REGNO (dest)))
+ 	    {
+ 	      rtx note = rtx_alloc (EXPR_LIST);
+ 	      PUT_REG_NOTE_KIND (note, REG_DEAD);
+ 	      XEXP (note, 0) = dest;
+ 	      XEXP (note, 1) = REG_NOTES (insn);
+ 	      REG_NOTES (insn) = note;
+ 	    }
+ 	  return 1;
+ 	}
+     }
+   return 0;
+ }
+ 
+ /* Find the first insn in the set of insns from FIRST to LAST inclusive
+    that contains the note NOTE. */
+ rtx
+ find_insn_with_note (note, first, last)
+      rtx note, first, last;
+ {
+   rtx insn;
+ 
+   for (insn = first; insn != NULL_RTX; insn = NEXT_INSN (insn))
+     {
+       rtx temp = find_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
+       if (temp == note)
+ 	{
+ 	  return insn;
+ 	}
+       if (insn == last)
+ 	{
+ 	  break;
+ 	}
+     }
+   return NULL_RTX;
+ }
+      
+ /* Subroutine of update_life_info.  Determines whether a SET or
+    CLOBBER in an insn created by splitting needs a REG_DEAD or
+    REG_UNUSED note added.  */
+ 
+ static void
+ new_insn_dead_notes (pat, insn, first, last, orig_first_insn, orig_last_insn)
+      rtx pat, insn, first, last, orig_first_insn, orig_last_insn;
+ {
+   rtx dest, tem;
+ 
+   if (GET_CODE (pat) != CLOBBER && GET_CODE (pat) != SET)
+     abort ();
+ 
+   dest = XEXP (pat, 0);
+ 
+   while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
+ 	 || GET_CODE (dest) == STRICT_LOW_PART
+ 	 || GET_CODE (dest) == SIGN_EXTRACT)
+     dest = XEXP (dest, 0);
+ 
+   if (GET_CODE (dest) == REG)
+     {
+       /* If the original insns already used this register, we may not
+          add new notes for it.  One example for a replacement that
+          needs this test is when a multi-word memory access with
+          register-indirect addressing is changed into multiple memory
+          accesses with auto-increment and one adjusting add
+          instruction for the address register.
+ 
+ 	 However, there is a problem with this code. We're assuming
+ 	 that any registers that are set in the new insns are either
+ 	 set/referenced in the old insns (and thus "inherit" the
+ 	 liveness of the old insns), or are registers that are dead
+ 	 before we enter this part of the stream (and thus should be
+ 	 dead when we leave).
+ 
+ 	 To do this absolutely correctly, we must determine the actual
+ 	 liveness of the registers before we go randomly adding
+ 	 REG_DEAD notes. This can probably be accurately done by
+ 	 calling mark_referenced_resources() on the old stream before
+ 	 replacing the old insns.  */
+ 
+       for (tem = orig_first_insn; tem != NULL_RTX; tem = NEXT_INSN (tem))
+ 	{
+ 	  if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
+ 	      && reg_referenced_p (dest, PATTERN (tem)))
+ 	    return;
+ 	  if (tem == orig_last_insn)
+ 	    break;
+ 	}
+       /* So it's a new register, presumably only used within this
+ 	 group of insns. Find the last insn in the set of new insns
+ 	 that DEST is referenced in, and add a dead note to it. */
+       if (! maybe_add_dead_note (dest, insn, last))
+ 	{
+ 	  /* If this is a set, it must die somewhere, unless it is the
+ 	     dest of the original insn, and thus is live after the
+ 	     original insn.  Abort if it isn't supposed to be live after
+ 	     the original insn.
+ 
+ 	     If this is a clobber, then just add a REG_UNUSED note.  */
+ 	  if (GET_CODE (pat) == CLOBBER)
+ 	    {
+ 	      rtx note = rtx_alloc (EXPR_LIST);
+ 	      PUT_REG_NOTE_KIND (note, REG_UNUSED);
+ 	      XEXP (note, 0) = dest;
+ 	      XEXP (note, 1) = REG_NOTES (insn);
+ 	      REG_NOTES (insn) = note;
+ 	      return;
+ 	    }
+ 	  else
+ 	    {
+ 	      struct resources res;
+ 	      rtx curr;
+ 
+ 	      CLEAR_RESOURCE (&res);
+ 	      for (curr = orig_first_insn;
+ 		   curr != NULL_RTX;
+ 		   curr = NEXT_INSN (curr))
+ 		{
+ 		  if (GET_RTX_CLASS (GET_CODE (curr)) == 'i')
+ 		    mark_set_resources (PATTERN (curr), &res, 0, 0);
+ 		  if (TEST_HARD_REG_BIT (res.regs, REGNO (dest)))
+ 		    break;
+ 		  if (curr == orig_last_insn)
+ 		    break;
+ 		}
+ 
+ 	      /* In case reg was not used later, it is dead store.
+ 	         add REG_UNUSED note.  */
+ 	      if (! TEST_HARD_REG_BIT (res.regs, REGNO (dest)))
+ 	        {
+ 	          rtx note = rtx_alloc (EXPR_LIST);
+ 	          PUT_REG_NOTE_KIND (note, REG_UNUSED);
+ 	          XEXP (note, 0) = dest;
+ 	          XEXP (note, 1) = REG_NOTES (insn);
+ 	          REG_NOTES (insn) = note;
+ 	          return;
+ 	        }
+ 	    }
+ 	}
+       if (insn != first)
+ 	{
+ 	  rtx set = single_set (insn);
+ 	  /* If this is a set, scan backwards for a previous
+ 	     reference, and attach a REG_DEAD note to it. But we don't
+ 	     want to do it if the insn is both using and setting the
+ 	     register.
+ 
+ 	     Global registers are always live.  */
+ 	  if (set && ! reg_overlap_mentioned_p (dest, SET_SRC (pat))
+ 	      && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
+ 		  || ! global_regs[REGNO (dest)]))
+ 	    {
+ 	      for (tem = PREV_INSN (insn);
+ 		   tem != NULL_RTX; tem = PREV_INSN (tem))
+ 		{
+ 		  if (maybe_add_dead_note_use (tem, dest))
+ 		    break;
+ 		  if (tem == first)
+ 		    break;
+ 		}
+ 	    }
+ 	}
+     }
+ }
+ 
+ /* Subroutine of update_life_info.  Update the value of reg_n_sets for all
+    registers modified by X.  INC is -1 if the containing insn is being deleted,
+    and is 1 if the containing insn is a newly generated insn.  */
+ 
+ static void
+ update_n_sets (x, inc)
+      rtx x;
+      int inc;
+ {
+   rtx dest = SET_DEST (x);
+ 
+   while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
+ 	 || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
+     dest = SUBREG_REG (dest);
+ 
+   if (GET_CODE (dest) == REG)
+     {
+       int regno = REGNO (dest);
+       
+       if (regno < FIRST_PSEUDO_REGISTER)
+ 	{
+ 	  register int i;
+ 	  int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
+ 	  
+ 	  for (i = regno; i < endregno; i++)
+ 	    REG_N_SETS (i) += inc;
+ 	}
+       else
+ 	REG_N_SETS (regno) += inc;
+     }
+ }
+ 
+ /* Scan INSN for a SET that sets REG. If it sets REG via a SUBREG,
+    then return 2. If it sets REG directly, return 1. Otherwise, return
+    0. */
+ 
+ static int sets_reg_or_subreg_ret;
+ static rtx sets_reg_or_subreg_rtx;
+ 
+ static void
+ sets_reg_or_subreg_1 (x, set)
+      rtx x, set;
+ {
+   if (rtx_equal_p (x, sets_reg_or_subreg_rtx))
+     {
+       if (x == XEXP (set, 0))
+ 	sets_reg_or_subreg_ret = 1;
+       else if (GET_CODE (XEXP (set, 0)) == SUBREG)
+ 	sets_reg_or_subreg_ret = 2;
+     }
+ }
+ 
+ static int
+ sets_reg_or_subreg (insn, reg)
+      rtx insn;
+      rtx reg;
+ {
+   if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+     return 0;
+ 
+   sets_reg_or_subreg_ret = 0;
+   sets_reg_or_subreg_rtx = reg;
+   note_stores (PATTERN (insn), sets_reg_or_subreg_1);
+   return sets_reg_or_subreg_ret;
+ }
+ 
+ /* If a replaced SET_INSN (which is part of the insns between
+    OLD_FIRST_INSN and OLD_LAST_INSN inclusive) is modifying a multiple
+    register target, and the original dest is now set in the new insns
+    (between FIRST_INSN and LAST_INSN inclusive) by one or more subreg
+    sets, then the new insns no longer kill the destination of the
+    original insn.
+ 
+    We may also be directly using the register in the new insns before
+    setting it.
+ 
+    In either case, if there exists an instruction in the same basic
+    block before the replaced insns which uses the original dest (and
+    contains a corresponding REG_DEAD note), then we must remove this
+    REG_DEAD note. 
+ 
+    SET_INSN is the insn that contains the SET; it may be a PARALLEL
+    containing the SET insn.
+ 
+    SET is the actual SET insn proper. */
+ 
+ static void
+ maybe_remove_dead_notes (set_insn, set, first_insn, last_insn, 
+ 			 old_first_insn, old_last_insn)
+      rtx set_insn, set;
+      rtx first_insn, last_insn;
+      rtx old_first_insn, old_last_insn;
+ {
+   rtx insn;
+   rtx stop_insn = NEXT_INSN (last_insn);
+   int set_type = 0;
+   rtx set_dest;
+   rtx set_pattern;
+ 
+   if (GET_RTX_CLASS (GET_CODE (set)) != 'i')
+     return;
+ 
+   set_pattern = PATTERN (set);
+ 
+   if (GET_CODE (set_pattern) == PARALLEL)
+     {
+       int i;
+ 
+       for (i = 0; i < XVECLEN (set_pattern, 0); i++)
+ 	{
+ 	  maybe_remove_dead_notes (set_insn, XVECEXP (set_pattern, 0, i),
+ 				   first_insn, last_insn, 
+ 				   old_first_insn, old_last_insn);
+ 	}
+       return;
+     }
+ 
+   if (GET_CODE (set_pattern) != SET)
+     {
+       return;
+     }
+ 
+   set_dest = SET_DEST (set_pattern);
+ 
+   if (GET_CODE (set_dest) != REG)
+     {
+       return;
+     }
+ 
+   /* We have a set of a REG. First we need to determine if this set is
+      both using and setting the register. (FIXME: if this is in a
+      PARALLEL, we will have to check the other exprs as well.) */
+   if (reg_overlap_mentioned_p (set_dest, SET_SRC (set_pattern)))
+     {
+       return;
+     }
+ 
+   /* Now determine if we used or set the register in the old insns
+      previous to this one. */
+ 
+   for (insn = old_first_insn; insn != set_insn; insn = NEXT_INSN (insn))
+     {
+       if (reg_overlap_mentioned_p (set_dest, insn))
+ 	{
+ 	  return;
+ 	}
+     }
+ 
+   /* Now determine if we're setting it in the new insns, or using
+      it. */
+   for (insn = first_insn; insn != stop_insn; insn = NEXT_INSN (insn))
+     {
+       set_type = sets_reg_or_subreg (insn, set_dest);
+       if (set_type != 0)
+ 	{
+ 	  break;
+ 	}
+       else if (reg_overlap_mentioned_p (set_dest, insn))
+ 	{
+ 	  /* Is the reg now used in this new insn?  -- This is probably an
+ 	     error. */
+ 	  set_type = 2;
+ 	  break;
+ 	}
+     }
+   if (set_type == 2)
+     {
+       /* The register is being set via a SUBREG or is being used in
+ 	 some other way, so it's no longer dead.
+ 
+ 	 Search backwards from first_insn, looking for the first insn
+ 	 that uses the original dest.  Stop if we pass a CODE_LABEL or
+ 	 a JUMP_INSN.
+ 
+ 	 If we find such an insn and it has a REG_DEAD note referring
+ 	 to the original dest, then delete the note.  */
+ 
+       for (insn = first_insn; insn != NULL_RTX; insn = PREV_INSN (insn))
+ 	{
+ 	  if (GET_CODE (insn) == CODE_LABEL
+ 	      || GET_CODE (insn) == JUMP_INSN)
+ 	    break;
+ 	  else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 		   && reg_mentioned_p (set_dest, insn))
+ 	    {
+ 	      rtx note = find_regno_note (insn, REG_DEAD, REGNO (set_dest));
+ 	      if (note != NULL_RTX)
+ 		{
+ 		  remove_note (insn, note);
+ 		}
+ 	      /* ??? -- Is this right? */
+ 	      break;
+ 	    }
+ 	}
+     }
+   else if (set_type == 0)
+     {
+       /* The reg is not being set or used in the new insns at all. */
+       int i, regno;
+ 
+       /* Should never reach here for a pseudo reg.  */
+       if (REGNO (set_dest) >= FIRST_PSEUDO_REGISTER)
+ 	abort ();
+ 
+       /* This can happen for a hard register, if the new insns do not
+ 	 contain instructions which would be no-ops referring to the
+ 	 old registers. 
+ 
+ 	 We try to verify that this is the case by checking to see if
+ 	 the original instruction uses all of the registers that it
+ 	 set. This case is OK, because deleting a no-op can not affect
+ 	 REG_DEAD notes on other insns. If this is not the case, then
+ 	 abort.  */
+ 
+       regno = REGNO (set_dest);
+       for (i = HARD_REGNO_NREGS (regno, GET_MODE (set_dest)) - 1;
+ 	   i >= 0; i--)
+ 	{
+ 	  if (! refers_to_regno_p (regno + i, regno + i + 1, set,
+ 				   NULL_PTR))
+ 	    break;
+ 	}
+       if (i >= 0)
+ 	abort ();
+     }
+ }
+ 
+ /* Updates all flow-analysis related quantities (including REG_NOTES) for
+    the insns from FIRST to LAST inclusive that were created by replacing
+    the insns from ORIG_INSN_FIRST to ORIG_INSN_LAST inclusive.  NOTES
+    are the original REG_NOTES.  */
+ 
+ void
+ update_life_info (notes, first, last, orig_first_insn, orig_last_insn)
+      rtx notes;
+      rtx first, last;
+      rtx orig_first_insn, orig_last_insn;
+ {
+   rtx insn, note;
+   rtx next;
+   rtx orig_dest, temp;
+   rtx orig_insn;
+   rtx tem;
+ 
+   /* Get and save the destination set by the original insn, if there
+      was only one insn replaced.  */
+ 
+   if (orig_first_insn == orig_last_insn)
+     {
+       orig_insn = orig_first_insn;
+       orig_dest = single_set (orig_insn);
+       if (orig_dest)
+ 	orig_dest = SET_DEST (orig_dest);
+     }
+   else
+     {
+       orig_insn = NULL_RTX;
+       orig_dest = NULL_RTX;
+     }
+ 
+   /* Move REG_NOTES from the original insns to where they now belong.  */
+ 
+   for (note = notes; note; note = next)
+     {
+       next = XEXP (note, 1);
+       switch (REG_NOTE_KIND (note))
+ 	{
+ 	case REG_DEAD:
+ 	case REG_UNUSED:
+ 	  /* Move these notes from the original insn to the last new
+ 	     insn where the register is mentioned.  */
+ 
+ 	  for (insn = last; ; insn = PREV_INSN (insn))
+ 	    {
+ 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 		  && reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+ 		{
+ 		  /* Sometimes need to convert REG_UNUSED notes to
+ 		     REG_DEAD notes. */
+ 		  if (REG_NOTE_KIND (note) == REG_UNUSED
+ 		      && GET_CODE (XEXP (note, 0)) == REG
+ 		      && ! dead_or_set_p (insn, XEXP (note, 0)))
+ 		    {
+ 		      PUT_REG_NOTE_KIND (note, REG_DEAD);
+ 		    }
+ 		  split_hard_reg_notes (insn, note, first, last);
+ 		  /* The reg only dies in one insn, the last one that uses
+ 		     it.  */
+ 		  break;
+ 		}
+ 	      /* It must die somewhere, fail if we couldn't find where it died.
+ 
+ 		 We abort because otherwise the register will be live
+ 		 longer than it should, and we'll probably take an
+ 		 abort later. What we should do instead is search back
+ 		 and find the appropriate places to insert the note.  */
+ 	      if (insn == first)
+ 		{
+ 		  if (REG_NOTE_KIND (note) == REG_DEAD)
+ 		    {
+ 		      abort ();
+ 		    }
+ 		  break;
+ 		}
+ 	    }
+ 	  break;
+ 
+ 	case REG_WAS_0:
+ 	  {
+ 	    rtx note_dest;
+ 
+ 	    /* If the insn that set the register to 0 was deleted, this
+ 	       note cannot be relied on any longer.  The destination might
+ 	       even have been moved to memory.
+ 	       This was observed for SH4 with execute/920501-6.c compilation,
+ 	       -O2 -fomit-frame-pointer -finline-functions .  */
+ 
+ 	    if (GET_CODE (XEXP (note, 0)) == NOTE
+ 		|| INSN_DELETED_P (XEXP (note, 0)))
+ 	      break;
+ 	    if (orig_insn != NULL_RTX)
+ 	      {
+ 		note_dest = orig_dest;
+ 	      }
+ 	    else
+ 	      {
+ 		note_dest = find_insn_with_note (note, first, last);
+ 		if (note_dest != NULL_RTX)
+ 		  {
+ 		    note_dest = single_set (orig_dest);
+ 		    if (note_dest != NULL_RTX)
+ 		      {
+ 			note_dest = SET_DEST (orig_dest);
+ 		      }
+ 		  }
+ 	      }
+ 	      /* This note applies to the dest of the original insn.  Find the
+ 		 first new insn that now has the same dest, and move the note
+ 		 there.  */
+ 
+ 	    if (! note_dest)
+ 	      abort ();
+ 
+ 	    for (insn = first; ; insn = NEXT_INSN (insn))
+ 	      {
+ 		if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 		    && (temp = single_set (insn))
+ 		    && rtx_equal_p (SET_DEST (temp), note_dest))
+ 		  {
+ 		    XEXP (note, 1) = REG_NOTES (insn);
+ 		    REG_NOTES (insn) = note;
+ 		    /* The reg is only zero before one insn, the first that
+ 		       uses it.  */
+ 		    break;
+ 		  }
+ 		/* If this note refers to a multiple word hard
+ 		   register, it may have been split into several smaller
+ 		   hard register references.  We could split the notes,
+ 		   but simply dropping them is good enough.  */
+ 		if (GET_CODE (note_dest) == REG
+ 		    && REGNO (note_dest) < FIRST_PSEUDO_REGISTER
+ 		    && HARD_REGNO_NREGS (REGNO (note_dest),
+ 					 GET_MODE (note_dest)) > 1)
+ 		  break;
+ 		/* It must be set somewhere; fail if we couldn't find
+ 		   where it was set.  */
+ 		if (insn == last)
+ 		  abort ();
+ 	      }
+ 	  }
+ 	  break;
+ 
+ 	case REG_EQUAL:
+ 	case REG_EQUIV:
+ 	  /* A REG_EQUIV or REG_EQUAL note on an insn with more than one
+ 	     set is meaningless.  Just drop the note.  */
+ 	  if (! orig_dest)
+ 	    break;
+ 
+ 	case REG_NO_CONFLICT:
+ 	  /* These notes apply to the dest of the original insn.  Find the last
+ 	     new insn that now has the same dest, and move the note there.  
+ 
+ 	     If we are replacing multiple insns, just drop the note. */
+ 
+ 	  if (! orig_insn)
+ 	    break;
+ 
+ 	  if (! orig_dest)
+ 	    abort ();
+ 
+ 	  for (insn = last; ; insn = PREV_INSN (insn))
+ 	    {
+ 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 		  && (temp = single_set (insn))
+ 		  && rtx_equal_p (SET_DEST (temp), orig_dest))
+ 		{
+ 		  XEXP (note, 1) = REG_NOTES (insn);
+ 		  REG_NOTES (insn) = note;
+ 		  /* Only put this note on one of the new insns.  */
+ 		  break;
+ 		}
+ 
+ 	      /* The original dest must still be set someplace.  Abort if we
+ 		 couldn't find it.  */
+ 	      if (insn == first)
+ 		{
+ 		  /* However, if this note refers to a multiple word hard
+ 		     register, it may have been split into several smaller
+ 		     hard register references.  We could split the notes,
+ 		     but simply dropping them is good enough.  */
+ 		  if (GET_CODE (orig_dest) == REG
+ 		      && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+ 		      && HARD_REGNO_NREGS (REGNO (orig_dest),
+ 					   GET_MODE (orig_dest)) > 1)
+ 		    break;
+ 		  /* Likewise for multi-word memory references.  */
+ 		  if (GET_CODE (orig_dest) == MEM
+ 		      && GET_MODE_SIZE (GET_MODE (orig_dest)) > MOVE_MAX)
+ 		    break;
+ 		  abort ();
+ 		}
+ 	    }
+ 	  break;
+ 
+ 	case REG_LIBCALL:
+ 	  /* Move a REG_LIBCALL note to the first insn created, and update
+ 	     the corresponding REG_RETVAL note.  */
+ 	  XEXP (note, 1) = REG_NOTES (first);
+ 	  REG_NOTES (first) = note;
+ 
+ 	  insn = XEXP (note, 0);
+ 	  note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
+ 	  if (note)
+ 	    XEXP (note, 0) = first;
+ 	  break;
+ 
+ 	case REG_EXEC_COUNT:
+ 	  /* Move a REG_EXEC_COUNT note to the first insn created.  */
+ 	  XEXP (note, 1) = REG_NOTES (first);
+ 	  REG_NOTES (first) = note;
+ 	  break;
+ 
+ 	case REG_RETVAL:
+ 	  /* Move a REG_RETVAL note to the last insn created, and update
+ 	     the corresponding REG_LIBCALL note.  */
+ 	  XEXP (note, 1) = REG_NOTES (last);
+ 	  REG_NOTES (last) = note;
+ 
+ 	  insn = XEXP (note, 0);
+ 	  note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
+ 	  if (note)
+ 	    XEXP (note, 0) = last;
+ 	  break;
+ 
+ 	case REG_NONNEG:
+ 	case REG_BR_PROB:
+ 	  /* This should be moved to whichever instruction is a JUMP_INSN.  */
+ 
+ 	  for (insn = last; ; insn = PREV_INSN (insn))
+ 	    {
+ 	      if (GET_CODE (insn) == JUMP_INSN)
+ 		{
+ 		  XEXP (note, 1) = REG_NOTES (insn);
+ 		  REG_NOTES (insn) = note;
+ 		  /* Only put this note on one of the new insns.  */
+ 		  break;
+ 		}
+ 	      /* Fail if we couldn't find a JUMP_INSN.  */
+ 	      if (insn == first)
+ 		abort ();
+ 	    }
+ 	  break;
+ 
+ 	case REG_INC:
+ 	  /* reload sometimes leaves obsolete REG_INC notes around.  */
+ 	  if (reload_completed)
+ 	    break;
+ 	  /* This should be moved to whichever instruction now has the
+ 	     increment operation.  */
+ 	  abort ();
+ 
+ 	case REG_LABEL:
+ 	  /* Should be moved to the new insn(s) which use the label.  */
+ 	  for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
+ 	    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ 		&& reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+ 	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
+ 						    XEXP (note, 0),
+ 						    REG_NOTES (insn));
+ 	  break;
+ 
+ 	case REG_CC_SETTER:
+ 	case REG_CC_USER:
+ 	  /* These two notes will never appear until after reorg, so we don't
+ 	     have to handle them here.  */
+ 	default:
+ 	  abort ();
+ 	}
+     }
+ 
+   /* Each new insn created has a new set.  If the destination is a
+      register, then this reg is now live across several insns, whereas
+      previously the dest reg was born and died within the same insn.
+      To reflect this, we now need a REG_DEAD note on the insn where
+      this dest reg dies.
+ 
+      Similarly, the new insns may have clobbers that need REG_UNUSED
+      notes.  */
+ 
+   for (insn = first; ;insn = NEXT_INSN (insn))
+     {
+       rtx pat;
+       int i;
+ 
+       pat = PATTERN (insn);
+       if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
+ 	new_insn_dead_notes (pat, insn, first, last, 
+ 			     orig_first_insn, orig_last_insn);
+       else if (GET_CODE (pat) == PARALLEL)
+ 	{
+ 	  for (i = 0; i < XVECLEN (pat, 0); i++)
+ 	    {
+ 	      if (GET_CODE (XVECEXP (pat, 0, i)) == SET
+ 		  || GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER)
+ 		{
+ 		  rtx parpat = XVECEXP (pat, 0, i);
+ 
+ 		  new_insn_dead_notes (parpat, insn, first, last, 
+ 				       orig_first_insn, orig_last_insn);
+ 		}
+ 	    }
+ 	}
+       if (insn == last)
+ 	{
+ 	  break;
+ 	}
+     }
+ 
+   /* Check to see if we have any REG_DEAD notes on insns previous to
+      the new ones that are now incorrect and need to be removed. */
+ 
+   for (insn = orig_first_insn; ; insn = NEXT_INSN (insn))
+     {
+       maybe_remove_dead_notes (insn, insn, first, last,
+ 			       orig_first_insn, orig_last_insn);
+ 
+       if (insn == orig_last_insn)
+ 	break;
+     }
+ 
+   /* Update reg_n_sets.  This is necessary to prevent local alloc from
+      converting REG_EQUAL notes to REG_EQUIV when the new insns are setting
+      a reg multiple times instead of once. */
+ 
+   for (tem = orig_first_insn; tem != NULL_RTX; tem = NEXT_INSN (tem))
+     {
+       rtx x;
+       RTX_CODE code;
+ 
+       if (GET_RTX_CLASS (GET_CODE (tem)) != 'i')
+ 	continue;
+ 
+        x = PATTERN (tem);
+       code = GET_CODE (x);
+       if (code == SET || code == CLOBBER)
+ 	update_n_sets (x, -1);
+       else if (code == PARALLEL)
+ 	{
+ 	  int i;
+ 	  for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ 	    {
+ 	      code = GET_CODE (XVECEXP (x, 0, i));
+ 	      if (code == SET || code == CLOBBER)
+ 		update_n_sets (XVECEXP (x, 0, i), -1);
+ 	    }
+ 	}
+       if (tem == orig_last_insn)
+ 	break;
+     }
+ 
+   for (insn = first; ; insn = NEXT_INSN (insn))
+     {
+       rtx x = PATTERN (insn);
+       RTX_CODE code = GET_CODE (x);
+ 
+       if (code == SET || code == CLOBBER)
+ 	update_n_sets (x, 1);
+       else if (code == PARALLEL)
+ 	{
+ 	  int i;
+ 	  for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ 	    {
+ 	      code = GET_CODE (XVECEXP (x, 0, i));
+ 	      if (code == SET || code == CLOBBER)
+ 		update_n_sets (XVECEXP (x, 0, i), 1);
+ 	    }
+ 	}
+ 
+       if (insn == last)
+ 	break;
+     }
+ }
+ 
+ /* Prepends the set of REG_NOTES in NEW to NOTES, and returns NEW. */
+ static rtx
+ prepend_reg_notes (notes, new)
+      rtx notes, new;
+ {
+   rtx end;
+ 
+   if (new == NULL_RTX)
+     {
+       return notes;
+     }
+   if (notes == NULL_RTX)
+     {
+       return new;
+     }
+   end = new;
+   while (XEXP (end, 1) != NULL_RTX)
+     {
+       end = XEXP (end, 1);
+     }
+   XEXP (end, 1) = notes;
+   return new;
+ }
+ 
+ /* Replace the insns from FIRST to LAST inclusive with the set of insns in
+    NEW, and update the life analysis info accordingly. */
+ void
+ replace_insns (first, last, first_new, notes)
+      rtx first, last, first_new, notes;
+ {
+   rtx stop = NEXT_INSN (last);
+   rtx last_new;
+   rtx curr, next;
+   rtx prev = PREV_INSN (first);
+   int i;
+ 
+   if (notes == NULL_RTX)
+     {
+       for (curr = first; curr != stop; curr = NEXT_INSN (curr))
+ 	{
+ 	  notes = prepend_reg_notes (notes, REG_NOTES (curr));
+ 	}
+     }
+   for (curr = first; curr; curr = next)
+     {
+       next = NEXT_INSN (curr);
+       delete_insn (curr);
+       if (curr == last)
+ 	break;
+     }
+   last_new = emit_insn_after (first_new, prev);
+   first_new = NEXT_INSN (prev);
+   for (i = 0; i < n_basic_blocks; i++)
+     {
+       if (BLOCK_HEAD (i) == first)
+ 	{
+ 	  BLOCK_HEAD (i) = first_new;
+ 	}
+       if (BLOCK_END (i) == last)
+ 	{
+ 	  BLOCK_END (i) = last_new;
+ 	}
+     }
+   /* This is probably bogus. */
+   if (first_new == last_new)
+     {
+       if (GET_CODE (first_new) == SEQUENCE)
+ 	{
+ 	  first_new = XVECEXP (first_new, 0, 0);
+ 	  last_new = XVECEXP (last_new, 0, XVECLEN (last_new, 0) - 1);
+ 	}
+     }
+   update_life_info (notes, first_new, last_new, first, last);
  }
  
  /* Verify the CFG consistency.  This function check some CFG invariants and
Index: haifa-sched.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/haifa-sched.c,v
retrieving revision 1.92
diff -c -p -d -r1.92 haifa-sched.c
*** haifa-sched.c	1999/08/09 13:59:45	1.92
--- haifa-sched.c	1999/08/09 23:25:54
*************** static void attach_deaths_insn PROTO ((r
*** 452,460 ****
  static int new_sometimes_live PROTO ((struct sometimes *, int, int));
  static void finish_sometimes_live PROTO ((struct sometimes *, int));
  static int schedule_block PROTO ((int, int));
- static void split_hard_reg_notes PROTO ((rtx, rtx, rtx));
- static void new_insn_dead_notes PROTO ((rtx, rtx, rtx, rtx));
- static void update_n_sets PROTO ((rtx, int));
  static char *safe_concat PROTO ((char *, char *, char *));
  static int insn_issue_delay PROTO ((rtx));
  static int birthing_insn_p PROTO ((rtx));
--- 452,457 ----
*************** schedule_region (rgn)
*** 7773,8455 ****
  
    FREE_REG_SET (reg_pending_sets);
    FREE_REG_SET (reg_pending_clobbers);
- }
- 
- /* Subroutine of update_flow_info.  Determines whether any new REG_NOTEs are
-    needed for the hard register mentioned in the note.  This can happen
-    if the reference to the hard register in the original insn was split into
-    several smaller hard register references in the split insns.  */
- 
- static void
- split_hard_reg_notes (note, first, last)
-      rtx note, first, last;
- {
-   rtx reg, temp, link;
-   int n_regs, i, new_reg;
-   rtx insn;
- 
-   /* Assume that this is a REG_DEAD note.  */
-   if (REG_NOTE_KIND (note) != REG_DEAD)
-     abort ();
- 
-   reg = XEXP (note, 0);
- 
-   n_regs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
- 
-   for (i = 0; i < n_regs; i++)
-     {
-       new_reg = REGNO (reg) + i;
- 
-       /* Check for references to new_reg in the split insns.  */
-       for (insn = last;; insn = PREV_INSN (insn))
- 	{
- 	  if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 	      && (temp = regno_use_in (new_reg, PATTERN (insn))))
- 	    {
- 	      /* Create a new reg dead note ere.  */
- 	      link = alloc_EXPR_LIST (REG_DEAD, temp, REG_NOTES (insn));
- 	      REG_NOTES (insn) = link;
- 
- 	      /* If killed multiple registers here, then add in the excess.  */
- 	      i += HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) - 1;
- 
- 	      break;
- 	    }
- 	  /* It isn't mentioned anywhere, so no new reg note is needed for
- 	     this register.  */
- 	  if (insn == first)
- 	    break;
- 	}
-     }
- }
- 
- /* Subroutine of update_flow_info.  Determines whether a SET or CLOBBER in an
-    insn created by splitting needs a REG_DEAD or REG_UNUSED note added.  */
- 
- static void
- new_insn_dead_notes (pat, insn, last, orig_insn)
-      rtx pat, insn, last, orig_insn;
- {
-   rtx dest, tem, set;
- 
-   /* PAT is either a CLOBBER or a SET here.  */
-   dest = XEXP (pat, 0);
- 
-   while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
- 	 || GET_CODE (dest) == STRICT_LOW_PART
- 	 || GET_CODE (dest) == SIGN_EXTRACT)
-     dest = XEXP (dest, 0);
- 
-   if (GET_CODE (dest) == REG)
-     {
-       /* If the original insn already used this register, we may not add new
-          notes for it.  One example for a split that needs this test is
- 	 when a multi-word memory access with register-indirect addressing
- 	 is split into multiple memory accesses with auto-increment and
- 	 one adjusting add instruction for the address register.  */
-       if (reg_referenced_p (dest, PATTERN (orig_insn)))
- 	return;
-       for (tem = last; tem != insn; tem = PREV_INSN (tem))
- 	{
- 	  if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
- 	      && reg_overlap_mentioned_p (dest, PATTERN (tem))
- 	      && (set = single_set (tem)))
- 	    {
- 	      rtx tem_dest = SET_DEST (set);
- 
- 	      while (GET_CODE (tem_dest) == ZERO_EXTRACT
- 		     || GET_CODE (tem_dest) == SUBREG
- 		     || GET_CODE (tem_dest) == STRICT_LOW_PART
- 		     || GET_CODE (tem_dest) == SIGN_EXTRACT)
- 		tem_dest = XEXP (tem_dest, 0);
- 
- 	      if (!rtx_equal_p (tem_dest, dest))
- 		{
- 		  /* Use the same scheme as combine.c, don't put both REG_DEAD
- 		     and REG_UNUSED notes on the same insn.  */
- 		  if (!find_regno_note (tem, REG_UNUSED, REGNO (dest))
- 		      && !find_regno_note (tem, REG_DEAD, REGNO (dest)))
- 		    {
- 		      rtx note = alloc_EXPR_LIST (REG_DEAD, dest,
- 						  REG_NOTES (tem));
- 		      REG_NOTES (tem) = note;
- 		    }
- 		  /* The reg only dies in one insn, the last one that uses
- 		     it.  */
- 		  break;
- 		}
- 	      else if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
- 		/* We found an instruction that both uses the register,
- 		   and sets it, so no new REG_NOTE is needed for this set.  */
- 		break;
- 	    }
- 	}
-       /* If this is a set, it must die somewhere, unless it is the dest of
-          the original insn, and hence is live after the original insn.  Abort
-          if it isn't supposed to be live after the original insn.
- 
-          If this is a clobber, then just add a REG_UNUSED note.  */
-       if (tem == insn)
- 	{
- 	  int live_after_orig_insn = 0;
- 	  rtx pattern = PATTERN (orig_insn);
- 	  int i;
- 
- 	  if (GET_CODE (pat) == CLOBBER)
- 	    {
- 	      rtx note = alloc_EXPR_LIST (REG_UNUSED, dest, REG_NOTES (insn));
- 	      REG_NOTES (insn) = note;
- 	      return;
- 	    }
- 
- 	  /* The original insn could have multiple sets, so search the
- 	     insn for all sets.  */
- 	  if (GET_CODE (pattern) == SET)
- 	    {
- 	      if (reg_overlap_mentioned_p (dest, SET_DEST (pattern)))
- 		live_after_orig_insn = 1;
- 	    }
- 	  else if (GET_CODE (pattern) == PARALLEL)
- 	    {
- 	      for (i = 0; i < XVECLEN (pattern, 0); i++)
- 		if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
- 		    && reg_overlap_mentioned_p (dest,
- 						SET_DEST (XVECEXP (pattern,
- 								   0, i))))
- 		  live_after_orig_insn = 1;
- 	    }
- 
- 	  if (!live_after_orig_insn)
- 	    abort ();
- 	}
-     }
- }
- 
- /* Subroutine of update_flow_info.  Update the value of reg_n_sets for all
-    registers modified by X.  INC is -1 if the containing insn is being deleted,
-    and is 1 if the containing insn is a newly generated insn.  */
- 
- static void
- update_n_sets (x, inc)
-      rtx x;
-      int inc;
- {
-   rtx dest = SET_DEST (x);
- 
-   while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
-       || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
-     dest = SUBREG_REG (dest);
- 
-   if (GET_CODE (dest) == REG)
-     {
-       int regno = REGNO (dest);
- 
-       if (regno < FIRST_PSEUDO_REGISTER)
- 	{
- 	  register int i;
- 	  int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
- 
- 	  for (i = regno; i < endregno; i++)
- 	    REG_N_SETS (i) += inc;
- 	}
-       else
- 	REG_N_SETS (regno) += inc;
-     }
- }
- 
- /* Updates all flow-analysis related quantities (including REG_NOTES) for
-    the insns from FIRST to LAST inclusive that were created by splitting
-    ORIG_INSN.  NOTES are the original REG_NOTES.  */
- 
- void
- update_flow_info (notes, first, last, orig_insn)
-      rtx notes;
-      rtx first, last;
-      rtx orig_insn;
- {
-   rtx insn, note;
-   rtx next;
-   rtx orig_dest, temp;
-   rtx set;
- 
-   /* Get and save the destination set by the original insn.  */
- 
-   orig_dest = single_set (orig_insn);
-   if (orig_dest)
-     orig_dest = SET_DEST (orig_dest);
- 
-   /* Move REG_NOTES from the original insn to where they now belong.  */
- 
-   for (note = notes; note; note = next)
-     {
-       next = XEXP (note, 1);
-       switch (REG_NOTE_KIND (note))
- 	{
- 	case REG_DEAD:
- 	case REG_UNUSED:
- 	  /* Move these notes from the original insn to the last new insn where
- 	     the register is now set.  */
- 
- 	  for (insn = last;; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- 		{
- 		  /* If this note refers to a multiple word hard register, it
- 		     may have been split into several smaller hard register
- 		     references, so handle it specially.  */
- 		  temp = XEXP (note, 0);
- 		  if (REG_NOTE_KIND (note) == REG_DEAD
- 		      && GET_CODE (temp) == REG
- 		      && REGNO (temp) < FIRST_PSEUDO_REGISTER
- 		      && HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) > 1)
- 		    split_hard_reg_notes (note, first, last);
- 		  else
- 		    {
- 		      XEXP (note, 1) = REG_NOTES (insn);
- 		      REG_NOTES (insn) = note;
- 		    }
- 
- 		  /* Sometimes need to convert REG_UNUSED notes to REG_DEAD
- 		     notes.  */
- 		  /* ??? This won't handle multiple word registers correctly,
- 		     but should be good enough for now.  */
- 		  if (REG_NOTE_KIND (note) == REG_UNUSED
- 		      && GET_CODE (XEXP (note, 0)) != SCRATCH
- 		      && !dead_or_set_p (insn, XEXP (note, 0)))
- 		    PUT_REG_NOTE_KIND (note, REG_DEAD);
- 
- 		  /* The reg only dies in one insn, the last one that uses
- 		     it.  */
- 		  break;
- 		}
- 	      /* It must die somewhere, fail it we couldn't find where it died.
- 
- 	         If this is a REG_UNUSED note, then it must be a temporary
- 	         register that was not needed by this instantiation of the
- 	         pattern, so we can safely ignore it.  */
- 	      if (insn == first)
- 		{			
- 		  if (REG_NOTE_KIND (note) != REG_UNUSED)
- 		    abort ();
- 
- 		  break;
- 		}
- 	    }
- 	  break;
- 
- 	case REG_WAS_0:
- 	  /* If the insn that set the register to 0 was deleted, this
- 	     note cannot be relied on any longer.  The destination might
- 	     even have been moved to memory.
-              This was observed for SH4 with execute/920501-6.c compilation,
- 	     -O2 -fomit-frame-pointer -finline-functions .  */
- 	  if (GET_CODE (XEXP (note, 0)) == NOTE
- 	      || INSN_DELETED_P (XEXP (note, 0)))
- 	    break;
- 	  /* This note applies to the dest of the original insn.  Find the
- 	     first new insn that now has the same dest, and move the note
- 	     there.  */
- 
- 	  if (!orig_dest)
- 	    abort ();
- 
- 	  for (insn = first;; insn = NEXT_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && (temp = single_set (insn))
- 		  && rtx_equal_p (SET_DEST (temp), orig_dest))
- 		{
- 		  XEXP (note, 1) = REG_NOTES (insn);
- 		  REG_NOTES (insn) = note;
- 		  /* The reg is only zero before one insn, the first that
- 		     uses it.  */
- 		  break;
- 		}
- 	      /* If this note refers to a multiple word hard
- 		 register, it may have been split into several smaller
- 		 hard register references.  We could split the notes,
- 		 but simply dropping them is good enough.  */
- 	      if (GET_CODE (orig_dest) == REG
- 		  && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
- 		  && HARD_REGNO_NREGS (REGNO (orig_dest),
- 				       GET_MODE (orig_dest)) > 1)
- 		    break;
- 	      /* It must be set somewhere, fail if we couldn't find where it
- 	         was set.  */
- 	      if (insn == last)
- 		abort ();
- 	    }
- 	  break;
- 
- 	case REG_EQUAL:
- 	case REG_EQUIV:
- 	  /* A REG_EQUIV or REG_EQUAL note on an insn with more than one
- 	     set is meaningless.  Just drop the note.  */
- 	  if (!orig_dest)
- 	    break;
- 
- 	case REG_NO_CONFLICT:
- 	  /* These notes apply to the dest of the original insn.  Find the last
- 	     new insn that now has the same dest, and move the note there.  */
- 
- 	  if (!orig_dest)
- 	    abort ();
- 
- 	  for (insn = last;; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && (temp = single_set (insn))
- 		  && rtx_equal_p (SET_DEST (temp), orig_dest))
- 		{
- 		  XEXP (note, 1) = REG_NOTES (insn);
- 		  REG_NOTES (insn) = note;
- 		  /* Only put this note on one of the new insns.  */
- 		  break;
- 		}
- 
- 	      /* The original dest must still be set someplace.  Abort if we
- 	         couldn't find it.  */
- 	      if (insn == first)
- 		{
- 		  /* However, if this note refers to a multiple word hard
- 		     register, it may have been split into several smaller
- 		     hard register references.  We could split the notes,
- 		     but simply dropping them is good enough.  */
- 		  if (GET_CODE (orig_dest) == REG
- 		      && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
- 		      && HARD_REGNO_NREGS (REGNO (orig_dest),
- 					   GET_MODE (orig_dest)) > 1)
- 		    break;
- 		  /* Likewise for multi-word memory references.  */
- 		  if (GET_CODE (orig_dest) == MEM
- 		      && SIZE_FOR_MODE (orig_dest) > UNITS_PER_WORD)
- 		    break;
- 		  abort ();
- 		}
- 	    }
- 	  break;
- 
- 	case REG_LIBCALL:
- 	  /* Move a REG_LIBCALL note to the first insn created, and update
- 	     the corresponding REG_RETVAL note.  */
- 	  XEXP (note, 1) = REG_NOTES (first);
- 	  REG_NOTES (first) = note;
- 
- 	  insn = XEXP (note, 0);
- 	  note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
- 	  if (note)
- 	    XEXP (note, 0) = first;
- 	  break;
- 
- 	case REG_EXEC_COUNT:
- 	  /* Move a REG_EXEC_COUNT note to the first insn created.  */
- 	  XEXP (note, 1) = REG_NOTES (first);
- 	  REG_NOTES (first) = note;
- 	  break;
- 
- 	case REG_RETVAL:
- 	  /* Move a REG_RETVAL note to the last insn created, and update
- 	     the corresponding REG_LIBCALL note.  */
- 	  XEXP (note, 1) = REG_NOTES (last);
- 	  REG_NOTES (last) = note;
- 
- 	  insn = XEXP (note, 0);
- 	  note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
- 	  if (note)
- 	    XEXP (note, 0) = last;
- 	  break;
- 
- 	case REG_NONNEG:
- 	case REG_BR_PROB:
- 	  /* This should be moved to whichever instruction is a JUMP_INSN.  */
- 
- 	  for (insn = last;; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_CODE (insn) == JUMP_INSN)
- 		{
- 		  XEXP (note, 1) = REG_NOTES (insn);
- 		  REG_NOTES (insn) = note;
- 		  /* Only put this note on one of the new insns.  */
- 		  break;
- 		}
- 	      /* Fail if we couldn't find a JUMP_INSN.  */
- 	      if (insn == first)
- 		abort ();
- 	    }
- 	  break;
- 
- 	case REG_INC:
- 	  /* reload sometimes leaves obsolete REG_INC notes around.  */
- 	  if (reload_completed)
- 	    break;
- 	  /* This should be moved to whichever instruction now has the
- 	     increment operation.  */
- 	  abort ();
- 
- 	case REG_LABEL:
- 	  /* Should be moved to the new insn(s) which use the label.  */
- 	  for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
- 	    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		&& reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- 	      {
- 	        REG_NOTES (insn) = alloc_EXPR_LIST (REG_LABEL,
- 						    XEXP (note, 0),
- 						    REG_NOTES (insn));
- 	      }
- 	  break;
- 
- 	case REG_CC_SETTER:
- 	case REG_CC_USER:
- 	  /* These two notes will never appear until after reorg, so we don't
- 	     have to handle them here.  */
- 	default:
- 	  abort ();
- 	}
-     }
- 
-   /* Each new insn created, except the last, has a new set.  If the destination
-      is a register, then this reg is now live across several insns, whereas
-      previously the dest reg was born and died within the same insn.  To
-      reflect this, we now need a REG_DEAD note on the insn where this
-      dest reg dies.
- 
-      Similarly, the new insns may have clobbers that need REG_UNUSED notes.  */
- 
-   for (insn = first; insn != last; insn = NEXT_INSN (insn))
-     {
-       rtx pat;
-       int i;
- 
-       pat = PATTERN (insn);
-       if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
- 	new_insn_dead_notes (pat, insn, last, orig_insn);
-       else if (GET_CODE (pat) == PARALLEL)
- 	{
- 	  for (i = 0; i < XVECLEN (pat, 0); i++)
- 	    if (GET_CODE (XVECEXP (pat, 0, i)) == SET
- 		|| GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER)
- 	      new_insn_dead_notes (XVECEXP (pat, 0, i), insn, last, orig_insn);
- 	}
-     }
- 
-   /* If any insn, except the last, uses the register set by the last insn,
-      then we need a new REG_DEAD note on that insn.  In this case, there
-      would not have been a REG_DEAD note for this register in the original
-      insn because it was used and set within one insn.  */
- 
-   set = single_set (last);
-   if (set)
-     {
-       rtx dest = SET_DEST (set);
- 
-       while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
- 	     || GET_CODE (dest) == STRICT_LOW_PART
- 	     || GET_CODE (dest) == SIGN_EXTRACT)
- 	dest = XEXP (dest, 0);
- 
-       if (GET_CODE (dest) == REG
- 	  /* Global registers are always live, so the code below does not
- 	     apply to them.  */
- 	  && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
- 	      || ! global_regs[REGNO (dest)]))
- 	{
- 	  rtx stop_insn = PREV_INSN (first);
- 
- 	  /* If the last insn uses the register that it is setting, then
- 	     we don't want to put a REG_DEAD note there.  Search backwards
- 	     to find the first insn that sets but does not use DEST.  */
- 
- 	  insn = last;
- 	  if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
- 	    {
- 	      for (insn = PREV_INSN (insn); insn != first;
- 		   insn = PREV_INSN (insn))
- 		{
- 		  if ((set = single_set (insn))
- 		      && reg_mentioned_p (dest, SET_DEST (set))
- 		      && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
- 		    break;
- 		}
- 	    }
- 
- 	  /* Now find the first insn that uses but does not set DEST.  */
- 
- 	  for (insn = PREV_INSN (insn); insn != stop_insn;
- 	       insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && reg_mentioned_p (dest, PATTERN (insn))
- 		  && (set = single_set (insn)))
- 		{
- 		  rtx insn_dest = SET_DEST (set);
- 
- 		  while (GET_CODE (insn_dest) == ZERO_EXTRACT
- 			 || GET_CODE (insn_dest) == SUBREG
- 			 || GET_CODE (insn_dest) == STRICT_LOW_PART
- 			 || GET_CODE (insn_dest) == SIGN_EXTRACT)
- 		    insn_dest = XEXP (insn_dest, 0);
- 
- 		  if (insn_dest != dest)
- 		    {
- 		      note = alloc_EXPR_LIST (REG_DEAD, dest, REG_NOTES (insn));
- 		      REG_NOTES (insn) = note;
- 		      /* The reg only dies in one insn, the last one
- 			 that uses it.  */
- 		      break;
- 		    }
- 		}
- 	    }
- 	}
-     }
- 
-   /* If the original dest is modifying a multiple register target, and the
-      original instruction was split such that the original dest is now set
-      by two or more SUBREG sets, then the split insns no longer kill the
-      destination of the original insn.
- 
-      In this case, if there exists an instruction in the same basic block,
-      before the split insn, which uses the original dest, and this use is
-      killed by the original insn, then we must remove the REG_DEAD note on
-      this insn, because it is now superfluous.
- 
-      This does not apply when a hard register gets split, because the code
-      knows how to handle overlapping hard registers properly.  */
-   if (orig_dest && GET_CODE (orig_dest) == REG)
-     {
-       int found_orig_dest = 0;
-       int found_split_dest = 0;
- 
-       for (insn = first;; insn = NEXT_INSN (insn))
- 	{
- 	  rtx pat;
- 	  int i;
- 
- 	  /* I'm not sure if this can happen, but let's be safe.  */
- 	  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
- 	    continue;
- 
- 	  pat = PATTERN (insn);
- 	  i = GET_CODE (pat) == PARALLEL ? XVECLEN (pat, 0) : 0;
- 	  set = pat;
- 
- 	  for (;;)
- 	    {
- 	      if (GET_CODE (set) == SET)
- 		{
- 		  if (GET_CODE (SET_DEST (set)) == REG
- 		      && REGNO (SET_DEST (set)) == REGNO (orig_dest))
- 		    {
- 		      found_orig_dest = 1;
- 		      break;
- 		    }
- 		  else if (GET_CODE (SET_DEST (set)) == SUBREG
- 			   && SUBREG_REG (SET_DEST (set)) == orig_dest)
- 		    {
- 		      found_split_dest = 1;
- 		      break;
- 		    }
- 		}
- 	      if (--i < 0)
- 		break;
- 	      set = XVECEXP (pat, 0, i);
- 	    }
- 
- 	  if (insn == last)
- 	    break;
- 	}
- 
-       if (found_split_dest)
- 	{
- 	  /* Search backwards from FIRST, looking for the first insn that uses
- 	     the original dest.  Stop if we pass a CODE_LABEL or a JUMP_INSN.
- 	     If we find an insn, and it has a REG_DEAD note, then delete the
- 	     note.  */
- 
- 	  for (insn = first; insn; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_CODE (insn) == CODE_LABEL
- 		  || GET_CODE (insn) == JUMP_INSN)
- 		break;
- 	      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		       && reg_mentioned_p (orig_dest, insn))
- 		{
- 		  note = find_regno_note (insn, REG_DEAD, REGNO (orig_dest));
- 		  if (note)
- 		    remove_note (insn, note);
- 		}
- 	    }
- 	}
-       else if (!found_orig_dest)
- 	{
- 	  int i, regno;
- 
- 	  /* Should never reach here for a pseudo reg.  */
- 	  if (REGNO (orig_dest) >= FIRST_PSEUDO_REGISTER)
- 	    abort ();
- 
- 	  /* This can happen for a hard register, if the splitter
- 	     does not bother to emit instructions which would be no-ops.
- 	     We try to verify that this is the case by checking to see if
- 	     the original instruction uses all of the registers that it
- 	     set.  This case is OK, because deleting a no-op can not affect
- 	     REG_DEAD notes on other insns.  If this is not the case, then
- 	     abort.  */
- 	  
- 	  regno = REGNO (orig_dest);
- 	  for (i = HARD_REGNO_NREGS (regno, GET_MODE (orig_dest)) - 1;
- 	       i >= 0; i--)
- 	    if (! refers_to_regno_p (regno + i, regno + i + 1, orig_insn,
- 				     NULL_PTR))
- 	      break;
- 	  if (i >= 0)
- 	    abort ();
- 	}
-     }
- 
-   /* Update reg_n_sets.  This is necessary to prevent local alloc from
-      converting REG_EQUAL notes to REG_EQUIV when splitting has modified
-      a reg from set once to set multiple times.  */
- 
-   {
-     rtx x = PATTERN (orig_insn);
-     RTX_CODE code = GET_CODE (x);
- 
-     if (code == SET || code == CLOBBER)
-       update_n_sets (x, -1);
-     else if (code == PARALLEL)
-       {
- 	int i;
- 	for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- 	  {
- 	    code = GET_CODE (XVECEXP (x, 0, i));
- 	    if (code == SET || code == CLOBBER)
- 	      update_n_sets (XVECEXP (x, 0, i), -1);
- 	  }
-       }
- 
-     for (insn = first;; insn = NEXT_INSN (insn))
-       {
- 	x = PATTERN (insn);
- 	code = GET_CODE (x);
- 
- 	if (code == SET || code == CLOBBER)
- 	  update_n_sets (x, 1);
- 	else if (code == PARALLEL)
- 	  {
- 	    int i;
- 	    for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- 	      {
- 		code = GET_CODE (XVECEXP (x, 0, i));
- 		if (code == SET || code == CLOBBER)
- 		  update_n_sets (XVECEXP (x, 0, i), 1);
- 	      }
- 	  }
- 
- 	if (insn == last)
- 	  break;
-       }
-   }
  }
  
  /* The one entry point in this file.  DUMP_FILE is the dump file for
--- 7770,7775 ----
Index: output.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/output.h,v
retrieving revision 1.26
diff -c -p -d -r1.26 output.h
*** output.h	1999/08/09 13:59:47	1.26
--- output.h	1999/08/09 23:25:54
*************** extern void find_basic_blocks         PR
*** 132,137 ****
--- 132,138 ----
  extern void free_basic_block_vars     PROTO((int));
  extern void set_block_num             PROTO((rtx, int));
  extern void life_analysis             PROTO((rtx, int, FILE *, int));
+ extern void update_life_info	        PROTO((rtx, rtx, rtx, rtx, rtx));
  #endif
  
  /* Functions in varasm.c.  */
Index: recog.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/recog.c,v
retrieving revision 1.35
diff -c -p -d -r1.35 recog.c
*** recog.c	1999/08/09 13:59:47	1.35
--- recog.c	1999/08/09 23:25:54
*************** split_block_insns (b, do_split)
*** 2669,2675 ****
  	      /* try_split returns the NOTE that INSN became.  */
  	      first = NEXT_INSN (first);
  #ifdef INSN_SCHEDULING
! 	      update_flow_info (notes, first, last, insn);
  #endif
  	      PUT_CODE (insn, NOTE);
  	      NOTE_SOURCE_FILE (insn) = 0;
--- 2669,2675 ----
  	      /* try_split returns the NOTE that INSN became.  */
  	      first = NEXT_INSN (first);
  #ifdef INSN_SCHEDULING
! 	      update_life_info (notes, first, last, insn, insn);
  #endif
  	      PUT_CODE (insn, NOTE);
  	      NOTE_SOURCE_FILE (insn) = 0;
Index: resource.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/resource.c,v
retrieving revision 1.7
diff -c -p -d -r1.7 resource.c
*** resource.c	1999/08/09 13:59:50	1.7
--- resource.c	1999/08/09 23:25:54
*************** find_free_register (current_insn, class_
*** 1264,1277 ****
  
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
      {
!       int success = 1;
  
!       if (! TEST_HARD_REG_BIT (reg_class_contents[class], i))
  	continue;
!       for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
  	{
! 	  if (TEST_HARD_REG_BIT (*reg_set, i + j)
! 	      || TEST_HARD_REG_BIT (used.regs, i + j))
  	    {
  	      success = 0;
  	      break;
--- 1264,1296 ----
  
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
      {
!       int regno;
!       int success;
  
! #ifdef REG_ALLOC_ORDER
!       regno = reg_alloc_order [i];
! #else
!       regno = i;
! #endif
! 
!       /* Don't allocate fixed registers.  */
!       if (fixed_regs[regno])
  	continue;
!       /* Make sure the register is of the right class.  */
!       if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
! 	continue;
!       /* And can support the mode we need.  */
!       if (! HARD_REGNO_MODE_OK (regno, mode))
! 	continue;
!       /* And that we don't create an extra save/restore.  */
!       if (! call_used_regs[regno] && ! regs_ever_live[regno])
! 	continue;
! 
!       success = 1;
!       for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
  	{
! 	  if (TEST_HARD_REG_BIT (*reg_set, regno + j)
! 	      || TEST_HARD_REG_BIT (used.regs, regno + j))
  	    {
  	      success = 0;
  	      break;
*************** find_free_register (current_insn, class_
*** 1279,1290 ****
  	}
        if (success)
  	{
! 	  for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
  	    {
! 	      SET_HARD_REG_BIT (*reg_set, i + j);
  	    }
! 	  return gen_rtx_REG (mode, i);
  	}
      }
    return NULL_RTX;
  }
--- 1298,1330 ----
  	}
        if (success)
  	{
! 	  for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
  	    {
! 	      SET_HARD_REG_BIT (*reg_set, regno + j);
  	    }
! 	  return gen_rtx_REG (mode, regno);
  	}
      }
    return NULL_RTX;
+ }
+ 
+ /* Return true if REG is dead at CURRENT_INSN.  */
+ 
+ int
+ reg_dead_p (current_insn, reg)
+      rtx current_insn, reg;
+ {
+   struct resources used;
+   int regno, j;
+ 
+   mark_target_live_regs (get_insns (), current_insn, &used);
+   
+   regno = REGNO (reg);
+   for (j = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; j >= 0; j--)
+     {
+       if (TEST_HARD_REG_BIT (used.regs, regno + j))
+ 	return 0;
+     }
+ 
+   return 1;
  }
Index: rtl.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.110
diff -c -p -d -r1.110 rtl.h
*** rtl.h	1999/08/09 13:59:52	1.110
--- rtl.h	1999/08/09 23:25:54
*************** extern void recompute_reg_usage		PROTO (
*** 1415,1420 ****
--- 1415,1421 ----
  extern void dump_flow_info		PROTO ((FILE *));
  #endif
  extern void free_bb_mem			PROTO ((void));
+ extern void replace_insns               PROTO ((rtx, rtx, rtx, rtx));
  
  /* In expmed.c */
  extern void init_expmed			PROTO ((void));
Index: sched.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/sched.c,v
retrieving revision 1.39
diff -c -p -d -r1.39 sched.c
*** sched.c	1999/08/09 13:59:52	1.39
--- sched.c	1999/08/09 23:25:55
*************** static int new_sometimes_live		PROTO((st
*** 344,352 ****
  static void finish_sometimes_live	PROTO((struct sometimes *, int));
  static rtx reemit_notes			PROTO((rtx, rtx));
  static void schedule_block		PROTO((int, FILE *));
- static void split_hard_reg_notes	PROTO((rtx, rtx, rtx));
- static void new_insn_dead_notes		PROTO((rtx, rtx, rtx, rtx));
- static void update_n_sets		PROTO((rtx, int));
  
  /* Main entry point of this file.  */
  void schedule_insns	PROTO((FILE *));
--- 344,349 ----
*************** ret:
*** 3543,4226 ****
    FREE_REG_SET (old_live_regs);
  
    return;
- }
- 
- /* Subroutine of update_flow_info.  Determines whether any new REG_NOTEs are
-    needed for the hard register mentioned in the note.  This can happen
-    if the reference to the hard register in the original insn was split into
-    several smaller hard register references in the split insns.  */
- 
- static void
- split_hard_reg_notes (note, first, last)
-   rtx note, first, last;
- {
-   rtx reg, temp, link;
-   int n_regs, i, new_reg;
-   rtx insn;
- 
-   /* Assume that this is a REG_DEAD note.  */
-   if (REG_NOTE_KIND (note) != REG_DEAD)
-     abort ();
- 
-   reg = XEXP (note, 0);
- 
-   n_regs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
- 
-   for (i = 0; i < n_regs; i++)
-     {
-       new_reg = REGNO (reg) + i;
- 
-       /* Check for references to new_reg in the split insns.  */
-       for (insn = last; ; insn = PREV_INSN (insn))
- 	{
- 	  if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 	      && (temp = regno_use_in (new_reg, PATTERN (insn))))
- 	    {
- 	      /* Create a new reg dead note here.  */
- 	      link = rtx_alloc (EXPR_LIST);
- 	      PUT_REG_NOTE_KIND (link, REG_DEAD);
- 	      XEXP (link, 0) = temp;
- 	      XEXP (link, 1) = REG_NOTES (insn);
- 	      REG_NOTES (insn) = link;
- 
- 	      /* If killed multiple registers here, then add in the excess.  */
- 	      i += HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) - 1;
- 
- 	      break;
- 	    }
- 	  /* It isn't mentioned anywhere, so no new reg note is needed for
- 	     this register.  */
- 	  if (insn == first)
- 	    break;
- 	}
-     }
- }
- 
- /* Subroutine of update_flow_info.  Determines whether a SET or CLOBBER in an
-    insn created by splitting needs a REG_DEAD or REG_UNUSED note added.  */
- 
- static void
- new_insn_dead_notes (pat, insn, last, orig_insn)
-      rtx pat, insn, last, orig_insn;
- {
-   rtx dest, tem, set;
- 
-   /* PAT is either a CLOBBER or a SET here.  */
-   dest = XEXP (pat, 0);
- 
-   while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
- 	 || GET_CODE (dest) == STRICT_LOW_PART
- 	 || GET_CODE (dest) == SIGN_EXTRACT)
-     dest = XEXP (dest, 0);
- 
-   if (GET_CODE (dest) == REG)
-     {
-       /* If the original insn already used this register, we may not add new
-          notes for it.  One example for a split that needs this test is
- 	 when a multi-word memory access with register-indirect addressing
- 	 is split into multiple memory accesses with auto-increment and
- 	 one adjusting add instruction for the address register.  */
-       if (reg_referenced_p (dest, PATTERN (orig_insn)))
- 	return;
-       for (tem = last; tem != insn; tem = PREV_INSN (tem))
- 	{
- 	  if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
- 	      && reg_overlap_mentioned_p (dest, PATTERN (tem))
- 	      && (set = single_set (tem)))
- 	    {
- 	      rtx tem_dest = SET_DEST (set);
- 
- 	      while (GET_CODE (tem_dest) == ZERO_EXTRACT
- 		     || GET_CODE (tem_dest) == SUBREG
- 		     || GET_CODE (tem_dest) == STRICT_LOW_PART
- 		     || GET_CODE (tem_dest) == SIGN_EXTRACT)
- 		tem_dest = XEXP (tem_dest, 0);
- 
- 	      if (! rtx_equal_p (tem_dest, dest))
- 		{
- 		  /* Use the same scheme as combine.c, don't put both REG_DEAD
- 		     and REG_UNUSED notes on the same insn.  */
- 		  if (! find_regno_note (tem, REG_UNUSED, REGNO (dest))
- 		      && ! find_regno_note (tem, REG_DEAD, REGNO (dest)))
- 		    {
- 		      rtx note = rtx_alloc (EXPR_LIST);
- 		      PUT_REG_NOTE_KIND (note, REG_DEAD);
- 		      XEXP (note, 0) = dest;
- 		      XEXP (note, 1) = REG_NOTES (tem);
- 		      REG_NOTES (tem) = note;
- 		    }
- 		  /* The reg only dies in one insn, the last one that uses
- 		     it.  */
- 		  break;
- 		}
- 	      else if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
- 		/* We found an instruction that both uses the register,
- 		   and sets it, so no new REG_NOTE is needed for this set.  */
- 		break;
- 	    }
- 	}
-       /* If this is a set, it must die somewhere, unless it is the dest of
- 	 the original insn, and hence is live after the original insn.  Abort
- 	 if it isn't supposed to be live after the original insn.
- 
- 	 If this is a clobber, then just add a REG_UNUSED note.  */
-       if (tem == insn)
- 	{
- 	  int live_after_orig_insn = 0;
- 	  rtx pattern = PATTERN (orig_insn);
- 	  int i;
- 
- 	  if (GET_CODE (pat) == CLOBBER)
- 	    {
- 	      rtx note = rtx_alloc (EXPR_LIST);
- 	      PUT_REG_NOTE_KIND (note, REG_UNUSED);
- 	      XEXP (note, 0) = dest;
- 	      XEXP (note, 1) = REG_NOTES (insn);
- 	      REG_NOTES (insn) = note;
- 	      return;
- 	    }
- 
- 	  /* The original insn could have multiple sets, so search the
- 	     insn for all sets.  */
- 	  if (GET_CODE (pattern) == SET)
- 	    {
- 	      if (reg_overlap_mentioned_p (dest, SET_DEST (pattern)))
- 		live_after_orig_insn = 1;
- 	    }
- 	  else if (GET_CODE (pattern) == PARALLEL)
- 	    {
- 	      for (i = 0; i < XVECLEN (pattern, 0); i++)
- 		if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
- 		    && reg_overlap_mentioned_p (dest,
- 						SET_DEST (XVECEXP (pattern,
- 								   0, i))))
- 		  live_after_orig_insn = 1;
- 	    }
- 
- 	  if (! live_after_orig_insn)
- 	    abort ();
- 	}
-     }
- }
- 
- /* Subroutine of update_flow_info.  Update the value of reg_n_sets for all
-    registers modified by X.  INC is -1 if the containing insn is being deleted,
-    and is 1 if the containing insn is a newly generated insn.  */
- 
- static void
- update_n_sets (x, inc)
-      rtx x;
-      int inc;
- {
-   rtx dest = SET_DEST (x);
- 
-   while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
- 	 || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
-     dest = SUBREG_REG (dest);
- 	  
-   if (GET_CODE (dest) == REG)
-     {
-       int regno = REGNO (dest);
-       
-       if (regno < FIRST_PSEUDO_REGISTER)
- 	{
- 	  register int i;
- 	  int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
- 	  
- 	  for (i = regno; i < endregno; i++)
- 	    REG_N_SETS (i) += inc;
- 	}
-       else
- 	REG_N_SETS (regno) += inc;
-     }
- }
- 
- /* Updates all flow-analysis related quantities (including REG_NOTES) for
-    the insns from FIRST to LAST inclusive that were created by splitting
-    ORIG_INSN.  NOTES are the original REG_NOTES.  */
- 
- void
- update_flow_info (notes, first, last, orig_insn)
-      rtx notes;
-      rtx first, last;
-      rtx orig_insn;
- {
-   rtx insn, note;
-   rtx next;
-   rtx orig_dest, temp;
-   rtx set;
- 
-   /* Get and save the destination set by the original insn.  */
- 
-   orig_dest = single_set (orig_insn);
-   if (orig_dest)
-     orig_dest = SET_DEST (orig_dest);
- 
-   /* Move REG_NOTES from the original insn to where they now belong.  */
- 
-   for (note = notes; note; note = next)
-     {
-       next = XEXP (note, 1);
-       switch (REG_NOTE_KIND (note))
- 	{
- 	case REG_DEAD:
- 	case REG_UNUSED:
- 	  /* Move these notes from the original insn to the last new insn where
- 	     the register is now set.  */
- 
- 	  for (insn = last; ; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- 		{
- 		  /* If this note refers to a multiple word hard register, it
- 		     may have been split into several smaller hard register
- 		     references, so handle it specially.  */
- 		  temp = XEXP (note, 0);
- 		  if (REG_NOTE_KIND (note) == REG_DEAD
- 		      && GET_CODE (temp) == REG
- 		      && REGNO (temp) < FIRST_PSEUDO_REGISTER
- 		      && HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) > 1)
- 		    split_hard_reg_notes (note, first, last);
- 		  else
- 		    {
- 		      XEXP (note, 1) = REG_NOTES (insn);
- 		      REG_NOTES (insn) = note;
- 		    }
- 
- 		  /* Sometimes need to convert REG_UNUSED notes to REG_DEAD
- 		     notes.  */
- 		  /* ??? This won't handle multiple word registers correctly,
- 		     but should be good enough for now.  */
- 		  if (REG_NOTE_KIND (note) == REG_UNUSED
- 		      && GET_CODE (XEXP (note, 0)) != SCRATCH
- 		      && ! dead_or_set_p (insn, XEXP (note, 0)))
- 		    PUT_REG_NOTE_KIND (note, REG_DEAD);
- 
- 		  /* The reg only dies in one insn, the last one that uses
- 		     it.  */
- 		  break;
- 		}
- 	      /* It must die somewhere, fail it we couldn't find where it died.
- 
- 		 If this is a REG_UNUSED note, then it must be a temporary
- 		 register that was not needed by this instantiation of the
- 		 pattern, so we can safely ignore it.  */
- 	      if (insn == first)
- 		{			
- 		  if (REG_NOTE_KIND (note) != REG_UNUSED)
- 		    abort ();
- 
- 		  break;
- 		}
- 	    }
- 	  break;
- 
- 	case REG_WAS_0:
- 	  /* If the insn that set the register to 0 was deleted, this
- 	     note cannot be relied on any longer.  The destination might
- 	     even have been moved to memory.
-              This was observed for SH4 with execute/920501-6.c compilation,
- 	     -O2 -fomit-frame-pointer -finline-functions .  */
- 	  if (GET_CODE (XEXP (note, 0)) == NOTE
- 	      || INSN_DELETED_P (XEXP (note, 0)))
- 	    break;
- 	  /* This note applies to the dest of the original insn.  Find the
- 	     first new insn that now has the same dest, and move the note
- 	     there.  */
- 
- 	  if (! orig_dest)
- 	    abort ();
- 
- 	  for (insn = first; ; insn = NEXT_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && (temp = single_set (insn))
- 		  && rtx_equal_p (SET_DEST (temp), orig_dest))
- 		{
- 		  XEXP (note, 1) = REG_NOTES (insn);
- 		  REG_NOTES (insn) = note;
- 		  /* The reg is only zero before one insn, the first that
- 		     uses it.  */
- 		  break;
- 		}
- 	      /* If this note refers to a multiple word hard
- 		 register, it may have been split into several smaller
- 		 hard register references.  We could split the notes,
- 		 but simply dropping them is good enough.  */
- 	      if (GET_CODE (orig_dest) == REG
- 		  && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
- 		  && HARD_REGNO_NREGS (REGNO (orig_dest),
- 				       GET_MODE (orig_dest)) > 1)
- 		    break;
- 	      /* It must be set somewhere, fail if we couldn't find where it
- 		 was set.  */
- 	      if (insn == last)
- 		abort ();
- 	    }
- 	  break;
- 
- 	case REG_EQUAL:
- 	case REG_EQUIV:
- 	  /* A REG_EQUIV or REG_EQUAL note on an insn with more than one
- 	     set is meaningless.  Just drop the note.  */
- 	  if (! orig_dest)
- 	    break;
- 
- 	case REG_NO_CONFLICT:
- 	  /* These notes apply to the dest of the original insn.  Find the last
- 	     new insn that now has the same dest, and move the note there.  */
- 
- 	  if (! orig_dest)
- 	    abort ();
- 
- 	  for (insn = last; ; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && (temp = single_set (insn))
- 		  && rtx_equal_p (SET_DEST (temp), orig_dest))
- 		{
- 		  XEXP (note, 1) = REG_NOTES (insn);
- 		  REG_NOTES (insn) = note;
- 		  /* Only put this note on one of the new insns.  */
- 		  break;
- 		}
- 
- 	      /* The original dest must still be set someplace.  Abort if we
- 		 couldn't find it.  */
- 	      if (insn == first)
- 		{
- 		  /* However, if this note refers to a multiple word hard
- 		     register, it may have been split into several smaller
- 		     hard register references.  We could split the notes,
- 		     but simply dropping them is good enough.  */
- 		  if (GET_CODE (orig_dest) == REG
- 		      && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
- 		      && HARD_REGNO_NREGS (REGNO (orig_dest),
- 					   GET_MODE (orig_dest)) > 1)
- 		    break;
- 		  /* Likewise for multi-word memory references.  */
- 		  if (GET_CODE (orig_dest) == MEM
- 		      && SIZE_FOR_MODE (orig_dest) > MOVE_MAX)
- 		    break;
- 		  abort ();
- 		}
- 	    }
- 	  break;
- 
- 	case REG_LIBCALL:
- 	  /* Move a REG_LIBCALL note to the first insn created, and update
- 	     the corresponding REG_RETVAL note.  */
- 	  XEXP (note, 1) = REG_NOTES (first);
- 	  REG_NOTES (first) = note;
- 
- 	  insn = XEXP (note, 0);
- 	  note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
- 	  if (note)
- 	    XEXP (note, 0) = first;
- 	  break;
- 
- 	case REG_EXEC_COUNT:
- 	  /* Move a REG_EXEC_COUNT note to the first insn created.  */
- 	  XEXP (note, 1) = REG_NOTES (first);
- 	  REG_NOTES (first) = note;
- 	  break;
- 
- 	case REG_RETVAL:
- 	  /* Move a REG_RETVAL note to the last insn created, and update
- 	     the corresponding REG_LIBCALL note.  */
- 	  XEXP (note, 1) = REG_NOTES (last);
- 	  REG_NOTES (last) = note;
- 
- 	  insn = XEXP (note, 0);
- 	  note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
- 	  if (note)
- 	    XEXP (note, 0) = last;
- 	  break;
- 
- 	case REG_NONNEG:
- 	case REG_BR_PROB:
- 	  /* This should be moved to whichever instruction is a JUMP_INSN.  */
- 
- 	  for (insn = last; ; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_CODE (insn) == JUMP_INSN)
- 		{
- 		  XEXP (note, 1) = REG_NOTES (insn);
- 		  REG_NOTES (insn) = note;
- 		  /* Only put this note on one of the new insns.  */
- 		  break;
- 		}
- 	      /* Fail if we couldn't find a JUMP_INSN.  */
- 	      if (insn == first)
- 		abort ();
- 	    }
- 	  break;
- 
- 	case REG_INC:
- 	  /* reload sometimes leaves obsolete REG_INC notes around.  */
- 	  if (reload_completed)
- 	    break;
- 	  /* This should be moved to whichever instruction now has the
- 	     increment operation.  */
- 	  abort ();
- 
- 	case REG_LABEL:
- 	  /* Should be moved to the new insn(s) which use the label.  */
- 	  for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
- 	    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		&& reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- 	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
- 						    XEXP (note, 0),
- 						    REG_NOTES (insn));
- 	  break;
- 
- 	case REG_CC_SETTER:
- 	case REG_CC_USER:
- 	  /* These two notes will never appear until after reorg, so we don't
- 	     have to handle them here.  */
- 	default:
- 	  abort ();
- 	}
-     }
- 
-   /* Each new insn created, except the last, has a new set.  If the destination
-      is a register, then this reg is now live across several insns, whereas
-      previously the dest reg was born and died within the same insn.  To
-      reflect this, we now need a REG_DEAD note on the insn where this
-      dest reg dies.
- 
-      Similarly, the new insns may have clobbers that need REG_UNUSED notes.  */
- 
-   for (insn = first; insn != last; insn = NEXT_INSN (insn))
-     {
-       rtx pat;
-       int i;
- 
-       pat = PATTERN (insn);
-       if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
- 	new_insn_dead_notes (pat, insn, last, orig_insn);
-       else if (GET_CODE (pat) == PARALLEL)
- 	{
- 	  for (i = 0; i < XVECLEN (pat, 0); i++)
- 	    if (GET_CODE (XVECEXP (pat, 0, i)) == SET
- 		|| GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER)
- 	      new_insn_dead_notes (XVECEXP (pat, 0, i), insn, last, orig_insn);
- 	}
-     }
- 
-   /* If any insn, except the last, uses the register set by the last insn,
-      then we need a new REG_DEAD note on that insn.  In this case, there
-      would not have been a REG_DEAD note for this register in the original
-      insn because it was used and set within one insn.  */
- 
-   set = single_set (last);
-   if (set)
-     {
-       rtx dest = SET_DEST (set);
- 
-       while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
- 	     || GET_CODE (dest) == STRICT_LOW_PART
- 	     || GET_CODE (dest) == SIGN_EXTRACT)
- 	dest = XEXP (dest, 0);
- 
-       if (GET_CODE (dest) == REG
- 	  /* Global registers are always live, so the code below does not
- 	     apply to them.  */
- 	  && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
- 	      || ! global_regs[REGNO (dest)]))
- 	{
- 	  rtx stop_insn = PREV_INSN (first);
- 
- 	  /* If the last insn uses the register that it is setting, then
- 	     we don't want to put a REG_DEAD note there.  Search backwards
- 	     to find the first insn that sets but does not use DEST.  */
- 
- 	  insn = last;
- 	  if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
- 	    {
- 	      for (insn = PREV_INSN (insn); insn != first;
- 		   insn = PREV_INSN (insn))
- 		{
- 		  if ((set = single_set (insn))
- 		      && reg_mentioned_p (dest, SET_DEST (set))
- 		      && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
- 		    break;
- 		}
- 	    }
- 
- 	  /* Now find the first insn that uses but does not set DEST.  */
- 
- 	  for (insn = PREV_INSN (insn); insn != stop_insn;
- 	       insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		  && reg_mentioned_p (dest, PATTERN (insn))
- 		  && (set = single_set (insn)))
- 		{
- 		  rtx insn_dest = SET_DEST (set);
- 
- 		  while (GET_CODE (insn_dest) == ZERO_EXTRACT
- 			 || GET_CODE (insn_dest) == SUBREG
- 			 || GET_CODE (insn_dest) == STRICT_LOW_PART
- 			 || GET_CODE (insn_dest) == SIGN_EXTRACT)
- 		    insn_dest = XEXP (insn_dest, 0);
- 
- 		  if (insn_dest != dest)
- 		    {
- 		      note = rtx_alloc (EXPR_LIST);
- 		      PUT_REG_NOTE_KIND (note, REG_DEAD);
- 		      XEXP (note, 0) = dest;
- 		      XEXP (note, 1) = REG_NOTES (insn);
- 		      REG_NOTES (insn) = note;
- 		      /* The reg only dies in one insn, the last one
- 			 that uses it.  */
- 		      break;
- 		    }
- 		}
- 	    }
- 	}
-     }
- 
-   /* If the original dest is modifying a multiple register target, and the
-      original instruction was split such that the original dest is now set
-      by two or more SUBREG sets, then the split insns no longer kill the
-      destination of the original insn.
- 
-      In this case, if there exists an instruction in the same basic block,
-      before the split insn, which uses the original dest, and this use is
-      killed by the original insn, then we must remove the REG_DEAD note on
-      this insn, because it is now superfluous.
- 
-      This does not apply when a hard register gets split, because the code
-      knows how to handle overlapping hard registers properly.  */
-   if (orig_dest && GET_CODE (orig_dest) == REG)
-     {
-       int found_orig_dest = 0;
-       int found_split_dest = 0;
- 
-       for (insn = first; ; insn = NEXT_INSN (insn))
- 	{
- 	  rtx pat = PATTERN (insn);
- 	  int i = GET_CODE (pat) == PARALLEL ? XVECLEN (pat, 0) : 0;
- 	  set = pat;
- 	  for (;;)
- 	    {
- 	      if (GET_CODE (set) == SET)
- 		{
- 		  if (GET_CODE (SET_DEST (set)) == REG
- 		      && REGNO (SET_DEST (set)) == REGNO (orig_dest))
- 		    {
- 		      found_orig_dest = 1;
- 		      break;
- 		    }
- 		  else if (GET_CODE (SET_DEST (set)) == SUBREG
- 			   && SUBREG_REG (SET_DEST (set)) == orig_dest)
- 		    {
- 		      found_split_dest = 1;
- 		      break;
- 		    }
- 		}
- 	      if (--i < 0)
- 		break;
- 	      set = XVECEXP (pat, 0, i);
- 	    }
- 
- 	  if (insn == last)
- 	    break;
- 	}
- 
-       if (found_split_dest)
- 	{
- 	  /* Search backwards from FIRST, looking for the first insn that uses
- 	     the original dest.  Stop if we pass a CODE_LABEL or a JUMP_INSN.
- 	     If we find an insn, and it has a REG_DEAD note, then delete the
- 	     note.  */
- 
- 	  for (insn = first; insn; insn = PREV_INSN (insn))
- 	    {
- 	      if (GET_CODE (insn) == CODE_LABEL
- 		  || GET_CODE (insn) == JUMP_INSN)
- 		break;
- 	      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- 		       && reg_mentioned_p (orig_dest, insn))
- 		{
- 		  note = find_regno_note (insn, REG_DEAD, REGNO (orig_dest));
- 		  if (note)
- 		    remove_note (insn, note);
- 		}
- 	    }
- 	}
-       else if (! found_orig_dest)
- 	{
- 	  int i, regno;
- 
- 	  /* Should never reach here for a pseudo reg.  */
- 	  if (REGNO (orig_dest) >= FIRST_PSEUDO_REGISTER)
- 	    abort ();
- 
- 	  /* This can happen for a hard register, if the splitter
- 	     does not bother to emit instructions which would be no-ops.
- 	     We try to verify that this is the case by checking to see if
- 	     the original instruction uses all of the registers that it
- 	     set.  This case is OK, because deleting a no-op can not affect
- 	     REG_DEAD notes on other insns.  If this is not the case, then
- 	     abort.  */
- 	  
- 	  regno = REGNO (orig_dest);
- 	  for (i = HARD_REGNO_NREGS (regno, GET_MODE (orig_dest)) - 1;
- 	       i >= 0; i--)
- 	    if (! refers_to_regno_p (regno + i, regno + i + 1, orig_insn,
- 				     NULL_PTR))
- 	      break;
- 	  if (i >= 0)
- 	    abort ();
- 	}
-     }
- 
-   /* Update reg_n_sets.  This is necessary to prevent local alloc from
-      converting REG_EQUAL notes to REG_EQUIV when splitting has modified
-      a reg from set once to set multiple times.  */
- 
-   {
-     rtx x = PATTERN (orig_insn);
-     RTX_CODE code = GET_CODE (x);
- 
-     if (code == SET || code == CLOBBER)
-       update_n_sets (x, -1);
-     else if (code == PARALLEL)
-       {
- 	int i;
- 	for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- 	  {
- 	    code = GET_CODE (XVECEXP (x, 0, i));
- 	    if (code == SET || code == CLOBBER)
- 	      update_n_sets (XVECEXP (x, 0, i), -1);
- 	  }
-       }
- 
-     for (insn = first; ; insn = NEXT_INSN (insn))
-       {
- 	x = PATTERN (insn);
- 	code = GET_CODE (x);
- 
- 	if (code == SET || code == CLOBBER)
- 	  update_n_sets (x, 1);
- 	else if (code == PARALLEL)
- 	  {
- 	    int i;
- 	    for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- 	      {
- 		code = GET_CODE (XVECEXP (x, 0, i));
- 		if (code == SET || code == CLOBBER)
- 		  update_n_sets (XVECEXP (x, 0, i), 1);
- 	      }
- 	  }
- 
- 	if (insn == last)
- 	  break;
-       }
-   }
  }
  
  /* The one entry point in this file.  DUMP_FILE is the dump file for
--- 3540,3545 ----


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