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]

Local spill patches, next part: using the chains


This patch changes some of the code in reload1.c and caller-save.c to actually
use the reload_insn_chain which is built by the register allocators.
The changes in reload1.c are fairly harmless; they mostly change rtl walks
to walks over the reload_insn_chain.  The changes in caller-save.c are much
more interesting: they now use the register life information that was computed
to determine which hard regs need caller-saving.

With this applied, the remaining changes for local spilling are almost
entirely in reload1.c (caller-save.c is done).

This patch (or rather an earlier version which had two more bugs) passed a
c-torture run on i586-linux and on sparc-sun-solaris2.6.

Bernd

	* reload.h (compute_use_by_pseudos): Declare.

	* reload1.c (spilled_pseudos, insns_need_reload): New variables.
	(something_needs_reloads): Delete variable.
	(finish_spills): New function.
	(compute_use_by_pseudos): New function.

	(delete_caller_save_insns): Lose argument FIRST.  All callers changed.
	Use the reload_insn_chain instead of walking the rtl directly.

	(reload): Allocate and free spilled_pseudos.
	Ensure that all calls of spill_hard_reg are followed by a call to
	finish_spills.
	Use the insns_need_reload list instead of something_needs_reloads
	to find out if reload_as_needed must be called.
	Clear unused_insn_chains at the end.

	(calculate_needs_all_insns): Lose FIRST parameter.  All callers
	changed.
	Delete code to keep track of current basic block.
	Walk reload_insn_chain instead of the rtl structure.  Build the
	insns_need_reload chain.
	Remember which insns need reloading/elimination by setting the
	appropriate fields in struct insn_chain, not by putting modes on the
	insn.

	(calculate_needs): Lose THIS_BLOCK arg.  Accept arg CHAIN instead of
	arg INSN.  All callers changed.
	Delete declaration of struct needs.
	Don't set something_needs_reloads.
	Record insn needs in the CHAIN argument.

	(spill_hard_reg): Record the affected pseudos in spilled_pseudos.

	(reload_as_needed): Lose FIRST arg.  All callers changed.
	Walk the reload_insn_chain instead of the rtx structure.
	Delete code to keep track of current basic block.
	Rename one of the NEXT variables to OLD_NEXT.

	(allocate_reload_reg): Accept arg CHAIN instead of arg INSN.  All
	callers changed.
	(choose_reload_regs): Likewise.

	(emit_reload_insns): Replace INSN and BB args with arg CHAIN.  All
	callers changed.
	
	* caller-save.c (MOVE_MAX_WORDS): New macro.  Use it throughout
	instead of (MOVE_MAX / UNITS_PER_WORD) computation.
	(hard_regs_live, hard_regs_need_restore): Delete variables.
	(n_regs_saved): Now static.
	(referenced_regs, this_insn_sets): New variables.

	(setup_save_areas): Restructure the code a bit.

	(restore_referenced_regs): Delete function.
	(mark_referenced_regs): New function, similar to the old
	restore_referenced_regs, but mark registers in referenced_regs.

	(clear_reg_live): Delete function.
	(mark_set_regs): Renamed from set_reg_live.  All callers changed.
	Only mark registers in this_insn_sets.

	(save_call_clobbered_regs): Rework this function to walk the
	reload_insn_chain instead of using the list of instructions directly.
	Delete code to keep track of register lives, compute live regs on the
	fly from information in the chain.
	Instead of calling restore_referenced_regs, use mark_referenced_regs,
	then walk the set it computes and call insert_restore as appropriate.

	(insert_restore): Lose INSN and BLOCK args.  Add CHAIN arg.  All
	callers changed.
	Restructure the code a bit.  Test hard_regs_saved instead of
	hard_regs_need_restore.
	(insert_save): Lose INSN and BLOCK args.  Add CHAIN and TO_SAVE
	args.  All callers changed.
	Restructure the code a bit.  Use TO_SAVE to determine which regs to
	save instead of more complicated test.
	(insert_one_arg): Lose INSN and BLOCK args.  Add CHAIN arg.  All
	callers changed.
	Create a new insn_chain structure for the new insn and place it
	into the chain.

	* rtl.texi: Update documentation to reflect that reload no longer
	puts modes on the insns.

Index: caller-save.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/caller-save.c,v
retrieving revision 1.12
diff -u -p -r1.12 caller-save.c
--- caller-save.c	1998/10/07 00:13:47	1.12
+++ caller-save.c	1998/10/07 12:13:14
@@ -39,6 +39,8 @@ Boston, MA 02111-1307, USA.  */
 #define MIN_UNITS_PER_WORD UNITS_PER_WORD
 #endif
 
+#define MOVE_MAX_WORDS (MOVE_MAX / UNITS_PER_WORD)
+
 /* Modes for each hard register that we can save.  The smallest mode is wide
    enough to save the entire contents of the register.  When saving the
    register because it is live we first try to save in multi-register modes.
@@ -64,29 +66,31 @@ static enum insn_code 
 static enum insn_code 
   reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
 
-/* Set of hard regs currently live (during scan of all insns).  */
-
-static HARD_REG_SET hard_regs_live;
-
 /* Set of hard regs currently residing in save area (during insn scan).  */
 
 static HARD_REG_SET hard_regs_saved;
 
-/* Set of hard regs which need to be restored before referenced.  */
-
-static HARD_REG_SET hard_regs_need_restore;
-
 /* Number of registers currently in hard_regs_saved.  */
 
-int n_regs_saved;
+static int n_regs_saved;
 
