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]

Duplicate code (update_flow_info et al.) in schedulers


Both schedulers contain code that is called from recog.c to update register
life information after splitting instructions.  This patch moves these four
functions to flow.c, where they fit somewhat better and aren't duplicated
anymore.
There are minimal differences in the two versions, none of which seem to
be very important.  The haifa version uses alloc_EXPR_LIST calls, while
the sched.c version uses rtx_alloc.  In haifa, there is one place where
there's an additional check that an insn has rtx class 'i' before attempting
to get its pattern.  
Finally, the following change is only in the haifa version, not in the sched
version:

revision 1.57
date: 1998/06/09 12:10:02;  author: rth;  state: Exp;  lines: +1 -1
        * haifa-sched.c (update_flow_info): Use UNITS_PER_WORD, not MOVE_MAX,
        as the threshold to permit splitting memory operations.

This appears to be a bug fix, so I've included it in the common code in
flow.c.

Other than that, the differences appear to be in whitespace only.

There are other occurrences of common code between sched.c/haifa-sched.c
where patches seem to have been applied only to the haifa scheduler.  Is
there a plan to eventually get rid of the old one, or are these oversights
that should be fixed?  (For example, the sched_analyze functions in haifa
keep track of a reg_last_clobbers array that isn't present in sched.c).

Bernd

	* sched.c (update_flow_info, split_hard_reg_notes, update_n_sets,
	new_insn_dead_notes, SIZE_FOR_MODE): Delete.
	* haifa-sched.c (update_flow_info, split_hard_reg_notes,
	update_n_sets, new_insn_dead_notes, SIZE_FOR_MODE): Delete.
	* flow.c (update_flow_info, split_hard_reg_notes,
	update_n_sets, new_insn_dead_notes): New functions, moved here from
	haifa-sched.c with small changes: use gen_rtx_EXPR_LIST instead of
	alloc_EXPR_LIST, expand sole use of SIZE_FOR_MODE macro.

Index: flow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flow.c,v
retrieving revision 1.124
diff -u -p -r1.124 flow.c
--- flow.c	1999/05/31 08:43:01	1.124
+++ flow.c	1999/06/04 23:12:23
@@ -323,19 +323,22 @@ static void mark_used_regs		PROTO((regse
 void dump_flow_info			PROTO((FILE *));
 static void dump_edge_info		PROTO((FILE *, edge, int));
 
-static int_list_ptr alloc_int_list_node PROTO ((int_list_block **));
-static int_list_ptr add_int_list_node   PROTO ((int_list_block **,
-						int_list **, int));
-
-static void add_pred_succ		PROTO ((int, int, int_list_ptr *,
-						int_list_ptr *, int *, int *));
-
-static void count_reg_sets_1		PROTO ((rtx));
-static void count_reg_sets		PROTO ((rtx));
-static void count_reg_references	PROTO ((rtx));
-static void notice_stack_pointer_modification PROTO ((rtx, rtx));
-static void invalidate_mems_from_autoinc	PROTO ((rtx));
-void verify_flow_info			PROTO ((void));
+static int_list_ptr alloc_int_list_node PROTO((int_list_block **));
+static int_list_ptr add_int_list_node   PROTO((int_list_block **,
+					       int_list **, int));
+
+static void add_pred_succ		PROTO((int, int, int_list_ptr *,
+					       int_list_ptr *, int *, int *));
+
+static void count_reg_sets_1		PROTO((rtx));
+static void count_reg_sets		PROTO((rtx));
+static void count_reg_references	PROTO((rtx));
+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 void notice_stack_pointer_modification	PROTO((rtx, rtx));
+static void invalidate_mems_from_autoinc	PROTO((rtx));
+void verify_flow_info			PROTO((void));
 
 /* Find basic blocks of the current function.
    F is the first insn of the function and NREGS the number of register
@@ -4994,7 +4997,684 @@ recompute_reg_usage (f, loop_step)
 	}
     }
 }
+
+/* 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 = gen_rtx_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 = gen_rtx_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 = gen_rtx_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
+		      && GET_MODE_SIZE (GET_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) = 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 = gen_rtx_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;
+      }
+  }
+}
+
 /* Record INSN's block as BB.  */
 
 void
Index: haifa-sched.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/haifa-sched.c,v
retrieving revision 1.87
diff -u -p -r1.87 haifa-sched.c
--- haifa-sched.c	1999/05/31 08:43:04	1.87
+++ haifa-sched.c	1999/06/04 23:12:42
@@ -451,9 +451,6 @@ static void attach_deaths_insn PROTO ((r
 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));
@@ -769,8 +766,6 @@ static void schedule_region PROTO ((int)
 
 #endif /* INSN_SCHEDULING */
 
-#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
-
 /* Helper functions for instruction scheduling.  */
 
 /* An INSN_LIST containing all INSN_LISTs allocated but currently unused.  */
@@ -7794,683 +7789,6 @@ schedule_region (rgn)
 
   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
Index: sched.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/sched.c,v
retrieving revision 1.37
diff -u -p -r1.37 sched.c
--- sched.c	1999/05/31 08:43:02	1.37
+++ sched.c	1999/06/04 23:12:52
@@ -343,15 +343,10 @@ static int new_sometimes_live		PROTO((st
 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 *));
 
-#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
-
 /* Helper functions for instruction scheduling.  */
 
 /* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
@@ -3535,684 +3530,6 @@ ret:
   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
    this pass.  */
 


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