-static void set_reg_live		PROTO((rtx, rtx));
-static void clear_reg_live		PROTO((rtx));
-static void restore_referenced_regs	PROTO((rtx, rtx, int));
-static int insert_restore		PROTO((rtx, int, int, int, int));
-static int insert_save			PROTO((rtx, int, int, int));
-static void insert_one_insn		PROTO((rtx, int, enum rtx_code,
-					       rtx, int));
+/* Computed by mark_referenced_regs, all regs referenced in a given
+   insn.  */
+static HARD_REG_SET referenced_regs;
+
+/* Computed in mark_set_regs, holds all registers set by the current
+   instruction.  */
+static HARD_REG_SET this_insn_sets;
+
+
+static void mark_set_regs		PROTO((rtx, rtx));
+static void mark_referenced_regs	PROTO((rtx));
+static int insert_save			PROTO((struct insn_chain *, int, int,
+					       HARD_REG_SET *));
+static int insert_restore		PROTO((struct insn_chain *, int, int,
+					       int));
+static void insert_one_insn		PROTO((struct insn_chain *, int,
+					       enum insn_code, rtx));
 
 /* Initialize for caller-save.
 
@@ -115,7 +119,7 @@ init_caller_save ()
     {
       if (call_used_regs[i] && ! call_fixed_regs[i])
 	{
-	  for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
+	  for (j = 1; j <= MOVE_MAX_WORDS; j++)
 	    {
 	      regno_save_mode[i][j] = HARD_REGNO_CALLER_SAVE_MODE (i, j);
 	      if (regno_save_mode[i][j] == VOIDmode && j == 1)
@@ -172,7 +176,7 @@ init_caller_save ()
   start_sequence ();
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
+    for (j = 1; j <= MOVE_MAX_WORDS; j++)
       if (regno_save_mode[i][j] != VOIDmode)
         {
 	  rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address);
@@ -221,7 +225,7 @@ init_save_areas ()
   int i, j;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
+    for (j = 1; j <= MOVE_MAX_WORDS; j++)
       regno_save_mem[i][j] = 0;
 }
 
@@ -275,10 +279,9 @@ setup_save_areas ()
      in a manner which allows multi-register saves/restores to be done.  */
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    for (j = MOVE_MAX / UNITS_PER_WORD; j > 0; j--)
+    for (j = MOVE_MAX_WORDS; j > 0; j--)
       {
-	int ok = 1;
-	int do_save;
+	int do_save = 1;
 
 	/* If no mode exists for this size, try another.  Also break out
 	   if we have already saved this hard register.  */
@@ -286,7 +289,6 @@ setup_save_areas ()
 	  continue;
 
 	/* See if any register in this group has been saved.  */
-	do_save = 1;
 	for (k = 0; k < j; k++)
 	  if (regno_save_mem[i + k][1])
 	    {
@@ -297,189 +299,171 @@ setup_save_areas ()
 	  continue;
 
 	for (k = 0; k < j; k++)
+	  if (! TEST_HARD_REG_BIT (hard_regs_used, i + k))
 	    {
-	      int regno = i + k;
-	      ok &= (TEST_HARD_REG_BIT (hard_regs_used, regno) != 0);
+	      do_save = 0;
+	      break;
 	    }
+	if (! do_save)
+	  continue;
 
 	/* We have found an acceptable mode to store in.  */
-	if (ok)
+	regno_save_mem[i][j]
+	  = assign_stack_local (regno_save_mode[i][j],
+				GET_MODE_SIZE (regno_save_mode[i][j]), 0);
+
+	/* Setup single word save area just in case...  */
+	for (k = 0; k < j; k++)
 	  {
+	    /* This should not depend on WORDS_BIG_ENDIAN.
+	       The order of words in regs is the same as in memory.  */
+	    rtx temp = gen_rtx_MEM (regno_save_mode[i+k][1], 
+				    XEXP (regno_save_mem[i][j], 0));
 
-	    regno_save_mem[i][j]
-	      = assign_stack_local (regno_save_mode[i][j],
-				    GET_MODE_SIZE (regno_save_mode[i][j]), 0);
-
-	    /* Setup single word save area just in case...  */
-	    for (k = 0; k < j; k++)
-	      {
-		/* This should not depend on WORDS_BIG_ENDIAN.
-		   The order of words in regs is the same as in memory.  */
-		rtx temp = gen_rtx_MEM (regno_save_mode[i+k][1], 
-					XEXP (regno_save_mem[i][j], 0));
-
-		regno_save_mem[i+k][1] 
-		  = adj_offsettable_operand (temp, k * UNITS_PER_WORD);
-	      }
+	    regno_save_mem[i+k][1] 
+	      = adj_offsettable_operand (temp, k * UNITS_PER_WORD);
 	  }
       }
-
-  return;
 }
 
 /* Find the places where hard regs are live across calls and save them.  */
-
 void
 save_call_clobbered_regs ()
 {
-  rtx insn;
-  int b;
+  struct insn_chain *chain, *next;
 
-  for (b = 0; b < n_basic_blocks; b++)
+  CLEAR_HARD_REG_SET (hard_regs_saved);
+  n_regs_saved = 0;
+
+  for (chain = reload_insn_chain; chain != 0; chain = next)
     {
-      regset regs_live = basic_block_live_at_start[b];
-      int i, j;
-      int regno;
-
-      /* Compute hard regs live at start of block -- this is the
-	 real hard regs marked live, plus live pseudo regs that
-	 have been renumbered to hard regs.  No registers have yet been
-	 saved because we restore all of them before the end of the basic
-	 block.  */
-
-      REG_SET_TO_HARD_REG_SET (hard_regs_live, regs_live);
-      CLEAR_HARD_REG_SET (hard_regs_saved);
-      CLEAR_HARD_REG_SET (hard_regs_need_restore);
-      n_regs_saved = 0;
-
-      EXECUTE_IF_SET_IN_REG_SET (regs_live, 0, i,
-				 {
-				   if ((regno = reg_renumber[i]) >= 0)
-				     for (j = regno;
-					  j < regno + HARD_REGNO_NREGS (regno,
-									PSEUDO_REGNO_MODE (i));
-					  j++)
-				       SET_HARD_REG_BIT (hard_regs_live, j);
-				 });
-
-      /* Now scan the insns in the block, keeping track of what hard
-	 regs are live as we go.  When we see a call, save the live
-	 call-clobbered hard regs.  */
+      rtx insn = chain->insn;
+      enum rtx_code code = GET_CODE (insn);
+
+      next = chain->next;
 
-      for (insn = basic_block_head[b]; ; insn = NEXT_INSN (insn))
+      if (chain->is_caller_save_insn)
+	abort ();
+
+      if (GET_RTX_CLASS (code) == 'i')
 	{
-	  RTX_CODE code = GET_CODE (insn);
+	  /* If some registers have been saved, see if INSN references
+	     any of them.  We must restore them before the insn if so.  */
 
-	  if (GET_RTX_CLASS (code) == 'i')
+	  if (n_regs_saved)
 	    {
-	      rtx link;
-
-	      /* If some registers have been saved, see if INSN references
-		 any of them.  We must restore them before the insn if so.  */
+	      int regno;
 
-	      if (n_regs_saved)
-		restore_referenced_regs (PATTERN (insn), insn, b);
+	      if (code == JUMP_INSN)
+		/* Restore all registers if this is a JUMP_INSN.  */
+		COPY_HARD_REG_SET (referenced_regs, hard_regs_saved);
+	      else
+		{
+		  CLEAR_HARD_REG_SET (referenced_regs);
+		  mark_referenced_regs (PATTERN (insn));
+		  AND_HARD_REG_SET (referenced_regs, hard_regs_saved);
+		}
 
-	      /* NB: the normal procedure is to first enliven any
-		 registers set by insn, then deaden any registers that
-		 had their last use at insn.  This is incorrect now,
-		 since multiple pseudos may have been mapped to the
-		 same hard reg, and the death notes are ambiguous.  So
-		 it must be done in the other, safe, order.  */
-
-	      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-		if (REG_NOTE_KIND (link) == REG_DEAD)
-		  clear_reg_live (XEXP (link, 0));
-
-	      /* When we reach a call, we need to save all registers that are
-		 live, call-used, not fixed, and not already saved.  We must
-		 test at this point because registers that die in a CALL_INSN
-		 are not live across the call and likewise for registers that
-		 are born in the CALL_INSN.
-		 
-		 If registers are filled with parameters for this function,
-		 and some of these are also being set by this function, then
-		 they will not appear to die (no REG_DEAD note for them),
-		 to check if in fact they do, collect the set registers in
-		 hard_regs_live first.  */
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		if (TEST_HARD_REG_BIT (referenced_regs, regno))
+		  regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS);
+	    }
 
-	      if (code == CALL_INSN)
+	  if (code == CALL_INSN)
+	    {
+	      rtx x;
+	      int regno, nregs;
+	      HARD_REG_SET hard_regs_to_save;
+
+	      /* Use the register life information in CHAIN to compute which
+		 regs are live before the call.  */
+	      REG_SET_TO_HARD_REG_SET (hard_regs_to_save, chain->live_before);
+	      compute_use_by_pseudos (&hard_regs_to_save, chain->live_before);
+
+	      /* Record all registers set in this call insn.  These don't need
+		 to be saved.  */
+	      CLEAR_HARD_REG_SET (this_insn_sets);
+	      note_stores (PATTERN (insn), mark_set_regs);
+
+	      /* Compute which hard regs must be saved before this call.  */
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, call_fixed_reg_set);
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, this_insn_sets);
+	      AND_COMPL_HARD_REG_SET (hard_regs_to_save, hard_regs_saved);
+	      AND_HARD_REG_SET (hard_regs_to_save, call_used_reg_set);
+
+	      /* Registers used for function parameters need not be saved.  */
+	      for (x = CALL_INSN_FUNCTION_USAGE (insn); x != 0;
+		   x = XEXP (x, 1))
 		{
-		  HARD_REG_SET this_call_sets;
-		  {
-		    HARD_REG_SET old_hard_regs_live;
-
-		    /* Save the hard_regs_live information.  */
-		    COPY_HARD_REG_SET (old_hard_regs_live, hard_regs_live);
-
-		    /* Now calculate hard_regs_live for this CALL_INSN
-		       only.  */
-		    CLEAR_HARD_REG_SET (hard_regs_live);
-		    note_stores (PATTERN (insn), set_reg_live);
-		    COPY_HARD_REG_SET (this_call_sets, hard_regs_live);
-
-		    /* Restore the hard_regs_live information.  */
-		    COPY_HARD_REG_SET (hard_regs_live, old_hard_regs_live);
-		  }
-
-		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-		    if (call_used_regs[regno] && ! call_fixed_regs[regno]
-		        && TEST_HARD_REG_BIT (hard_regs_live, regno)
-			/* It must not be set by this instruction.  */
-		        && ! TEST_HARD_REG_BIT (this_call_sets, regno)
-		        && ! TEST_HARD_REG_BIT (hard_regs_saved, regno))
-		      regno += insert_save (insn, 1, regno, b);
-
-		  /* Put the information for this CALL_INSN on top of what
-		     we already had.  */
-		  IOR_HARD_REG_SET (hard_regs_live, this_call_sets);
-		  COPY_HARD_REG_SET (hard_regs_need_restore, hard_regs_saved);
-
-		  /* Must recompute n_regs_saved.  */
-		  n_regs_saved = 0;
-		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-		    if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
-		      n_regs_saved++;
+		  rtx y;
+
+		  if (GET_CODE (XEXP (x, 0)) != USE)
+		    continue;
+		  y = XEXP (XEXP (x, 0), 0);
+		  if (GET_CODE (y) != REG)
+		    abort ();
+		  regno = REGNO (y);
+		  if (REGNO (y) >= FIRST_PSEUDO_REGISTER)
+		    abort ();
+		  nregs = HARD_REGNO_NREGS (regno, GET_MODE (y));
+		  while (nregs-- > 0)
+		    CLEAR_HARD_REG_BIT (hard_regs_to_save, regno + nregs);
 		}
-	      else
+
+	      /* Neither do registers for which we find a death note.  */
+	      for (x = REG_NOTES (insn); x != 0; x = XEXP (x, 1))
 		{
-		  note_stores (PATTERN (insn), set_reg_live);
-#ifdef AUTO_INC_DEC
-		  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-		    if (REG_NOTE_KIND (link) == REG_INC)
-		      set_reg_live (XEXP (link, 0), NULL_RTX);
-#endif
-		}
+		  rtx y = XEXP (x, 0);
 
-	      for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-		if (REG_NOTE_KIND (link) == REG_UNUSED)
-		  clear_reg_live (XEXP (link, 0));
+		  if (REG_NOTE_KIND (x) != REG_DEAD)
+		    continue;
+		  if (GET_CODE (y) != REG)
+		    abort ();
+		  regno = REGNO (y);
+
+		  if (regno >= FIRST_PSEUDO_REGISTER)
+		    regno = reg_renumber[regno];
+		  if (regno < 0)
+		    continue;
+		  nregs = HARD_REGNO_NREGS (regno, GET_MODE (y));
+		  while (nregs-- > 0)
+		    CLEAR_HARD_REG_BIT (hard_regs_to_save, regno + nregs);		  
+		}
+		
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+		  regno += insert_save (chain, 1, regno, &hard_regs_to_save);
+
+	      /* Must recompute n_regs_saved.  */
+	      n_regs_saved = 0;
+	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+		if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
+		  n_regs_saved++;
 	    }
-
-	  if (insn == basic_block_end[b])
-	    break;
 	}
 
-      /* At the end of the basic block, we must restore any registers that
-	 remain saved.  If the last insn in the block is a JUMP_INSN, put
-	 the restore before the insn, otherwise, put it after the insn.  */
-
-      if (n_regs_saved)
-	for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-	  if (TEST_HARD_REG_BIT (hard_regs_need_restore, regno))
-	    regno += insert_restore (insn, GET_CODE (insn) == JUMP_INSN,
-				     regno,
-				     MOVE_MAX / UNITS_PER_WORD, b);
-    }
+      if (chain->next == 0 || chain->next->block > chain->block)
+	{
+	  int regno;
+	  /* At the end of the basic block, we must restore any registers that
+	     remain saved.  If the last insn in the block is a JUMP_INSN, put
+	     the restore before the insn, otherwise, put it after the insn.  */
+
+	  if (n_regs_saved)
+	    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	      if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
+		regno += insert_restore (chain, GET_CODE (insn) == JUMP_INSN,
+					 regno, MOVE_MAX_WORDS);
+	}
+    }  
 }
 
 /* Here from note_stores when an insn stores a value in a register.
-   Set the proper bit or bits in hard_regs_live.  All pseudos that have
+   Set the proper bit or bits in this_insn_sets.  All pseudos that have
    been assigned hard regs have had their register number changed already,
    so we can ignore pseudos.  */
-
 static void
-set_reg_live (reg, setter)
+mark_set_regs (reg, setter)
      rtx reg;
      rtx setter ATTRIBUTE_UNUSED;
 {
@@ -500,104 +484,71 @@ set_reg_live (reg, setter)
   endregno = regno + HARD_REGNO_NREGS (regno, mode);
 
   for (i = regno; i < endregno; i++)
-    {
-      SET_HARD_REG_BIT (hard_regs_live, i);
-      CLEAR_HARD_REG_BIT (hard_regs_saved, i);
-      CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);
-    }
+    SET_HARD_REG_BIT (this_insn_sets, i);
 }
-
-/* Here when a REG_DEAD note records the last use of a reg.  Clear
-   the appropriate bit or bits in hard_regs_live.  Again we can ignore
-   pseudos.  */
-
-static void
-clear_reg_live (reg)
-     rtx reg;
-{
-  register int regno, endregno, i;
-
-  if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
-    return;
-
-  regno = REGNO (reg);
-  endregno= regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
-
-  for (i = regno; i < endregno; i++)
-    {
-      CLEAR_HARD_REG_BIT (hard_regs_live, i);
-      CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);
-      CLEAR_HARD_REG_BIT (hard_regs_saved, i);
-    }
-}      
-
-/* If any register currently residing in the save area is referenced in X,
-   which is part of INSN, emit code to restore the register in front of
-   INSN.  */
 
+/* Walk X and record all referenced registers in REFERENCED_REGS.  */
 static void
-restore_referenced_regs (x, insn, block)
+mark_referenced_regs (x)
      rtx x;
-     rtx insn;
-     int block;
 {
   enum rtx_code code = GET_CODE (x);
   char *fmt;
   int i, j;
 
-  if (code == CLOBBER)
-    return;
+  if (code == SET)
+    mark_referenced_regs (SET_SRC (x));
+  if (code == SET || code == CLOBBER)
+    {
+      x = SET_DEST (x);
+      code = GET_CODE (x);
+      if (code == REG || code == PC || code == CC0
+	  || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
+	return;
+    }
+  if (code == MEM || code == SUBREG)
+    {
+      x = XEXP (x, 0);
+      code = GET_CODE (x);
+    }
 
   if (code == REG)
     {
       int regno = REGNO (x);
-
-      /* If this is a pseudo, scan its memory location, since it might
-	 involve the use of another register, which might be saved.  */
-
-      if (regno >= FIRST_PSEUDO_REGISTER
-	  && reg_equiv_mem[regno] != 0)
-	restore_referenced_regs (XEXP (reg_equiv_mem[regno], 0),
-				 insn, block);
-      else if (regno >= FIRST_PSEUDO_REGISTER
-	       && reg_equiv_address[regno] != 0)
-	restore_referenced_regs (reg_equiv_address[regno],
-				 insn, block);
+      int hardregno = (regno < FIRST_PSEUDO_REGISTER ? regno
+		       : reg_renumber[regno]);
 
-      /* Otherwise if this is a hard register, restore any piece of it that
-	 is currently saved.  */
-
-      else if (regno < FIRST_PSEUDO_REGISTER)
+      if (hardregno >= 0)
 	{
-	  int numregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
-	  /* Save at most SAVEREGS at a time.  This can not be larger than
-	     MOVE_MAX, because that causes insert_restore to fail.  */
-	  int saveregs = MIN (numregs, MOVE_MAX / UNITS_PER_WORD);
-	  int endregno = regno + numregs;
-
-	  for (i = regno; i < endregno; i++)
-	    if (TEST_HARD_REG_BIT (hard_regs_need_restore, i))
-	      i += insert_restore (insn, 1, i, saveregs, block);
+	  int nregs = HARD_REGNO_NREGS (hardregno, GET_MODE (x));
+	  while (nregs-- > 0)
+	    SET_HARD_REG_BIT (referenced_regs, hardregno + nregs);
 	}
-
+      /* If this is a pseudo that did not get a hard register, scan its
+	 memory location, since it might involve the use of another
+	 register, which might be saved.  */
+      else if (reg_equiv_mem[regno] != 0)
+	mark_referenced_regs (XEXP (reg_equiv_mem[regno], 0));
+      else if (reg_equiv_address[regno] != 0)
+	mark_referenced_regs (reg_equiv_address[regno]);
       return;
     }
-	  
+
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-	restore_referenced_regs (XEXP (x, i), insn, block);
+	mark_referenced_regs (XEXP (x, i));
       else if (fmt[i] == 'E')
 	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-	  restore_referenced_regs (XVECEXP (x, i, j), insn, block);
+	  mark_referenced_regs (XVECEXP (x, i, j));
     }
 }
 
-/* Insert a sequence of insns to restore REGNO.  Place these insns in front
-   of or after INSN (determined by BEFORE_P).   MAXRESTORE is the maximum
-   number of registers which should be restored during this call.  It should
-   never be less than 1 since we only work with entire registers.
+/* Insert a sequence of insns to restore.  Place these insns in front of
+   CHAIN if BEFORE_P is nonzero, behind the insn otherwise.  MAXRESTORE is
+   the maximum number of registers which should be restored during this call.
+   It should never be less than 1 since we only work with entire registers.
 
    Note that we have verified in init_caller_save that we can do this
    with a simple SET, so use it.  Set INSN_CODE to what we save there
@@ -608,18 +559,16 @@ restore_referenced_regs (x, insn, block)
    Return the extra number of registers saved.  */
 
 static int
-insert_restore (insn, before_p, regno, maxrestore, block)
-     rtx insn;
+insert_restore (chain, before_p, regno, maxrestore)
+     struct insn_chain *chain;
      int before_p;
      int regno;
      int maxrestore;
-     int block;
 {
+  int i;
   rtx pat = NULL_RTX;
   enum insn_code code = CODE_FOR_nothing;
   int numregs = 0;
-  int i, j, k;
-  int ok;
 
   /* A common failure mode if register status is not correct in the RTL
      is for this routine to be called with a REGNO we didn't expect to
@@ -631,37 +580,38 @@ insert_restore (insn, before_p, regno, m
   if (regno_save_mem[regno][1] == 0)
     abort ();
 
-  /* Get the pattern to emit and update our status.  */
+  /* Get the pattern to emit and update our status.
 
-  /* See if we can restore `maxrestore' registers at once.  Work
+     See if we can restore `maxrestore' registers at once.  Work
      backwards to the single register case.  */
   for (i = maxrestore; i > 0; i--)
     {
-      ok = 1;
-      if (regno_save_mem[regno][i])
-	for (j = 0; j < i; j++)
-	  {
-	    if (! TEST_HARD_REG_BIT (hard_regs_need_restore, regno + j))
-	      ok = 0;
-	  }
-      else
+      int j, k;
+      int ok = 1;
+
+      if (regno_save_mem[regno][i] == 0)
 	continue;
 
+      for (j = 0; j < i; j++)
+	if (! TEST_HARD_REG_BIT (hard_regs_saved, regno + j))
+	  {
+	    ok = 0;
+	    break;
+	  }
       /* Must do this one restore at a time */
       if (! ok)
 	continue;
-	    
+
       pat = gen_rtx_SET (VOIDmode,
 			 gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]), 
 				      regno), 
 			 regno_save_mem[regno][i]);
       code = reg_restore_code[regno][i];
 
-
       /* Clear status for all registers we restored.  */
       for (k = 0; k < i; k++)
 	{
-	  CLEAR_HARD_REG_BIT (hard_regs_need_restore, regno + k);
+	  CLEAR_HARD_REG_BIT (hard_regs_saved, regno + k);
 	  n_regs_saved--;
 	}
 
@@ -669,25 +619,24 @@ insert_restore (insn, before_p, regno, m
       break;
     }
 
-  insert_one_insn (insn, before_p, code, pat, block);
+  insert_one_insn (chain, before_p, code, pat);
 
   /* Tell our callers how many extra registers we saved/restored */
   return numregs - 1;
 }
 
-/* Like insert_restore, but emit code to save REGNO.  */
+/* Like insert_restore above, but save registers instead.  */
 static int
-insert_save (insn, before_p, regno, block)
-     rtx insn;
+insert_save (chain, before_p, regno, to_save)
+     struct insn_chain *chain;
      int before_p;
      int regno;
-     int block;
+     HARD_REG_SET *to_save;
 {
+  int i;
   rtx pat = NULL_RTX;
   enum insn_code code = CODE_FOR_nothing;
   int numregs = 0;
-  int i, j, k;
-  int ok;
 
   /* A common failure mode if register status is not correct in the RTL
      is for this routine to be called with a REGNO we didn't expect to
@@ -699,24 +648,23 @@ insert_save (insn, before_p, regno, bloc
   if (regno_save_mem[regno][1] == 0)
     abort ();
 
-  /* Get the pattern to emit and update our status.  */
+  /* Get the pattern to emit and update our status.
 
-  /* See if we can save several registers with a single instruction.  
+     See if we can save several registers with a single instruction.  
      Work backwards to the single register case.  */
-  for (i = MOVE_MAX / UNITS_PER_WORD; i > 0; i--)
+  for (i = MOVE_MAX_WORDS; i > 0; i--)
     {
-      ok = 1;
-      if (regno_save_mem[regno][i] != 0)
-	for (j = 0; j < i; j++)
-	  {
-	    if (! call_used_regs[regno + j] || call_fixed_regs[regno + j]
-		|| ! TEST_HARD_REG_BIT (hard_regs_live, regno + j)
-		|| TEST_HARD_REG_BIT (hard_regs_saved, regno + j))
-	      ok = 0;
-	  }
-      else 
+      int j, k;
+      int ok = 1;
+      if (regno_save_mem[regno][i] == 0)
 	continue;
 
+      for (j = 0; j < i; j++)
+	if (! TEST_HARD_REG_BIT (*to_save, regno + j))
+	  {
+	    ok = 0;
+	    break;
+	  }
       /* Must do this one save at a time */
       if (! ok)
 	continue;
@@ -730,7 +678,6 @@ insert_save (insn, before_p, regno, bloc
       for (k = 0; k < i; k++)
 	{
 	  SET_HARD_REG_BIT (hard_regs_saved, regno + k);
-	  SET_HARD_REG_BIT (hard_regs_need_restore, regno + k);
 	  n_regs_saved++;
 	}
 
@@ -738,23 +685,23 @@ insert_save (insn, before_p, regno, bloc
       break;
     }
 
-  insert_one_insn (insn, before_p, code, pat, block);
+  insert_one_insn (chain, before_p, code, pat);
 
   /* Tell our callers how many extra registers we saved/restored */
   return numregs - 1;
 }
 
-/* Emit one insn, set the code, and update basic block boundaries.  */
+/* Emit a new caller-save insn and set the code.  */
 static void
-insert_one_insn (insn, before_p, code, pat, block)
-     rtx insn;
+insert_one_insn (chain, before_p, code, pat)
+     struct insn_chain *chain;
      int before_p;
-     enum rtx_code code;
+     enum insn_code code;
      rtx pat;
-     int block;
 {
-  rtx insert_point = insn;
-  rtx new;
+  rtx insn = chain->insn;
+  struct insn_chain *new;
+  
 #ifdef HAVE_cc0
   /* If INSN references CC0, put our insns in front of the insn that sets
      CC0.  This is always safe, since the only way we could be passed an
@@ -765,21 +712,37 @@ insert_one_insn (insn, before_p, code, p
   if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
       && before_p
       && reg_referenced_p (cc0_rtx, PATTERN (insn)))
-    insert_point = prev_nonnote_insn (insn);
+    chain = chain->prev, insn = chain->insn;
 #endif
 
+  new = new_insn_chain ();
   if (before_p)
     {
-      new = emit_insn_before (pat, insert_point);
-      if (insert_point == basic_block_head[block])
-	basic_block_head[block] = new;
+      new->prev = chain->prev;
+      if (new->prev != 0)
+	new->prev->next = new;
+      else
+	reload_insn_chain = new;
+
+      chain->prev = new;
+      new->next = chain;
+      new->insn = emit_insn_before (pat, insn);
+      if (chain->insn == basic_block_head[chain->block])
+	basic_block_head[chain->block] = new->insn;
     }
   else
     {
-      new = emit_insn_after (pat, insert_point);
-      if (insert_point == basic_block_end[block])
-	basic_block_end[block] = new;
+      new->next = chain->next;
+      if (new->next != 0)
+	new->next->prev = new;
+      chain->next = new;
+      new->prev = chain;
+      new->insn = emit_insn_after (pat, insn);
+      if (chain->insn == basic_block_end[chain->block])
+	basic_block_end[chain->block] = new->insn;
     }
+  new->block = chain->block;
+  new->is_caller_save_insn = 1;
 
-  INSN_CODE (new) = code;
+  INSN_CODE (new->insn) = code;
 }
Index: reload.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/reload.h,v
retrieving revision 1.11
diff -u -p -r1.11 reload.h
--- reload.h	1998/10/07 00:13:48	1.11
+++ reload.h	1998/10/07 12:13:15
@@ -215,6 +215,7 @@ extern struct insn_chain *reload_insn_ch
 /* Allocate a new insn_chain structure.  */
 extern struct insn_chain *new_insn_chain	PROTO((void));
 
+extern void compute_use_by_pseudos		PROTO((HARD_REG_SET *, regset));
 #endif
 
 /* Functions from reload.c:  */
Index: reload1.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/reload1.c,v
retrieving revision 1.73
diff -u -p -r1.73 reload1.c
--- reload1.c	1998/10/07 00:13:49	1.73
+++ reload1.c	1998/10/07 12:13:22
@@ -177,12 +177,10 @@ static short spill_regs[FIRST_PSEUDO_REG
    registers.  This information is used in reorg.c, to help figure out
    what registers are live at any point.  It is assumed that all spill_regs
    are dead at every CODE_LABEL.  */
-
 HARD_REG_SET used_spill_regs;
 
 /* Index of last register assigned as a spill register.  We allocate in
    a round-robin fashion.  */
-
 static int last_spill_reg;
 
 /* Describes order of preference for putting regs into spill_regs.
@@ -213,32 +211,29 @@ static HARD_REG_SET counted_for_nongroup
    value indicates the level of indirect addressing supported, e.g., two
    means that (MEM (MEM (REG n))) is also valid if (REG n) does not get
    a hard register.  */
-
 static char spill_indirect_levels;
 
 /* Nonzero if indirect addressing is supported when the innermost MEM is
    of the form (MEM (SYMBOL_REF sym)).  It is assumed that the level to
    which these are valid is the same as spill_indirect_levels, above.   */
-
 char indirect_symref_ok;
 
 /* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid.  */
-
 char double_reg_address_ok;
 
 /* Record the stack slot for each spilled hard register.  */
-
 static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER];
 
 /* Width allocated so far for that stack slot.  */
-
 static int spill_stack_slot_width[FIRST_PSEUDO_REGISTER];
 
+/* Record which pseudos needed to be spilled.  */
+static regset spilled_pseudos;
+
 /* Indexed by register class and basic block number, nonzero if there is
    any need for a spill register of that class in that basic block.
    The pointer is 0 if we did stupid allocation and don't know
    the structure of basic blocks.  */
-
 char *basic_block_needs[N_REG_CLASSES];
 
 /* First uid used by insns created by reload in this function.
@@ -247,7 +242,6 @@ int reload_first_uid;
 
 /* Flag set by local-alloc or global-alloc if anything is live in
    a call-clobbered reg across calls.  */
-
 int caller_save_needed;
 
 /* The register class to use for a base register when reloading an
@@ -297,6 +291,9 @@ extern rtx forced_labels;
 /* List of insn_chain instructions, one for every insn that reload needs to
    examine.  */
 struct insn_chain *reload_insn_chain;
+
+/* List of insns needing reloads.  */
+static struct insn_chain *insns_need_reload;
 
 /* This structure is used to record information about register eliminations.
    Each array entry describes one possible way of eliminating a register
@@ -360,8 +357,8 @@ static int num_labels;
 struct hard_reg_n_uses { int regno; int uses; };
 
 static void dump_needs			PROTO((FILE *));
-static int calculate_needs_all_insns	PROTO((rtx, int));
-static int calculate_needs		PROTO((int, rtx, rtx, int));
+static int calculate_needs_all_insns	PROTO((int));
+static int calculate_needs		PROTO((struct insn_chain *, rtx, int));
 static int find_reload_regs		PROTO((int, FILE *));
 static int find_tworeg_group		PROTO((int, int, FILE *));
 static int find_group			PROTO((int, int, FILE *));
@@ -371,7 +368,7 @@ static void count_possible_groups	PROTO(
 static int modes_equiv_for_class_p	PROTO((enum machine_mode,
 					       enum machine_mode,
 					       enum reg_class));
-static void delete_caller_save_insns	PROTO((rtx));
+static void delete_caller_save_insns	PROTO((void));
 static void spill_failure		PROTO((rtx));
 static int new_spill_reg		PROTO((int, int, int *, int *, int,
 					       FILE *));
@@ -384,11 +381,12 @@ static void set_initial_elim_offsets	PRO
 static void init_elim_table		PROTO((void));
 static void update_eliminables		PROTO((HARD_REG_SET *));
 static int spill_hard_reg		PROTO((int, int, FILE *, int));
+static void finish_spills		PROTO((int, FILE *));
 static void scan_paradoxical_subregs	PROTO((rtx));
 static int hard_reg_use_compare		PROTO((const GENERIC_PTR, const GENERIC_PTR));
 static void order_regs_for_reload	PROTO((void));
 static int compare_spill_regs		PROTO((const GENERIC_PTR, const GENERIC_PTR));
-static void reload_as_needed		PROTO((rtx, int));
+static void reload_as_needed		PROTO((int));
 static void forget_old_reloads_1	PROTO((rtx, rtx));
 static int reload_reg_class_lower	PROTO((const GENERIC_PTR, const GENERIC_PTR));
 static void mark_reload_reg_in_use	PROTO((int, int, enum reload_type,
@@ -399,10 +397,10 @@ static int reload_reg_free_p		PROTO((int
 static int reload_reg_free_before_p	PROTO((int, int, enum reload_type, int));
 static int reload_reg_free_for_value_p	PROTO((int, int, enum reload_type, rtx, rtx, int));
 static int reload_reg_reaches_end_p	PROTO((int, int, enum reload_type));
-static int allocate_reload_reg		PROTO((int, rtx, int, int));
-static void choose_reload_regs		PROTO((rtx, rtx));
+static int allocate_reload_reg		PROTO((struct insn_chain *, int, int, int));
+static void choose_reload_regs		PROTO((struct insn_chain *, rtx));
 static void merge_assigned_reloads	PROTO((rtx));
-static void emit_reload_insns		PROTO((rtx, int));
+static void emit_reload_insns		PROTO((struct insn_chain *));
 static void delete_output_reload	PROTO((rtx, int, rtx));
 static void inc_for_reload		PROTO((rtx, rtx, int));
 static int constraint_accepts_reg_p	PROTO((char *, rtx));
@@ -560,10 +558,29 @@ new_insn_chain ()
   return c;
 }
 
+/* Small utility function to set all regs in hard reg set TO which are
+   allocated to pseudos in regset FROM.  */
+void
+compute_use_by_pseudos (to, from)
+     HARD_REG_SET *to;
+     regset from;
+{
+  int regno;
+  EXECUTE_IF_SET_IN_REG_SET
+    (from, FIRST_PSEUDO_REGISTER, regno,
+     {
+       int r = reg_renumber[regno];
+       int nregs;
+       if (r < 0)
+	 abort ();
+       nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (regno));
+       while (nregs-- > 0)
+	 SET_HARD_REG_BIT (*to, r + nregs);
+     });
+}
+
 /* Global variables used by reload and its subroutines.  */
 
-/* Set during calculate_needs if an insn needs reloading.  */
-static int something_needs_reloads;
 /* Set during calculate_needs if an insn needs register elimination.  */
 static int something_needs_elimination;
 
@@ -866,6 +883,8 @@ reload (first, global, dumpfile)
   if (! SMALL_REGISTER_CLASSES)
     COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
 
+  spilled_pseudos = ALLOCA_REG_SET ();
+
   /* Spill any hard regs that we know we can't eliminate.  */
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     if (! ep->can_eliminate)
@@ -876,6 +895,8 @@ reload (first, global, dumpfile)
     spill_hard_reg (HARD_FRAME_POINTER_REGNUM, global, dumpfile, 1);
 #endif
 
+  finish_spills (global, dumpfile);
+
   if (global)
     for (i = 0; i < N_REG_CLASSES; i++)
       {
@@ -894,8 +915,7 @@ reload (first, global, dumpfile)
      reg does not necessarily imply any pseudo reg was spilled;
      sometimes we find a reload reg that no pseudo reg was allocated in.  */
   something_changed = 1;
-  /* This flag is set if there are any insns that require reloading.  */
-  something_needs_reloads = 0;
+
   /* This flag is set if there are any insns that require register
      eliminations.  */
   something_needs_elimination = 0;
@@ -1002,7 +1022,7 @@ reload (first, global, dumpfile)
 	  reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
 	}
 
-      something_changed |= calculate_needs_all_insns (first, global);
+      something_changed |= calculate_needs_all_insns (global);
 
       /* If we allocated any new memory locations, make another pass
 	 since it might have changed elimination offsets.  */
@@ -1024,6 +1044,8 @@ reload (first, global, dumpfile)
 	    }
       }
 
+      finish_spills (global, dumpfile);
+
       /* If all needs are met, we win.  */
 
       for (i = 0; i < N_REG_CLASSES; i++)
@@ -1075,8 +1097,10 @@ reload (first, global, dumpfile)
       if (failure)
 	goto failed;
 
+      finish_spills (global, dumpfile);
+
       if (something_changed)
-	delete_caller_save_insns (first);
+	delete_caller_save_insns ();
     }
 
   /* If global-alloc was run, notify it of any register eliminations we have
@@ -1111,8 +1135,8 @@ reload (first, global, dumpfile)
      by generating move instructions to move the must-be-register
      values into or out of the reload registers.  */
 
-  if (something_needs_reloads || something_needs_elimination)
-    reload_as_needed (first, global);
+  if (insns_need_reload != 0 || something_needs_elimination)
+    reload_as_needed (global);
 
   /* If we were able to eliminate the frame pointer, show that it is no
      longer live at the start of any basic block.  If it ls live by
@@ -1225,8 +1249,6 @@ reload (first, global, dumpfile)
 	warning ("frame size too large for reliable stack checking");
     }
 
-  obstack_free (&reload_obstack, reload_startobj);
-
   /* Indicate that we no longer have known memory locations or constants.  */
   reg_equiv_constant = 0;
   reg_equiv_memory_loc = 0;
@@ -1243,10 +1265,16 @@ reload (first, global, dumpfile)
   free (reg_equiv_address);
   free (reg_max_ref_width);
 
+  FREE_REG_SET (spilled_pseudos);
+
   CLEAR_HARD_REG_SET (used_spill_regs);
   for (i = 0; i < n_spills; i++)
     SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
 
+  /* Free all the insn_chain structures at once.  */
+  obstack_free (&reload_obstack, reload_startobj);
+  unused_insn_chains = 0;
+
   return failure;
 }
 
@@ -1254,24 +1282,20 @@ reload (first, global, dumpfile)
    information about the need to do register elimination and the need to
    perform reloads.  */
 static int
-calculate_needs_all_insns (first, global)
-     rtx first;
+calculate_needs_all_insns (global)
      int global;
 {
-  rtx insn;
   int something_changed = 0;
   rtx after_call = 0;
-  /* Keep track of which basic blocks are needing the reloads.  */
-  int this_block = 0;
+  struct insn_chain **pprev_reload = &insns_need_reload;
+  struct insn_chain *chain;
 
   /* Compute the most additional registers needed by any instruction.
      Collect information separately for each class of regs.  */
-
-  for (insn = first; insn; insn = NEXT_INSN (insn))
+  
+  for (chain = reload_insn_chain; chain; chain = chain->next)
     {
-      if (global && this_block + 1 < n_basic_blocks
-	  && insn == basic_block_head[this_block+1])
-	++this_block;
+      rtx insn = chain->insn;
 
       /* If this is a label, a JUMP_INSN, or has REG_NOTES (which
 	 might include REG_LABEL), we need to see what effects this
@@ -1324,23 +1348,9 @@ calculate_needs_all_insns (first, global
 			spill_reg_order);
 
 	  /* Remember for later shortcuts which insns had any reloads or
-	     register eliminations.
-
-	     One might think that it would be worthwhile to mark insns
-	     that need register replacements but not reloads, but this is
-	     not safe because find_reloads may do some manipulation of
-	     the insn (such as swapping commutative operands), which would
-	     be lost when we restore the old pattern after register
-	     replacement.  So the actions of find_reloads must be redone in
-	     subsequent passes or in reload_as_needed.
-
-	     However, it is safe to mark insns that need reloads
-	     but not register replacement.  */
-
-	  PUT_MODE (insn, (did_elimination ? QImode
-			   : n_reloads ? HImode
-			   : GET_MODE (insn) == DImode ? DImode
-			   : VOIDmode));
+	     register eliminations.  */
+	  chain->need_elim = did_elimination;
+	  chain->need_reload = n_reloads > 0;
 
 	  /* Discard any register replacements done.  */
 	  if (did_elimination)
@@ -1353,12 +1363,15 @@ calculate_needs_all_insns (first, global
 	    }
 
 	  if (n_reloads != 0)
-	    something_changed |= calculate_needs (this_block, insn,
-						  avoid_return_reg, global);
+	    {
+	      *pprev_reload = chain;
+	      pprev_reload = &chain->next_need_reload;
+	      something_changed |= calculate_needs (chain, avoid_return_reg,
+						    global);
+	    }
 	}
-
-      /* Note that there is a continue statement above.  */
     }
+  *pprev_reload = 0;
   return something_changed;
 }
 
@@ -1381,21 +1394,15 @@ calculate_needs_all_insns (first, global
    inputs and outputs.  */
 
 static int
-calculate_needs (this_block, insn, avoid_return_reg, global)
-     int this_block;
-     rtx insn, avoid_return_reg;
+calculate_needs (chain, avoid_return_reg, global)
+     struct insn_chain *chain;
+     rtx avoid_return_reg;
      int global;
 {
+  rtx insn = chain->insn;
   int something_changed = 0;
   int i;
 
-  struct needs
-  {
-    /* [0] is normal, [1] is nongroup.  */
-    int regs[2][N_REG_CLASSES];
-    int groups[N_REG_CLASSES];
-  };
-
   /* Each `struct needs' corresponds to one RELOAD_... type.  */
   struct {
     struct needs other;
@@ -1411,7 +1418,6 @@ calculate_needs (this_block, insn, avoid
     struct needs out_addr_addr[MAX_RECOG_OPERANDS];
   } insn_needs;
 
-  something_needs_reloads = 1;
   bzero ((char *) &insn_needs, sizeof insn_needs);
 
   /* Count each reload once in every class
@@ -1439,9 +1445,9 @@ calculate_needs (this_block, insn, avoid
 	 in this basic block.  We do not use insn_needs and
 	 insn_groups because they are overly conservative for
 	 this purpose.  */
-      if (global && ! basic_block_needs[(int) class][this_block])
+      if (global && ! basic_block_needs[(int) class][chain->block])
 	{
-	  basic_block_needs[(int) class][this_block] = 1;
+	  basic_block_needs[(int) class][chain->block] = 1;
 	  something_changed = 1;
 	}
 
@@ -1701,6 +1707,10 @@ calculate_needs (this_block, insn, avoid
 	  max_nongroups_insn[i] = insn;
 	}
     }
+
+  /* Record the needs for later.  */
+  chain->need = insn_needs.other;
+
   return something_changed;
 }
 
@@ -2062,41 +2072,39 @@ dump_needs (dumpfile)
 /* Delete all insns that were inserted by emit_caller_save_insns during
    this iteration.  */
 static void
-delete_caller_save_insns (first)
-     rtx first;
+delete_caller_save_insns ()
 {
-  rtx insn = first;
-  int b = -1;
+  struct insn_chain *c = reload_insn_chain;
 
-  while (insn != 0)
+  while (c != 0)
     {
-      if (b + 1 != n_basic_blocks
-	  && basic_block_head[b + 1] == insn)
-	b++;
-
-      while (insn != 0 && INSN_UID (insn) >= reload_first_uid)
+      while (c != 0 && c->is_caller_save_insn)
 	{
-	  rtx next = NEXT_INSN (insn);
-	  rtx prev = PREV_INSN (insn);
-
-	  if (insn == basic_block_head[b])
-	    basic_block_head[b] = next;
-	  if (insn == basic_block_end[b])
-	    basic_block_end[b] = prev;
-
-	  if (next != 0)
-	    PREV_INSN (next) = prev;
-	  if (prev != 0)
-	    NEXT_INSN (prev) = next;
-
-	  insn = next;
-
-	  if (b + 1 != n_basic_blocks
-	      && basic_block_head[b + 1] == insn)
-	    b++;
+	  struct insn_chain *next = c->next;
+	  rtx insn = c->insn;
+
+	  if (insn == basic_block_head[c->block])
+	    basic_block_head[c->block] = NEXT_INSN (insn);
+	  if (insn == basic_block_end[c->block])
+	    basic_block_end[c->block] = PREV_INSN (insn);
+	  if (c == reload_insn_chain)
+	    reload_insn_chain = next;
+
+	  if (NEXT_INSN (insn) != 0)
+	    PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+	  if (PREV_INSN (insn) != 0)
+	    NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+
+	  if (next)
+	    next->prev = c->prev;
+	  if (c->prev)
+	    c->prev->next = next;
+	  c->next = unused_insn_chains;
+	  unused_insn_chains = c;
+	  c = next;
 	}
-      if (insn != 0)
-	insn = NEXT_INSN (insn);
+      if (c != 0)
+	c = c->next;
     }
 }
 
@@ -3807,6 +3815,10 @@ spill_hard_reg (regno, global, dumpfile,
 	  retry_global_alloc (i, forbidden_regs);
 
 	alter_reg (i, regno);
+
+	if (reg_renumber[i] == -1)
+	  SET_REGNO_REG_SET (spilled_pseudos, i);
+
 	if (dumpfile)
 	  {
 	    if (reg_renumber[i] == -1)
@@ -3819,6 +3831,22 @@ spill_hard_reg (regno, global, dumpfile,
 
   return something_changed;
 }
+
+/* Clear the contents of spilled_pseudos from the life information in all
+   insn chains.  */
+static void
+finish_spills (global, dumpfile)
+     int global;
+     FILE *dumpfile;
+{
+  struct insn_chain *chain;
+
+  for (chain = reload_insn_chain; chain; chain = chain->next)
+    {
+      AND_COMPL_REG_SET (chain->live_before, spilled_pseudos);
+      AND_COMPL_REG_SET (chain->live_after, spilled_pseudos);
+    }
+}
 
 /* Find all paradoxical subregs within X and update reg_max_ref_width. 
    Also mark any hard registers used to store user variables as
@@ -4023,13 +4051,11 @@ compare_spill_regs (r1p, r2p)
    as the insns are scanned.  */
 
 static void
-reload_as_needed (first, live_known)
-     rtx first;
+reload_as_needed (live_known)
      int live_known;
 {
-  register rtx insn;
+  struct insn_chain *chain;
   register int i;
-  int this_block = 0;
   rtx x;
   rtx after_call = 0;
 
@@ -4066,15 +4092,11 @@ reload_as_needed (first, live_known)
 	spill_reg_order[spill_regs[i]] = i;
     }
 
-  for (insn = first; insn;)
+  for (chain = reload_insn_chain; chain; chain = chain->next)
     {
-      register rtx next = NEXT_INSN (insn);
+      rtx insn = chain->insn;
+      rtx old_next = NEXT_INSN (insn);
 
-      /* Notice when we move to a new basic block.  */
-      if (live_known && this_block + 1 < n_basic_blocks
-	  && insn == basic_block_head[this_block+1])
-	++this_block;
-
       /* If we pass a label, copy the offsets from the label information
 	 into the current offsets of each elimination.  */
       if (GET_CODE (insn) == CODE_LABEL)
@@ -4131,17 +4153,21 @@ reload_as_needed (first, live_known)
 
 	  /* If we need to do register elimination processing, do so.
 	     This might delete the insn, in which case we are done.  */
-	  if (num_eliminable && GET_MODE (insn) == QImode)
+	  if (num_eliminable && chain->need_elim)
 	    {
 	      eliminate_regs_in_insn (insn, 1);
 	      if (GET_CODE (insn) == NOTE)
-		{
-		  insn = next;
-		  continue;
-		}
+		continue;
 	    }
 
-	  if (GET_MODE (insn) == VOIDmode)
+	  /* If need_elim is nonzero but need_reload is zero, one might think
+	     that we could simply set n_reloads to 0.  However, find_reloads
+	     could have done some manipulation of the insn (such as swapping
+	     commutative operands), and these manipulations are lost during
+	     the first pass for every insn that needs register elimination.
+	     So the actions of find_reloads must be redone here.  */
+
+	  if (! chain->need_elim && ! chain->need_reload)
 	    n_reloads = 0;
 	  /* First find the pseudo regs that must be reloaded for this insn.
 	     This info is returned in the tables reload_... (see reload.h).
@@ -4168,7 +4194,7 @@ reload_as_needed (first, live_known)
 
 	      for (class = 0; class < N_REG_CLASSES; class++)
 		if (basic_block_needs[class] != 0
-		    && basic_block_needs[class][this_block] == 0)
+		    && basic_block_needs[class][chain->block] == 0)
 		  for (i = 0; i < n_reloads; i++)
 		    if (class == (int) reload_reg_class[i]
 			&& reload_reg_rtx[i] == 0
@@ -4181,7 +4207,7 @@ reload_as_needed (first, live_known)
 		 reusing reload regs from previous insns, or else output
 		 load insns to reload them.  Maybe output store insns too.
 		 Record the choices of reload reg in reload_reg_rtx.  */
-	      choose_reload_regs (insn, avoid_return_reg);
+	      choose_reload_regs (chain, avoid_return_reg);
 
 	      /* Merge any reloads that we didn't combine for fear of 
 		 increasing the number of spill registers needed but now
@@ -4191,7 +4217,7 @@ reload_as_needed (first, live_known)
 
 	      /* Generate the insns to reload operands into or out of
 		 their reload regs.  */
-	      emit_reload_insns (insn, this_block);
+	      emit_reload_insns (chain);
 
 	      /* Substitute the chosen reload regs from reload_reg_rtx
 		 into the insn's body (or perhaps into the bodies of other
@@ -4227,7 +4253,7 @@ reload_as_needed (first, live_known)
 
 	  /* There may have been CLOBBER insns placed after INSN.  So scan
 	     between INSN and NEXT and use them to forget old reloads.  */
-	  for (x = NEXT_INSN (insn); x != next; x = NEXT_INSN (x))
+	  for (x = NEXT_INSN (insn); x != old_next; x = NEXT_INSN (x))
 	    if (GET_CODE (x) == INSN && GET_CODE (PATTERN (x)) == CLOBBER)
 	      note_stores (PATTERN (x), forget_old_reloads_1);
 
@@ -4269,8 +4295,6 @@ reload_as_needed (first, live_known)
 	  CLEAR_HARD_REG_BIT (reg_reloaded_valid, i);
 #endif
 
-      insn = next;
-
 #ifdef USE_C_ALLOCA
       alloca (0);
 #endif
@@ -5214,12 +5238,13 @@ reload_reg_free_for_value_p (regno, opnu
    or 0 if we couldn't find a spill reg and we didn't change anything.  */
 
 static int
-allocate_reload_reg (r, insn, last_reload, noerror)
+allocate_reload_reg (chain, r, last_reload, noerror)
+     struct insn_chain *chain;
      int r;
-     rtx insn;
      int last_reload;
      int noerror;
 {
+  rtx insn = chain->insn;
   int i;
   int pass;
   int count;
@@ -5420,10 +5445,11 @@ allocate_reload_reg (r, insn, last_reloa
    finding a reload reg in the proper class.  */
 
 static void
-choose_reload_regs (insn, avoid_return_reg)
-     rtx insn;
+choose_reload_regs (chain, avoid_return_reg)
+     struct insn_chain *chain;
      rtx avoid_return_reg;
 {
+  rtx insn = chain->insn;
   register int i, j;
   int max_group_size = 1;
   enum reg_class group_class = NO_REGS;
@@ -5666,7 +5692,7 @@ choose_reload_regs (insn, avoid_return_r
 		   || reload_secondary_p[reload_order[i]])
 		  && ! reload_optional[reload_order[i]]
 		  && reload_reg_rtx[reload_order[i]] == 0)
-		allocate_reload_reg (reload_order[i], insn, 0, inheritance);
+		allocate_reload_reg (chain, reload_order[i], 0, inheritance);
 #endif
 
 	  /* First see if this pseudo is already available as reloaded
@@ -5992,7 +6018,7 @@ choose_reload_regs (insn, avoid_return_r
 	  if (i == n_reloads)
 	    continue;
 
-	  allocate_reload_reg (r, insn, j == n_reloads - 1, inheritance);
+	  allocate_reload_reg (chain, r, j == n_reloads - 1, inheritance);
 #endif
 	}
 
@@ -6011,7 +6037,7 @@ choose_reload_regs (insn, avoid_return_r
 	  if (reload_reg_rtx[r] != 0 || reload_optional[r])
 	    continue;
 
-	  if (! allocate_reload_reg (r, insn, j == n_reloads - 1, inheritance))
+	  if (! allocate_reload_reg (chain, r, j == n_reloads - 1, inheritance))
 	    break;
 	}
 
@@ -6310,10 +6336,11 @@ merge_assigned_reloads (insn)
 /* Output insns to reload values in and out of the chosen reload regs.  */
 
 static void
-emit_reload_insns (insn, bb)
-     rtx insn;
-     int bb;
+emit_reload_insns (chain)
+     struct insn_chain *chain;
 {
+  rtx insn = chain->insn;
+
   register int j;
   rtx input_reload_insns[MAX_RECOG_OPERANDS];
   rtx other_input_address_reload_insns = 0;
@@ -7257,10 +7284,10 @@ emit_reload_insns (insn, bb)
   /* Keep basic block info up to date.  */
   if (n_basic_blocks)
     {
-      if (basic_block_head[bb] == insn)
-        basic_block_head[bb] = NEXT_INSN (before_insn);
-      if (basic_block_end[bb] == insn)
-        basic_block_end[bb] = PREV_INSN (following_insn);
+      if (basic_block_head[chain->block] == insn)
+        basic_block_head[chain->block] = NEXT_INSN (before_insn);
+      if (basic_block_end[chain->block] == insn)
+        basic_block_end[chain->block] = PREV_INSN (following_insn);
     }
 
   /* Move death notes from INSN
Index: rtl.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.texi,v
retrieving revision 1.12
diff -u -p -r1.12 rtl.texi
--- rtl.texi	1998/09/05 21:57:56	1.12
+++ rtl.texi	1998/10/07 12:13:25
@@ -2372,9 +2372,7 @@ These codes are printed symbolically whe
 @cindex @code{HImode}, in @code{insn}
 @cindex @code{QImode}, in @code{insn}
 The machine mode of an insn is normally @code{VOIDmode}, but some
-phases use the mode for various purposes; for example, the reload pass
-sets it to @code{HImode} if the insn needs reloading but not register
-elimination and @code{QImode} if both are required. 
+phases use the mode for various purposes. 
 
 The common subexpression elimination pass sets the mode of an insn to
 @code{QImode} when it is the first insn in a block that has already


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