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]

hard register reload patch


As discussed before, there are sometimes cases where a hard register is
mentioned in an insn, yet it needs to be available for reloads, e.g.
the explicit use is an input and we need the same register for an output
reload, or vice versa.
This used to work -after a fashion - for SMALL_REGISTER_CLASSES machines
before the local spilling patch went in.  If no other hard register was
available, an explicitly mentioned one was acceptable for reload.
The downside was, of course, that the port had to 'know' what spills could
possibly happen, and avoid live hard registers when a spill of their class
could be needed.

Now, the local spilling code will not care about registers that are used in
some other insn far away, but if the register is mentioned in an insn, it
is not available at all for reloads - hence you can easily run out of
registers in small registers classes, e.g. FPUL_REGS on the SH - there
is only one fpul register.

As discussed before, I aim to recitify this problem by recording the lifetime
of the explicitly mentioned hard regsiters by using special reloads.
(I have called them 'hard reload' in the code below).
These reloads are emitted after the ordinary reloads, so the trick to keep
reload register pressure under control still works for RELOAD_FOR_X_ADDR /
RELOAD_FOR_X_ADDR_ADDR combination where there are other RELOAD_FOR_X_ADDRs,
but none of the others use the RELOAD_FOR_X_ADDR_ADDR, and the all come later
than the RELOAD_FOR_X_ADDR that uses the RELOAD_FOR_X_ADDR_ADDR.

You can tell a hard reload from an ordinary one because it always has the
reg_rtx field set, and it is equal to the in or out field, or to both.
Hard reloads have a longer lifetime than ordinary ones; input hard reloads
occupy the register before the very first ordinary reloads
(RELOAD_FOR_OTHER_ADDRESS) do.  And output hard reloads occupy their
register after all ordinary output reloads and their secondary reloads
are done.
I have reflected this by setting the appropriate bits in
choose_reload_regs_init, and some specific tests in
reload_reg_free_for_value_p.

This patch is also expected to make reload a bit faster for large programs;
instead of using regsets live_before and live_after, which were used
in tandem all the time, I use live_throughout and dead_or_set.
In a typical instruction, only few registers die or are set, so the latter
regset should be pretty quick to process - when it has to be processed;
often just processing live_throughout does just fine.

Mon Nov 29 19:49:38 1999  J"orn Rennecke <amylaar@cygnus.co.uk>

	* caller-save.c (save_call_clobbered_regs): Get register liveness
	information from chain->live_throughout.
	(add_stored_regs): New function.
	* global.c (reg_dies): New parameter chain.
	(reg_becomes_live): Third parameter is regs_set now.
	Changed all callers.
	(reg_dies): New parameter chain.  Changed all callers.
	(build_insn_chain): Set live_throughout instead of
	live_before / live_after.
	* reload.c (basic-block.h): #include.
	(reload.h):#include after had-reg-set.h & basic-block.h .
	(n_earlyclobbers, reload_earlyclobbers): Now static.
	(combine_reloads): Deleted.
	(push_hard_reload, note_earlyclobbers): New functions.
	(earlyclobber_overlap_p, mentioned_in_operand): Likewise.
	(find_reloads): First parameter is now of type struct insn_chain*.
	Changed all callers.
	Set used_spill_regs to the set of regsisters that die or are set
	in this insn.  Push hard register reloads for these registers.
	* reload.h (n_earlyclobbers, reload_earlyclobbers): Don't declare.
	(struct insn_chain): Replace members live_before / live_after with
	live_throughout / dead_or_set.
	(find_reloads): Update declaration.
	(earlyclobber_overlap_p): Update declaration.
	* reload1.c (reg_reloaded_dead, pseudos_counted): Delete.  Reoved all
	sets / uses.
	(spill_pseudo, hard_reload_conflict): New functions.
	(mark_regs_outside_operands): Likewise.
	(new_insn_chain): Set live_throughout / dead_or_set instead of
	live_before / live_after.
	(reload): Call mark_regs_outside_operands.
	(maybe_fix_stack_asms): Clear bits in chain->live_throughout instead of
	in chain->live_before / chain->live_after.
	(order_regs_for_reload): Test chain->live_throughout instead of
	chain->live_before / chain->live_after.
	(find_reg): Look at all reloads for conflicts.
	Call hard_reload_conflict.
	Test chain->live_troughout instead of chain->live_before and
	chain->live_after.
	(find_reload_regs): Call spill_pseudo.
	Don't overwrite used_spill_regs, ior to it.
	(finish_spills): Fix up chain->live_troughout / chain->dead_or_set
	instead of chain->live_before and chain->live_after.
	Don't adjust used_spill_regs.
	(reload_reg_free_p): Check reg_used_in_insn.
	(reload_reg_fre_for_value_p): Don't test reload_reg_used.
	In RELOAD_OTHER case, use earlyclobber_overlap_p for earlyclobber test.
	Test for conflicts with hard reloads.
	(allocate_reload_reg): Check reg_used_in_insn, not reload_reg_used.
	(choose_reload_regs_init): Use chain->live_throughout instead of
	chain->live_before and chain->live_after.
	Don't mess with reload_reg_used.
	Mark register usage of hard reloads.
	(choose_reload_regs): Use earlyclobber_overlap_p.
	Use search_equiv as value, and NULL_RTX as out to pass to
	reload_reg_free_for_value_p.
	Make action taken for earlyclobber operands dependent on reload type.
	Don't abort for RELOAD_FOR_OUTPUT_ADDRESS hard reloads.
	(emit_reload_insns): Remove reg_reloaded_dead / reg_relaoded_died code.
	* stupid.c (current_chain, find_clobbered_regs): Delete.
	(stupid_life_analysis): Set chain->live_throughout chain->dead_or_set
	instead of chain->live_before / chain->live_after.
	(mark_hard_ref): New function.
	(stupid_mark_refs): Call mark_hard_ref.  Consistently add REG_DEAD /
	REG_UNUSED notes for pseudos.  Clear chain->live_throughout.

diff -p allocpatch/caller-save.c ./caller-save.c
*** allocpatch/caller-save.c	Tue Nov 23 22:45:40 1999
--- ./caller-save.c	Mon Nov 29 21:38:35 1999
*************** save_call_clobbered_regs ()
*** 373,389 ****
  
  	  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, NULL);
  
--- 373,392 ----
  
  	  if (code == CALL_INSN)
  	    {
! 	      int regno;
  	      HARD_REG_SET hard_regs_to_save;
  
  	      /* Use the register life information in CHAIN to compute which
! 		 regs are live during the call.  */
! 	      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
! 				       chain->live_throughout);
! 	      compute_use_by_pseudos (&hard_regs_to_save,
! 				      chain->live_throughout);
  
  	      /* Record all registers set in this call insn.  These don't need
! 		 to be saved.  N.B. the call insn might set a subreg of a
! 		 multi-hard-reg pseudo; then the pseudo is considered live
! 		 during the call, but the subreg that is set isn't.  */
  	      CLEAR_HARD_REG_SET (this_insn_sets);
  	      note_stores (PATTERN (insn), mark_set_regs, NULL);
  
*************** save_call_clobbered_regs ()
*** 393,437 ****
  	      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))
- 		{
- 		  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);
- 		}
- 
- 	      /* Neither do registers for which we find a death note.  */
- 	      for (x = REG_NOTES (insn); x != 0; x = XEXP (x, 1))
- 		{
- 		  rtx y = XEXP (x, 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);
--- 396,401 ----
*************** mark_set_regs (reg, setter, data)
*** 490,495 ****
--- 454,492 ----
      SET_HARD_REG_BIT (this_insn_sets, i);
  }
  
+ /* Here from note_stores when an insn stores a value in a register.
+    Set the proper bit or bits in the passed regset.  All pseudos that have
+    been assigned hard regs have had their register number changed already,
+    so we can ignore pseudos.  */
+ static void
+ add_stored_regs (reg, setter, data)
+      rtx reg;
+      rtx setter;
+      void *data;
+ {
+   register int regno, endregno, i;
+   enum machine_mode mode = GET_MODE (reg);
+   int word = 0;
+ 
+   if (GET_CODE (setter) == CLOBBER)
+     return;
+ 
+   if (GET_CODE (reg) == SUBREG)
+     {
+       word = SUBREG_WORD (reg);
+       reg = SUBREG_REG (reg);
+     }
+ 
+   if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
+     return;
+ 
+   regno = REGNO (reg) + word;
+   endregno = regno + HARD_REGNO_NREGS (regno, mode);
+ 
+   for (i = regno; i < endregno; i++)
+     SET_REGNO_REG_SET ((regset) data, i);
+ }
+ 
  /* Walk X and record all referenced registers in REFERENCED_REGS.  */
  static void
  mark_referenced_regs (x)
*************** insert_one_insn (chain, before_p, code, 
*** 721,726 ****
--- 718,725 ----
    new = new_insn_chain ();
    if (before_p)
      {
+       rtx link;
+ 
        new->prev = chain->prev;
        if (new->prev != 0)
  	new->prev->next = new;
*************** insert_one_insn (chain, before_p, code, 
*** 732,739 ****
        new->insn = emit_insn_before (pat, insn);
        /* ??? It would be nice if we could exclude the already / still saved
  	 registers from the live sets.  */
!       COPY_REG_SET (new->live_before, chain->live_before);
!       COPY_REG_SET (new->live_after, chain->live_before);
        if (chain->insn == BLOCK_HEAD (chain->block))
  	BLOCK_HEAD (chain->block) = new->insn;
      }
--- 731,759 ----
        new->insn = emit_insn_before (pat, insn);
        /* ??? It would be nice if we could exclude the already / still saved
  	 registers from the live sets.  */
!       COPY_REG_SET (new->live_throughout, chain->live_throughout);
!       /* Registers that die in CHAIN->INSN still live in the new insn.  */
!       for (link = REG_NOTES (chain->insn); link; link = XEXP (link, 1))
! 	{
! 	  if (REG_NOTE_KIND (link) == REG_DEAD)
! 	    {
! 	      rtx reg = XEXP (link, 0);
! 	      int regno, i;
! 
! 	      if (GET_CODE (reg) != REG)
! 		abort ();
! 
! 	      regno = REGNO (reg);
! 	      if (regno >= FIRST_PSEUDO_REGISTER)
! 		regno = reg_renumber[regno];
! 	      if (regno < 0)
! 		continue;
! 	      for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
! 		   i >= 0; i--)
! 		SET_REGNO_REG_SET (new->live_throughout, regno + i);
! 	    }
! 	}
!       CLEAR_REG_SET (new->dead_or_set);
        if (chain->insn == BLOCK_HEAD (chain->block))
  	BLOCK_HEAD (chain->block) = new->insn;
      }
*************** insert_one_insn (chain, before_p, code, 
*** 747,754 ****
        new->insn = emit_insn_after (pat, insn);
        /* ??? It would be nice if we could exclude the already / still saved
  	 registers from the live sets, and observe REG_UNUSED notes.  */
!       COPY_REG_SET (new->live_before, chain->live_after);
!       COPY_REG_SET (new->live_after, chain->live_after);
        if (chain->insn == BLOCK_END (chain->block))
  	BLOCK_END (chain->block) = new->insn;
      }
--- 767,779 ----
        new->insn = emit_insn_after (pat, insn);
        /* ??? It would be nice if we could exclude the already / still saved
  	 registers from the live sets, and observe REG_UNUSED notes.  */
!       COPY_REG_SET (new->live_throughout, chain->live_throughout);
!       /* Registers that are set in CHAIN->INSN live in the new insn.
!          (Unless there is a REG_UNUSED note for them, but we don't
! 	  look for them here.) */
!       note_stores (PATTERN (chain->insn), add_stored_regs,
! 		   new->live_throughout);
!       CLEAR_REG_SET (new->dead_or_set);
        if (chain->insn == BLOCK_END (chain->block))
  	BLOCK_END (chain->block) = new->insn;
      }
diff -p allocpatch/global.c ./global.c
*** allocpatch/global.c	Tue Nov 23 22:45:41 1999
--- ./global.c	Sat Nov 13 03:30:09 1999
*************** static void mark_reg_live_nc	PROTO((int,
*** 335,339 ****
  static void set_preference	PROTO((rtx, rtx));
  static void dump_conflicts	PROTO((FILE *));
  static void reg_becomes_live	PROTO((rtx, rtx, void *));
! static void reg_dies		PROTO((int, enum machine_mode));
  static void build_insn_chain	PROTO((rtx));
--- 335,340 ----
  static void set_preference	PROTO((rtx, rtx));
  static void dump_conflicts	PROTO((FILE *));
  static void reg_becomes_live	PROTO((rtx, rtx, void *));
! static void reg_dies		PROTO((int, enum machine_mode,
! 				       struct insn_chain *));
  static void build_insn_chain	PROTO((rtx));
*************** mark_elimination (from, to)
*** 2161,2173 ****
     current life information.  */
  static regset live_relevant_regs;
  
! /* Record in live_relevant_regs that register REG became live.  This
!    is called via note_stores.  */
  static void
! reg_becomes_live (reg, setter, data)
       rtx reg;
       rtx setter ATTRIBUTE_UNUSED;
!      void *data ATTRIBUTE_UNUSED;
  {
    int regno;
  
--- 2162,2174 ----
     current life information.  */
  static regset live_relevant_regs;
  
! /* Record in live_relevant_regs and REGS_SET that register REG became live.
!    This is called via note_stores.  */
  static void
! reg_becomes_live (reg, setter, regs_set)
       rtx reg;
       rtx setter ATTRIBUTE_UNUSED;
!      void *regs_set;
  {
    int regno;
  
*************** reg_becomes_live (reg, setter, data)
*** 2182,2207 ****
      {
        int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
        while (nregs-- > 0)
! 	SET_REGNO_REG_SET (live_relevant_regs, regno++);
      }
    else if (reg_renumber[regno] >= 0)
!     SET_REGNO_REG_SET (live_relevant_regs, regno);
  }
  
  /* Record in live_relevant_regs that register REGNO died.  */
  static void
! reg_dies (regno, mode)
       int regno;
       enum machine_mode mode;
  {
    if (regno < FIRST_PSEUDO_REGISTER)
      {
        int nregs = HARD_REGNO_NREGS (regno, mode);
        while (nregs-- > 0)
! 	CLEAR_REGNO_REG_SET (live_relevant_regs, regno++);
      }
    else
!     CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
  }
  
  /* Walk the insns of the current function and build reload_insn_chain,
--- 2183,2226 ----
      {
        int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
        while (nregs-- > 0)
! 	{
! 	  SET_REGNO_REG_SET (live_relevant_regs, regno);
! 	  if (! fixed_regs[regno])
! 	    SET_REGNO_REG_SET ((regset) regs_set, regno);
! 	  regno++;
! 	}
      }
    else if (reg_renumber[regno] >= 0)
!     {
!       SET_REGNO_REG_SET (live_relevant_regs, regno);
!       SET_REGNO_REG_SET ((regset) regs_set, regno);
!     }
  }
  
  /* Record in live_relevant_regs that register REGNO died.  */
  static void
! reg_dies (regno, mode, chain)
       int regno;
       enum machine_mode mode;
+      struct insn_chain *chain;
  {
    if (regno < FIRST_PSEUDO_REGISTER)
      {
        int nregs = HARD_REGNO_NREGS (regno, mode);
        while (nregs-- > 0)
! 	{
! 	  CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
! 	  if (! fixed_regs[regno])
! 	    SET_REGNO_REG_SET (chain->dead_or_set, regno);
! 	  regno++;
! 	}
      }
    else
!     {
!       CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
!       if (reg_renumber[regno] >= 0)
! 	SET_REGNO_REG_SET (chain->dead_or_set, regno);
!     }
  }
  
  /* Walk the insns of the current function and build reload_insn_chain,
*************** build_insn_chain (first)
*** 2246,2253 ****
  	  c->insn = first;
  	  c->block = b;
  
- 	  COPY_REG_SET (c->live_before, live_relevant_regs);
- 
  	  if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
  	    {
  	      rtx link;
--- 2265,2270 ----
*************** build_insn_chain (first)
*** 2257,2272 ****
  	      for (link = REG_NOTES (first); link; link = XEXP (link, 1))
  		if (REG_NOTE_KIND (link) == REG_DEAD
  		    && GET_CODE (XEXP (link, 0)) == REG)
! 		  reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
  
  	      /* Mark everything born in this instruction as live.  */
  
! 	      note_stores (PATTERN (first), reg_becomes_live, NULL);
  	    }
! 
! 	  /* Remember which registers are live at the end of the insn, before
! 	     killing those with REG_UNUSED notes.  */
! 	  COPY_REG_SET (c->live_after, live_relevant_regs);
  
  	  if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
  	    {
--- 2274,2291 ----
  	      for (link = REG_NOTES (first); link; link = XEXP (link, 1))
  		if (REG_NOTE_KIND (link) == REG_DEAD
  		    && GET_CODE (XEXP (link, 0)) == REG)
! 		  reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
! 			    c);
! 
! 	      COPY_REG_SET (c->live_throughout, live_relevant_regs);
  
  	      /* Mark everything born in this instruction as live.  */
  
! 	      note_stores (PATTERN (first), reg_becomes_live,
! 			   c->dead_or_set);
  	    }
! 	  else
! 	    COPY_REG_SET (c->live_throughout, live_relevant_regs);
  
  	  if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
  	    {
*************** build_insn_chain (first)
*** 2277,2283 ****
  	      for (link = REG_NOTES (first); link; link = XEXP (link, 1))
  		if (REG_NOTE_KIND (link) == REG_UNUSED
  		    && GET_CODE (XEXP (link, 0)) == REG)
! 		  reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
  	    }
  	}
  
--- 2296,2303 ----
  	      for (link = REG_NOTES (first); link; link = XEXP (link, 1))
  		if (REG_NOTE_KIND (link) == REG_UNUSED
  		    && GET_CODE (XEXP (link, 0)) == REG)
! 		  reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
! 			    c);
  	    }
  	}
  
diff -p allocpatch/reload.c ./reload.c
*** allocpatch/reload.c	Mon Nov 29 17:17:16 1999
--- ./reload.c	Mon Nov 29 20:22:09 1999
*************** a register with any other reload.  */
*** 94,102 ****
  #include "insn-config.h"
  #include "insn-codes.h"
  #include "recog.h"
- #include "reload.h"
  #include "regs.h"
  #include "hard-reg-set.h"
  #include "flags.h"
  #include "real.h"
  #include "output.h"
--- 94,103 ----
  #include "insn-config.h"
  #include "insn-codes.h"
  #include "recog.h"
  #include "regs.h"
  #include "hard-reg-set.h"
+ #include "basic-block.h"
+ #include "reload.h"
  #include "flags.h"
  #include "real.h"
  #include "output.h"
*************** struct reload rld[MAX_RELOADS];
*** 123,130 ****
  
  /* All the "earlyclobber" operands of the current insn
     are recorded here.  */
! int n_earlyclobbers;
! rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
  
  int reload_n_operands;
  
--- 124,131 ----
  
  /* All the "earlyclobber" operands of the current insn
     are recorded here.  */
! static int n_earlyclobbers;
! static rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
  
  int reload_n_operands;
  
*************** static enum reg_class find_valid_class P
*** 245,252 ****
  static int push_reload		PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
  				       enum machine_mode, enum machine_mode,
  				       int, int, int, enum reload_type));
  static void push_replacement	PROTO((rtx *, int, enum machine_mode));
- static void combine_reloads	PROTO((void));
  static int find_reusable_reload	PROTO((rtx *, rtx, enum reg_class,
  				       enum reload_type, int, int));
  static rtx find_dummy_reload	PROTO((rtx, rtx, rtx *, rtx *,
--- 246,253 ----
  static int push_reload		PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
  				       enum machine_mode, enum machine_mode,
  				       int, int, int, enum reload_type));
+ static void push_hard_reload	PROTO((int, int, int, enum reload_type));
  static void push_replacement	PROTO((rtx *, int, enum machine_mode));
  static int find_reusable_reload	PROTO((rtx *, rtx, enum reg_class,
  				       enum reload_type, int, int));
  static rtx find_dummy_reload	PROTO((rtx, rtx, rtx *, rtx *,
*************** static int find_inc_amount	PROTO((rtx, r
*** 273,278 ****
--- 274,280 ----
  static int loc_mentioned_in_p	PROTO((rtx *, rtx));
  extern void debug_reload_to_stream PROTO((FILE *));
  extern void debug_reload PROTO((void));
+ static void note_earlyclobbers	PROTO ((rtx, rtx, void *));
  
  #ifdef HAVE_SECONDARY_RELOADS
  
*************** push_reload (in, out, inloc, outloc, cla
*** 1481,1486 ****
--- 1483,1546 ----
    return i;
  }
  
+ /* Indicate that the hard register with register number REGNO is in use
+    for operand OPNUM, using a TYPE reload.  If IN_P is set, use
+    rld[].in / in_reg, otherwise rld[].out / out_reg.  */
+ static void
+ push_hard_reload (in_p, regno, opnum, type)
+      int in_p;
+      int regno;
+      int opnum;
+      enum reload_type type;
+ {
+   rtx x;
+   rtx in, out;
+   int i;
+   enum reg_class class = REGNO_REG_CLASS (regno);
+   enum machine_mode mode = reg_raw_mode[regno];
+ 
+   x = gen_rtx_REG (mode, regno);
+     x = gen_rtx_REG (GET_MODE (x), true_regnum (x));
+   if (in_p)
+     {
+       in = x;
+       out = NULL_RTX;
+     }
+   else
+     {
+       out = x;
+       in = NULL_RTX;
+     }
+ 
+   /* We want a specific reload register to be reserved for type / opnum,
+      thus re-using another reload is just asking for trouble.
+      So unconditionally add a new reload.  */
+ 
+   i = n_reloads;
+   rld[i].in = in;
+   rld[i].out = out;
+   rld[i].class = class;
+   rld[i].inmode = in_p ? mode : VOIDmode;
+   rld[i].outmode = in_p ? VOIDmode : mode;
+   rld[i].reg_rtx = x;
+   rld[i].optional = 0;
+   rld[i].nongroup = 0;
+   rld[i].inc = 0;
+   rld[i].nocombine = 0;
+   rld[i].in_reg = in;
+   rld[i].out_reg = out;
+   rld[i].opnum = opnum;
+   rld[i].when_needed = type;
+   rld[i].secondary_in_reload = -1;
+   rld[i].secondary_out_reload = -1;
+   rld[i].secondary_in_icode = CODE_FOR_nothing;
+   rld[i].secondary_out_icode = CODE_FOR_nothing;
+   rld[i].secondary_p = 0;
+   rld[i].reg_rtx = x;
+ 
+   n_reloads++;
+ }
+ 
  /* Record an additional place we must replace a value
     for which we have already recorded a reload.
     RELOADNUM is the value returned by push_reload
*************** loc_mentioned_in_p (loc, in)
*** 1582,1764 ****
    return 0;
  }
  
- /* If there is only one output reload, and it is not for an earlyclobber
-    operand, try to combine it with a (logically unrelated) input reload
-    to reduce the number of reload registers needed.
- 
-    This is safe if the input reload does not appear in
-    the value being output-reloaded, because this implies
-    it is not needed any more once the original insn completes.
- 
-    If that doesn't work, see we can use any of the registers that
-    die in this insn as a reload register.  We can if it is of the right
-    class and does not appear in the value being output-reloaded.  */
- 
- static void
- combine_reloads ()
- {
-   int i;
-   int output_reload = -1;
-   int secondary_out = -1;
-   rtx note;
- 
-   /* Find the output reload; return unless there is exactly one
-      and that one is mandatory.  */
- 
-   for (i = 0; i < n_reloads; i++)
-     if (rld[i].out != 0)
-       {
- 	if (output_reload >= 0)
- 	  return;
- 	output_reload = i;
-       }
- 
-   if (output_reload < 0 || rld[output_reload].optional)
-     return;
- 
-   /* An input-output reload isn't combinable.  */
- 
-   if (rld[output_reload].in != 0)
-     return;
- 
-   /* If this reload is for an earlyclobber operand, we can't do anything.  */
-   if (earlyclobber_operand_p (rld[output_reload].out))
-     return;
- 
-   /* Check each input reload; can we combine it?  */
- 
-   for (i = 0; i < n_reloads; i++)
-     if (rld[i].in && ! rld[i].optional && ! rld[i].nocombine
- 	/* Life span of this reload must not extend past main insn.  */
- 	&& rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
- 	&& rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS
- 	&& rld[i].when_needed != RELOAD_OTHER
- 	&& (CLASS_MAX_NREGS (rld[i].class, rld[i].inmode)
- 	    == CLASS_MAX_NREGS (rld[output_reload].class,
- 				rld[output_reload].outmode))
- 	&& rld[i].inc == 0
- 	&& rld[i].reg_rtx == 0
- #ifdef SECONDARY_MEMORY_NEEDED
- 	/* Don't combine two reloads with different secondary
- 	   memory locations.  */
- 	&& (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum] == 0
- 	    || secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] == 0
- 	    || rtx_equal_p (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum],
- 			    secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum]))
- #endif
- 	&& (SMALL_REGISTER_CLASSES
- 	    ? (rld[i].class == rld[output_reload].class)
- 	    : (reg_class_subset_p (rld[i].class,
- 				   rld[output_reload].class)
- 	       || reg_class_subset_p (rld[output_reload].class,
- 				      rld[i].class)))
- 	&& (MATCHES (rld[i].in, rld[output_reload].out)
- 	    /* Args reversed because the first arg seems to be
- 	       the one that we imagine being modified
- 	       while the second is the one that might be affected.  */
- 	    || (! reg_overlap_mentioned_for_reload_p (rld[output_reload].out,
- 						      rld[i].in)
- 		/* However, if the input is a register that appears inside
- 		   the output, then we also can't share.
- 		   Imagine (set (mem (reg 69)) (plus (reg 69) ...)).
- 		   If the same reload reg is used for both reg 69 and the
- 		   result to be stored in memory, then that result
- 		   will clobber the address of the memory ref.  */
- 		&& ! (GET_CODE (rld[i].in) == REG
- 		      && reg_overlap_mentioned_for_reload_p (rld[i].in,
- 							     rld[output_reload].out))))
- 	&& (reg_class_size[(int) rld[i].class]
- 	    || SMALL_REGISTER_CLASSES)
- 	/* We will allow making things slightly worse by combining an
- 	   input and an output, but no worse than that.  */
- 	&& (rld[i].when_needed == RELOAD_FOR_INPUT
- 	    || rld[i].when_needed == RELOAD_FOR_OUTPUT))
-       {
- 	int j;
- 
- 	/* We have found a reload to combine with!  */
- 	rld[i].out = rld[output_reload].out;
- 	rld[i].out_reg = rld[output_reload].out_reg;
- 	rld[i].outmode = rld[output_reload].outmode;
- 	/* Mark the old output reload as inoperative.  */
- 	rld[output_reload].out = 0;
- 	/* The combined reload is needed for the entire insn.  */
- 	rld[i].when_needed = RELOAD_OTHER;
- 	/* If the output reload had a secondary reload, copy it.  */
- 	if (rld[output_reload].secondary_out_reload != -1)
- 	  {
- 	    rld[i].secondary_out_reload
- 	      = rld[output_reload].secondary_out_reload;
- 	    rld[i].secondary_out_icode
- 	      = rld[output_reload].secondary_out_icode;
- 	  }
- 
- #ifdef SECONDARY_MEMORY_NEEDED
- 	/* Copy any secondary MEM.  */
- 	if (secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum] != 0)
- 	  secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[i].opnum]
- 	    = secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum];
- #endif
- 	/* If required, minimize the register class.  */
- 	if (reg_class_subset_p (rld[output_reload].class,
- 				rld[i].class))
- 	  rld[i].class = rld[output_reload].class;
- 
- 	/* Transfer all replacements from the old reload to the combined.  */
- 	for (j = 0; j < n_replacements; j++)
- 	  if (replacements[j].what == output_reload)
- 	    replacements[j].what = i;
- 
- 	return;
-       }
- 
-   /* If this insn has only one operand that is modified or written (assumed
-      to be the first),  it must be the one corresponding to this reload.  It
-      is safe to use anything that dies in this insn for that output provided
-      that it does not occur in the output (we already know it isn't an
-      earlyclobber.  If this is an asm insn, give up.  */
- 
-   if (INSN_CODE (this_insn) == -1)
-     return;
- 
-   for (i = 1; i < insn_data[INSN_CODE (this_insn)].n_operands; i++)
-     if (insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '='
- 	|| insn_data[INSN_CODE (this_insn)].operand[i].constraint[0] == '+')
-       return;
- 
-   /* See if some hard register that dies in this insn and is not used in
-      the output is the right class.  Only works if the register we pick
-      up can fully hold our output reload.  */
-   for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
-     if (REG_NOTE_KIND (note) == REG_DEAD
- 	&& GET_CODE (XEXP (note, 0)) == REG
- 	&& ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0),
- 						 rld[output_reload].out)
- 	&& REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- 	&& HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
- 	&& TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].class],
- 			      REGNO (XEXP (note, 0)))
- 	&& (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
- 	    <= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0))))
- 	/* Ensure that a secondary or tertiary reload for this output
- 	   won't want this register.  */
- 	&& ((secondary_out = rld[output_reload].secondary_out_reload) == -1
- 	    || (! (TEST_HARD_REG_BIT
- 		   (reg_class_contents[(int) rld[secondary_out].class],
- 		    REGNO (XEXP (note, 0))))
- 		&& ((secondary_out = rld[secondary_out].secondary_out_reload) == -1
- 		    ||  ! (TEST_HARD_REG_BIT
- 			   (reg_class_contents[(int) rld[secondary_out].class],
- 			    REGNO (XEXP (note, 0)))))))
- 	&& ! fixed_regs[REGNO (XEXP (note, 0))])
-       {
- 	rld[output_reload].reg_rtx
- 	  = gen_rtx_REG (rld[output_reload].outmode,
- 			 REGNO (XEXP (note, 0)));
- 	return;
-       }
- }
- 
  /* Try to find a reload register for an in-out reload (expressions IN and OUT).
     See if one of IN and OUT is a register that may be used;
     this is desirable since a spill-register won't be needed.
--- 1642,1647 ----
*************** earlyclobber_operand_p (x)
*** 1939,1944 ****
--- 1822,1843 ----
    return 0;
  }
  
+ /* Return 1 if X overlaps an operand that is being earlyclobbered.  */
+ 
+ int
+ earlyclobber_overlap_p (x)
+      rtx x;
+ {               
+   int i;
+ 
+   for (i = 0; i < n_earlyclobbers; i++)
+     {
+       if (reg_overlap_mentioned_for_reload_p (x, reload_earlyclobbers[i]))
+ 	return 1;
+     }
+   return 0;
+ }
+ 
  /* Return 1 if expression X alters a hard reg in the range
     from BEG_REGNO (inclusive) to END_REGNO (exclusive),
     either explicitly or in the guise of a pseudo-reg allocated to REGNO.
*************** safe_from_earlyclobber (op, clobber)
*** 2330,2337 ****
    early_data = decompose (clobber);
    return immune_p (op, clobber, early_data);
  }
  
! /* Main entry point of this file: search the body of INSN
     for values that need reloading and record them with push_reload.
     REPLACE nonzero means record also where the values occur
     so that subst_reloads can be used.
--- 2229,2274 ----
    early_data = decompose (clobber);
    return immune_p (op, clobber, early_data);
  }
+ 
+ /* Called via for_each_rtx; We look for a hard register *(int*)REGNOP in a
+    piece of rtl *XP from an instruction that has just been recognized.
+    When a match is found, store its address in *(rtx **)regnop.  */
+ static int
+ mentioned_in_operand (xp, regnop)
+      rtx *xp;
+      void *regnop;
+ {
+   rtx x = *xp;
+ 
+   if (GET_CODE (x) == REG
+       || (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
+     {
+       int regno = * (int *) regnop;
+       if (refers_to_regno_p (regno, regno + 1, x, NULL_PTR))
+ 	{
+ 	  *(rtx**)regnop = xp;
+ 	  return 1;
+ 	}
+     }
+   return 0;
+ }
+ 
+ static void
+ note_earlyclobbers (x, setter, n_operand_earlyclobbers)
+      rtx x, setter;
+      void *n_operand_earlyclobbers;
+ {
+   int i;
+ 
+   if (GET_CODE (setter) != CLOBBER)
+     return;
+   for (i = *(int *) n_operand_earlyclobbers; i >= 0; i--)
+     if (reload_earlyclobbers[i] == x)
+       return;
+   reload_earlyclobbers[n_earlyclobbers++] = XEXP (setter, 0);
+ }
  
! /* Main entry point of this file: search the body of CHAIN->INSN
     for values that need reloading and record them with push_reload.
     REPLACE nonzero means record also where the values occur
     so that subst_reloads can be used.
*************** safe_from_earlyclobber (op, clobber)
*** 2354,2365 ****
     commutative operands, reg_equiv_address substitution, or whatever.  */
  
  int
! find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
!      rtx insn;
       int replace, ind_levels;
       int live_known;
       short *reload_reg_p;
  {
    register int insn_code_number;
    register int i, j;
    int noperands;
--- 2291,2303 ----
     commutative operands, reg_equiv_address substitution, or whatever.  */
  
  int
! find_reloads (chain, replace, ind_levels, live_known, reload_reg_p)
!      struct insn_chain *chain;
       int replace, ind_levels;
       int live_known;
       short *reload_reg_p;
  {
+   rtx insn = chain->insn;
    register int insn_code_number;
    register int i, j;
    int noperands;
*************** find_reloads (insn, replace, ind_levels,
*** 2398,2404 ****
    int goal_alternative_swapped;
    int best;
    int commutative;
-   int changed;
    char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
    rtx substed_operand[MAX_RECOG_OPERANDS];
    rtx body = PATTERN (insn);
--- 2336,2341 ----
*************** find_reloads (insn, replace, ind_levels,
*** 2406,2411 ****
--- 2343,2350 ----
    int goal_earlyclobber, this_earlyclobber;
    enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
    int retval = 0;
+   int n_operand_earlyclobbers;
+   HARD_REG_SET live_throughout;
  
    this_insn = insn;
    n_reloads = 0;
*************** find_reloads (insn, replace, ind_levels,
*** 2415,2420 ****
--- 2354,2371 ----
    hard_regs_live_known = live_known;
    static_reload_reg_p = reload_reg_p;
  
+   /* Registers that die or are set in
+      this insn are 'free' spill regs.  */
+   REG_SET_TO_HARD_REG_SET (chain->used_spill_regs, chain->dead_or_set);
+   compute_use_by_pseudos (&chain->used_spill_regs, chain->dead_or_set);
+ 
+   /* However, since global can now allocate multiple pseudos to one
+      hard reg at a time (when all but one pseudo is uninitialized),
+   we must exclude any hard regs that are live due to another pseudo.  */
+   REG_SET_TO_HARD_REG_SET (live_throughout, chain->live_throughout);
+   compute_use_by_pseudos (&live_throughout, chain->live_throughout);
+   AND_COMPL_HARD_REG_SET(chain->used_spill_regs, live_throughout);
+ 
    /* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads;
       neither are insns that SET cc0.  Insns that use CC0 are not allowed
       to have any input reloads.  */
*************** find_reloads (insn, replace, ind_levels,
*** 2573,2579 ****
  		  || GET_CODE (recog_data.operand[i]) == PLUS))
  	    {
  	      INSN_CODE (insn) = -1;
! 	      retval = find_reloads (insn, replace, ind_levels, live_known,
  				     reload_reg_p);
  	      return retval;
  	    }
--- 2524,2530 ----
  		  || GET_CODE (recog_data.operand[i]) == PLUS))
  	    {
  	      INSN_CODE (insn) = -1;
! 	      retval = find_reloads (chain, replace, ind_levels, live_known,
  				     reload_reg_p);
  	      return retval;
  	    }
*************** find_reloads (insn, replace, ind_levels,
*** 3559,3564 ****
--- 3510,3517 ----
      for (i = 0; i < noperands; i++)
        if (goal_alternative_earlyclobber[i])
  	reload_earlyclobbers[n_earlyclobbers++] = recog_data.operand[i];
+   n_operand_earlyclobbers = n_earlyclobbers;
+   note_stores (PATTERN (insn), note_earlyclobbers, &n_operand_earlyclobbers);
  
    /* Now record reloads for all the operands that need them.  */
    for (i = 0; i < noperands; i++)
*************** find_reloads (insn, replace, ind_levels,
*** 3845,3854 ****
        }
  #endif
  
!   /* Perhaps an output reload can be combined with another
!      to reduce needs by one.  */
!   if (!goal_earlyclobber)
!     combine_reloads ();
  
    /* If we have a pair of reloads for parts of an address, they are reloading
       the same object, the operands themselves were not reloaded, and they
--- 3798,3929 ----
        }
  #endif
  
!   /* If a hard register dies or is born in the insn, record dummy reloads
!      for it.  Some insn have hard register inputs or outputs and these
!      should be noted as RELOAD_FOR_INPUT / RELOAD_FOR_OUTPUT, respectively,
!      to avoid artificial spill register shortage.
!      We don't have to register these uses if there are no reloads otherwise.
!      If the use is outside the operands, we generate a RELOAD_OTHER - to make
!      an insn use more fine-tuned reloads, you have to use a match_operand.  */
!     
!   if (n_reloads)
!     {
!       int next_reg;
!       int n_ordinary_reloads = n_reloads;
!       if (GET_CODE (insn) == CALL_INSN)
! 	{
! 	  rtx link;
! 
! 	  for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
! 	       link = XEXP (link, 1))
! 	    {
! 	      rtx op = XEXP (link, 0);
! 	      rtx reg;
! 	      int in_p, regno, endregno;
! 
! 	      if (GET_CODE (op) != USE && GET_CODE (op) != CLOBBER)
! 		continue;
! 	      reg = XEXP (op, 0);
! 	      if (GET_CODE (reg) != REG)
! 		continue;
! 
! 	      in_p = GET_CODE (op) == USE;
! 	      regno = REGNO (reg);
! 	      endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
! 
! 	      for (i = regno; i < endregno; i = next_reg)
! 		{
! 		  next_reg = i + 1;
! 		  if (! TEST_HARD_REG_BIT (chain->used_spill_regs, i))
! 		    continue;
! 		  next_reg = i + HARD_REGNO_NREGS (i, reg_raw_mode[i]);
! 		  goal_alternative_matches[noperands] = -1;
! 		  reload_n_operands = noperands + 1;
! 		  push_hard_reload (in_p, i, noperands,
! 				    (in_p
! 				     ? RELOAD_FOR_INPUT : RELOAD_FOR_OUTPUT));
! 		}
! 	    }
! 	}
! 
!       for (i = 0; i < FIRST_PSEUDO_REGISTER; i = next_reg)
! 	{
! 	  union { int i; rtx *p; } u;
! 
! 	  next_reg = i + 1;
! 
! 	  if (! TEST_HARD_REG_BIT (chain->used_spill_regs, i))
! 	    continue;
! 
! 	  next_reg = i + HARD_REGNO_NREGS (i, reg_raw_mode[i]);
! 
! 	  u.i = i;
! 
! 	  for (j = 0; j < noperands; j++)
! 	    {
! 	      rtx op = recog_data.operand[j];
! 	      enum reload_type type;
! 	      int in_p, out_p;
! 
! 	      u.i = i;
! 	      if (! for_each_rtx (recog_data.operand_loc[j],
! 				  mentioned_in_operand, &u))
! 		continue;
! 
! 	      out_p = recog_data.operand_loc[j] == u.p;
! 
! 	      while (GET_CODE (op) == SUBREG
! 		     || GET_CODE (op) == SIGN_EXTRACT
! 		     || GET_CODE (op) == ZERO_EXTRACT
! 		     || GET_CODE (op) == STRICT_LOW_PART)
! 		{
! 		  out_p |= &XEXP (op, 0) == u.p;
! 		  op = XEXP (op, 0);
! 		}
! 
! 	      out_p &= modified[j] != RELOAD_READ;
! 	      in_p = ! out_p || modified[j] != RELOAD_WRITE;
! 
! 	      if (GET_CODE (op) == REG && constraints[j][0] != 'p')
! 		{
! 		  int k;
! 
! 		  type = operand_type[j];
! 		  /* Check if this hard reg is already reloaded by an ordinary
! 		     reload.  We can't use the replacements array here because
! 		     that doesn't work when REPLACE is zero.  */
! 		  for (k = n_ordinary_reloads - 1; k >= 0; k--)
! 		    {
! 		      if (rld[k].opnum == j && ! rld[k].secondary_p
! 			  && ((in_p
! 			       && (rld[k].in == *u.p
! 				   || loc_mentioned_in_p (u.p, rld[k].in)))
! 			      || (out_p
! 				  && (rld[k].out == *u.p
! 				      || loc_mentioned_in_p (u.p,
! 							     rld[k].out)))))
! 			{
! 			  /* This is like a secondary reload.  */
! 			  type = address_type[j];
! 			  if (type == RELOAD_OTHER)
! 			    type = (in_p
! 				    ? RELOAD_FOR_INPUT_ADDRESS
! 				    : RELOAD_FOR_OUTPUT_ADDRESS);
! 			  break;
! 			}
! 		    }
! 		}
! 	      else
! 		type = address_type[j];
! 	      push_hard_reload (in_p, i, j, type);
! 	      if (in_p && out_p)
! 		push_hard_reload (0, i, j,
! 				  (type == RELOAD_FOR_INPUT_ADDRESS
! 				   ? RELOAD_FOR_OUTPUT_ADDRESS
! 				   : type));
! 	    }
! 	}
!     }
  
    /* If we have a pair of reloads for parts of an address, they are reloading
       the same object, the operands themselves were not reloaded, and they
diff -p allocpatch/reload.h ./reload.h
*** allocpatch/reload.h	Tue Nov 23 21:29:52 1999
--- ./reload.h	Mon Nov 29 18:57:26 1999
*************** Boston, MA 02111-1307, USA.  */
*** 29,34 ****
--- 29,36 ----
    SECONDARY_RELOAD_CLASS (CLASS, MODE, X)
  #endif
  
+ struct insn_chain;
+ 
  /* If either macro is defined, show that we need secondary reloads.  */
  #if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
  #define HAVE_SECONDARY_RELOADS
*************** extern rtx *reg_equiv_memory_loc;
*** 168,178 ****
  extern rtx *reg_equiv_address;
  extern rtx *reg_equiv_mem;
  
- /* All the "earlyclobber" operands of the current insn
-    are recorded here.  */
- extern int n_earlyclobbers;
- extern rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
- 
  /* Save the number of operands.  */
  extern int reload_n_operands;
  
--- 170,175 ----
*************** struct insn_chain 
*** 224,240 ****
    /* The rtx of the insn.  */
    rtx insn;
    /* Register life information: record all live hard registers, and all
!      live pseudos that have a hard register.
!      This information is recorded for the point immediately before the insn
!      (in live_before), and for the point within the insn at which all
!      outputs have just been written to (in live_after).  */
!   regset live_before;
!   regset live_after;
  
    /* Copies of the global variables computed by find_reloads.  */
    struct reload *rld;
    int n_reloads;
- 
    /* Indicates which registers have already been used for spills.  */
    HARD_REG_SET used_spill_regs;
  
--- 221,233 ----
    /* The rtx of the insn.  */
    rtx insn;
    /* Register life information: record all live hard registers, and all
!      live pseudos that have a hard register.  */
!   regset live_throughout;
!   regset dead_or_set;
  
    /* Copies of the global variables computed by find_reloads.  */
    struct reload *rld;
    int n_reloads;
    /* Indicates which registers have already been used for spills.  */
    HARD_REG_SET used_spill_regs;
  
*************** extern int safe_from_earlyclobber PROTO(
*** 294,300 ****
  /* Search the body of INSN for values that need reloading and record them
     with push_reload.  REPLACE nonzero means record also where the values occur
     so that subst_reloads can be used.  */
! extern int find_reloads PROTO((rtx, int, int, int, short *));
  
  /* Compute the sum of X and Y, making canonicalizations assumed in an
     address, namely: sum constant integers, surround the sum of two
--- 287,293 ----
  /* Search the body of INSN for values that need reloading and record them
     with push_reload.  REPLACE nonzero means record also where the values occur
     so that subst_reloads can be used.  */
! extern int find_reloads PROTO((struct insn_chain *, int, int, int, short *));
  
  /* Compute the sum of X and Y, making canonicalizations assumed in an
     address, namely: sum constant integers, surround the sum of two
*************** extern int regno_clobbered_p PROTO((int,
*** 340,345 ****
--- 333,342 ----
  
  /* Return 1 if X is an operand of an insn that is being earlyclobbered.  */
  int earlyclobber_operand_p PROTO((rtx));
+ 
+ /* Return 1 if X overlaps an operand that is being earlyclobbered.  */
+ 
+ int earlyclobber_overlap_p PROTO((rtx));
  
  /* Functions in reload1.c:  */
  
diff -p allocpatch/reload1.c ./reload1.c
*** allocpatch/reload1.c	Mon Nov 29 17:25:29 1999
--- ./reload1.c	Mon Nov 29 21:55:03 1999
*************** static rtx reg_reloaded_insn[FIRST_PSEUD
*** 140,148 ****
  
  /* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
  static HARD_REG_SET reg_reloaded_valid;
- /* Indicate if the register was dead at the end of the reload.
-    This is only valid if reg_reloaded_contents is set and valid.  */
- static HARD_REG_SET reg_reloaded_dead;
  
  /* Number of spill-regs so far; number of valid elements of spill_regs.  */
  static int n_spills;
--- 140,145 ----
*************** static short spill_reg_order[FIRST_PSEUD
*** 173,180 ****
  
  /* This reg set indicates registers that can't be used as spill registers for
     the currently processed insn.  These are the hard registers which are live
!    during the insn, but not allocated to pseudos, as well as fixed
!    registers.  */
  static HARD_REG_SET bad_spill_regs;
  
  /* These are the hard registers that can't be used as spill register for any
--- 170,177 ----
  
  /* This reg set indicates registers that can't be used as spill registers for
     the currently processed insn.  These are the hard registers which are live
!    during the insn, but not allocated to pseudos, dying, or set, as well as
!    fixed registers.  */
  static HARD_REG_SET bad_spill_regs;
  
  /* These are the hard registers that can't be used as spill register for any
*************** static int spill_stack_slot_width[FIRST_
*** 240,249 ****
  /* Record which pseudos needed to be spilled.  */
  static regset_head spilled_pseudos;
  
- /* Used for communication between order_regs_for_reload and count_pseudo.
-    Used to avoid counting one pseudo twice.  */
- static regset_head pseudos_counted;
- 
  /* First uid used by insns created by reload in this function.
     Used in find_equiv_reg.  */
  int reload_first_uid;
--- 237,242 ----
*************** static void find_reload_regs		PROTO((str
*** 375,380 ****
--- 368,374 ----
  static void select_reload_regs		PROTO((FILE *));
  static void delete_caller_save_insns	PROTO((void));
  
+ static int spill_pseudo			PROTO((regset, enum reg_class));
  static void spill_failure		PROTO((rtx));
  static void count_spilled_pseudo	PROTO((int, int, int));
  static void delete_dead_insn		PROTO((rtx));
*************** static int reload_reg_free_p		PROTO((int
*** 408,413 ****
--- 402,408 ----
  static int reload_reg_free_for_value_p	PROTO((int, int, enum reload_type,
  					       rtx, rtx, int, int));
  static int reload_reg_reaches_end_p	PROTO((int, int, enum reload_type));
+ static int hard_reload_conflict		PROTO((int, int));
  static int allocate_reload_reg		PROTO((struct insn_chain *, int, int));
  static void failed_reload		PROTO((rtx, int));
  static int set_reload_reg		PROTO((int, int));
*************** static rtx gen_mode_int			PROTO((enum ma
*** 444,449 ****
--- 439,445 ----
  static void failed_reload		PROTO((rtx, int));
  static int set_reload_reg		PROTO((int, int));
  extern void dump_needs			PROTO((struct insn_chain *, FILE *));
+ static int mark_regs_outside_operands	PROTO((rtx *, void *));
  
  /* Initialize the reload pass once per compilation.  */
  
*************** init_reload ()
*** 498,504 ****
    reload_startobj = (char *) obstack_alloc (&reload_obstack, 0);
  
    INIT_REG_SET (&spilled_pseudos);
-   INIT_REG_SET (&pseudos_counted);
  }
  
  /* List of insn chains that are currently unused.  */
--- 494,499 ----
*************** new_insn_chain ()
*** 514,521 ****
      {
        c = (struct insn_chain *)
  	obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
!       c->live_before = OBSTACK_ALLOC_REG_SET (&reload_obstack);
!       c->live_after = OBSTACK_ALLOC_REG_SET (&reload_obstack);
      }
    else
      {
--- 509,516 ----
      {
        c = (struct insn_chain *)
  	obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
!       c->live_throughout = OBSTACK_ALLOC_REG_SET (&reload_obstack);
!       c->dead_or_set = OBSTACK_ALLOC_REG_SET (&reload_obstack);
      }
    else
      {
*************** compute_use_by_pseudos (to, from)
*** 559,564 ****
--- 554,601 ----
  	 }
       });
  }
+ 
+ /* Called via for_each_rtx; We look for a registers in a
+    piece of rtl *XP from an instruction that has just been recognized.
+    *XP is not inside an operand (but it may be one).  Do not look at
+    operands of the recognized insn.
+    LIVE_THROUGHOUT is actually a regset.
+    Include all register numbers found in LIVE_THROUGHOUT.  */
+ 
+ static int
+ mark_regs_outside_operands (xp, live_throughout)
+      rtx *xp;
+      void *live_throughout;
+ {
+   int i;
+   rtx x, reg;
+ 
+   for (i = recog_data.n_operands - 1; i >= 0; i--)
+     {
+       if (xp == recog_data.operand_loc[i])
+       return -1;
+     }
+   x = *xp;
+   reg = x;
+   if (GET_CODE (x) == SUBREG)
+     reg = SUBREG_REG (x);
+   if (GET_CODE (reg) == REG)
+     {
+       int regno = REGNO (reg);
+ 
+       if (regno < FIRST_PSEUDO_REGISTER)
+ 	{
+ 	  int nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ 
+ 	  do
+ 	    SET_REGNO_REG_SET ((regset) live_throughout, regno++);
+ 	  while (--nregs);
+ 	}
+       else if (reg_renumber[regno] >= 0)
+ 	SET_REGNO_REG_SET ((regset) live_throughout, regno);
+     }
+   return 0;
+ }
  
  /* Global variables used by reload and its subroutines.  */
  
*************** reload (first, global, dumpfile)
*** 597,602 ****
--- 634,641 ----
    register int i;
    register rtx insn;
    register struct elim_table *ep;
+   struct insn_chain *chain;
+ 
  
    /* The two pointers used to track the true location of the memory used
       for label offsets.  */
*************** reload (first, global, dumpfile)
*** 764,769 ****
--- 803,821 ----
  	scan_paradoxical_subregs (PATTERN (insn));
      }
  
+   /* Note which register operands are life throughout each insn.  */
+   for (chain = reload_insn_chain; chain; chain = chain->next)
+     {
+       if (GET_RTX_CLASS (GET_CODE (chain->insn)) == 'i')
+ 	{
+ 	  int i;
+ 
+ 	  extract_insn (chain->insn);
+ 	  for_each_rtx (&PATTERN (chain->insn), mark_regs_outside_operands,
+ 			chain->live_throughout);
+ 	}
+     }
+ 
    init_elim_table ();
  
    num_labels = max_label_num () - get_first_label_num ();
*************** maybe_fix_stack_asms ()
*** 1299,1306 ****
        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	if (TEST_HARD_REG_BIT (allowed, i))
  	  {
! 	    CLEAR_REGNO_REG_SET (chain->live_before, i);
! 	    CLEAR_REGNO_REG_SET (chain->live_after, i);
  	  }
      }
  
--- 1351,1357 ----
        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	if (TEST_HARD_REG_BIT (allowed, i))
  	  {
! 	    CLEAR_REGNO_REG_SET (chain->live_throughout, i);
  	  }
      }
  
*************** calculate_needs_all_insns (global)
*** 1372,1378 ****
  	    did_elimination = eliminate_regs_in_insn (insn, 0);
  
  	  /* Analyze the instruction.  */
! 	  operands_changed = find_reloads (insn, 0, spill_indirect_levels,
  					   global, spill_reg_order);
  
  	  /* If a no-op set needs more than one reload, this is likely
--- 1423,1429 ----
  	    did_elimination = eliminate_regs_in_insn (insn, 0);
  
  	  /* Analyze the instruction.  */
! 	  operands_changed = find_reloads (chain, 0, spill_indirect_levels,
  					   global, spill_reg_order);
  
  	  /* If a no-op set needs more than one reload, this is likely
*************** calculate_needs_all_insns (global)
*** 1428,1433 ****
--- 1479,1537 ----
    *pprev_reload = 0;
  }
  
+ /* Try to find pseudo in DEAD_OR_SET that contains has a hard register in
+    CLASS allocated it.  If successful, add it to spilled_pseudos, and
+    return 1.  */
+ static int
+ spill_pseudo (dead_or_set, class)
+      regset dead_or_set;
+      enum reg_class class;
+ {
+   int pseudo;
+   int best_reg = -1;
+   unsigned long best_cost = ~0L;
+ 
+   /* We kick out the least-used pseudo that contains a hard
+      register of the desired class.  We don't strive to kick
+      out all pseudos that live on that hard register, since
+      just kicking out one pseudo might already satisfy our
+      requirements.  */
+   /* ??? We could refine this further by only kicking out pseudos
+      that are actually live during lifetime of the requested
+      reload; i.e. for a RELOAD_FOR_INPUT we'd want to kick out a
+      pseudo that dies, but for a RELOAD_FOR_OUTPUT we'd want to
+      kick out a pseudo that is set.  But for that we'd have to
+      record separately which pseudos are set and which die.
+      For now, we assume it's not worth the hassle.  */
+   EXECUTE_IF_SET_IN_REG_SET
+     (dead_or_set, FIRST_PSEUDO_REGISTER, pseudo,
+      {
+        int r = reg_renumber[pseudo];
+        int n = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (pseudo));
+        unsigned long cost = REG_N_REFS (pseudo) * n;
+ 
+        if (cost < best_cost)
+ 	 {
+ 	   do
+ 	     n--;
+ 	   while (n >= 0
+ 		  && ! TEST_HARD_REG_BIT (reg_class_contents[class],
+ 					  n+r));
+ 	   if (n >= 0)
+ 	     {
+ 	       best_cost = cost;
+ 	       best_reg = pseudo;
+ 	     }
+ 	 }
+      });
+   if (best_reg >= 0)
+     {
+       SET_REGNO_REG_SET (&spilled_pseudos, best_reg);
+       return 1;
+     }
+   return 0;
+ }
+ 
  /* Comparison function for qsort to decide which of two reloads
     should be handled first.  *P1 and *P2 are the reload numbers.  */
  
*************** count_pseudo (reg)
*** 1482,1493 ****
    int r = reg_renumber[reg];
    int nregs;
  
!   if (REGNO_REG_SET_P (&pseudos_counted, reg)
!       || REGNO_REG_SET_P (&spilled_pseudos, reg))
      return;
  
-   SET_REGNO_REG_SET (&pseudos_counted, reg);
- 
    if (r < 0)
      abort ();
    
--- 1586,1594 ----
    int r = reg_renumber[reg];
    int nregs;
  
!   if (REGNO_REG_SET_P (&spilled_pseudos, reg))
      return;
  
    if (r < 0)
      abort ();
    
*************** order_regs_for_reload (chain)
*** 1519,1543 ****
        /* Test the various reasons why we can't use a register for
  	 spilling in this insn.  */
        if (fixed_regs[i]
! 	  || REGNO_REG_SET_P (chain->live_before, i)
! 	  || REGNO_REG_SET_P (chain->live_after, i))
  	SET_HARD_REG_BIT (bad_spill_regs, i);
      }
    /* Now find out which pseudos are allocated to it, and update
       hard_reg_n_uses.  */
-   CLEAR_REG_SET (&pseudos_counted);
  
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->live_before, FIRST_PSEUDO_REGISTER, j,
       {
         count_pseudo (j);
       });
-   EXECUTE_IF_SET_IN_REG_SET
-     (chain->live_after, FIRST_PSEUDO_REGISTER, j,
-      {
-        count_pseudo (j);
-      });
-   CLEAR_REG_SET (&pseudos_counted);
  }
  
  /* Vector of reload-numbers showing the order in which the reloads should
--- 1620,1636 ----
        /* Test the various reasons why we can't use a register for
  	 spilling in this insn.  */
        if (fixed_regs[i]
! 	  || REGNO_REG_SET_P (chain->live_throughout, i))
  	SET_HARD_REG_BIT (bad_spill_regs, i);
      }
    /* Now find out which pseudos are allocated to it, and update
       hard_reg_n_uses.  */
  
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
       {
         count_pseudo (j);
       });
  }
  
  /* Vector of reload-numbers showing the order in which the reloads should
*************** find_reg (chain, order, dumpfile)
*** 1590,1601 ****
    IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]);
  
    CLEAR_HARD_REG_SET (used_by_other_reload);
!   for (i = 0; i < order; i++)
      {
!       int other = reload_order[i];
!       if (rld[other].regno >= 0 && reloads_conflict (other, rnum))
! 	for (j = 0; j < rld[other].nregs; j++)
! 	  SET_HARD_REG_BIT (used_by_other_reload, rld[other].regno + j);
      }
  
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
--- 1683,1695 ----
    IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]);
  
    CLEAR_HARD_REG_SET (used_by_other_reload);
!   for (i = n_reloads - 1; i >= 0; i--)
      {
!       if (rld[i].regno >= 0
! 	  && (reloads_conflict (i, rnum)
! 	      || hard_reload_conflict (i, rnum)))
! 	for (j = 0; j < rld[i].nregs; j++)
! 	  SET_HARD_REG_BIT (used_by_other_reload, rld[i].regno + j);
      }
  
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
*************** find_reg (chain, order, dumpfile)
*** 1642,1653 ****
    rl->regno = best_reg;
  
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->live_before, FIRST_PSEUDO_REGISTER, j,
!      {
!        count_spilled_pseudo (best_reg, rl->nregs, j);
!      });
!   EXECUTE_IF_SET_IN_REG_SET
!     (chain->live_after, FIRST_PSEUDO_REGISTER, j,
       {
         count_spilled_pseudo (best_reg, rl->nregs, j);
       });
--- 1736,1742 ----
    rl->regno = best_reg;
  
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
       {
         count_spilled_pseudo (best_reg, rl->nregs, j);
       });
*************** find_reload_regs (chain, dumpfile)
*** 1717,1729 ****
  	  && rld[r].regno == -1)
  	if (! find_reg (chain, i, dumpfile))
  	  {
  	    spill_failure (chain->insn);
  	    failure = 1;
  	    return;
  	  }
      }
  
!   COPY_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local);
    IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local);
  
    memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
--- 1806,1828 ----
  	  && rld[r].regno == -1)
  	if (! find_reg (chain, i, dumpfile))
  	  {
+ 	    /* Sometimes a pseudo that dies or is set in the insn is allocated
+ 	       to (a group of hard regsiters containing) a hard register in a
+ 	       class that we urgently need - typically a one-register class.
+ 	       If we can find a pseudo we can kick out, do so, and
+ 	       stop further register allocation; we don't know how many
+ 	       hard registers and for what timespan(s) we have freed up.
+ 	       The next reload iteration will find out the new reload
+ 	       requirements.  */
+ 	    if (spill_pseudo (chain->dead_or_set, rld[r].class))
+ 	      break;
  	    spill_failure (chain->insn);
  	    failure = 1;
  	    return;
  	  }
      }
  
!   IOR_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local);
    IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local);
  
    memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
*************** finish_spills (global, dumpfile)
*** 3486,3498 ****
        for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
  	{
  	  EXECUTE_IF_SET_IN_REG_SET
! 	    (chain->live_before, FIRST_PSEUDO_REGISTER, i,
! 	     {
! 	       ior_hard_reg_set (pseudo_forbidden_regs + i,
! 				 &chain->used_spill_regs);
! 	     });
! 	  EXECUTE_IF_SET_IN_REG_SET
! 	    (chain->live_after, FIRST_PSEUDO_REGISTER, i,
  	     {
  	       ior_hard_reg_set (pseudo_forbidden_regs + i,
  				 &chain->used_spill_regs);
--- 3585,3591 ----
        for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
  	{
  	  EXECUTE_IF_SET_IN_REG_SET
! 	    (chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
  	     {
  	       ior_hard_reg_set (pseudo_forbidden_regs + i,
  				 &chain->used_spill_regs);
*************** finish_spills (global, dumpfile)
*** 3502,3508 ****
        /* Retry allocating the spilled pseudos.  For each reg, merge the
  	 various reg sets that indicate which hard regs can't be used,
  	 and call retry_global_alloc.
! 	 We change spill_pseudos here to only contain pseudos that did not
  	 get a new hard register.  */
        for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
  	if (reg_old_renumber[i] != reg_renumber[i])
--- 3595,3601 ----
        /* Retry allocating the spilled pseudos.  For each reg, merge the
  	 various reg sets that indicate which hard regs can't be used,
  	 and call retry_global_alloc.
! 	 We change spilled_pseudos here to only contain pseudos that did not
  	 get a new hard register.  */
        for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
  	if (reg_old_renumber[i] != reg_renumber[i])
*************** finish_spills (global, dumpfile)
*** 3519,3554 ****
  
    /* Fix up the register information in the insn chain.
       This involves deleting those of the spilled pseudos which did not get
!      a new hard register home from the live_{before,after} sets.  */
    for (chain = reload_insn_chain; chain; chain = chain->next)
      {
!       HARD_REG_SET used_by_pseudos;
!       HARD_REG_SET used_by_pseudos2;
! 
!       AND_COMPL_REG_SET (chain->live_before, &spilled_pseudos);
!       AND_COMPL_REG_SET (chain->live_after, &spilled_pseudos);
! 
!       /* Mark any unallocated hard regs as available for spills.  That
! 	 makes inheritance work somewhat better.  */
!       if (chain->need_reload)
! 	{
! 	  REG_SET_TO_HARD_REG_SET (used_by_pseudos, chain->live_before);
! 	  REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->live_after);
! 	  IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
! 
! 	  /* Save the old value for the sanity test below.  */
! 	  COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
! 
! 	  compute_use_by_pseudos (&used_by_pseudos, chain->live_before);
! 	  compute_use_by_pseudos (&used_by_pseudos, chain->live_after);
! 	  COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
! 	  AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
! 
! 	  /* Make sure we only enlarge the set.  */
! 	  GO_IF_HARD_REG_SUBSET (used_by_pseudos2, chain->used_spill_regs, ok);
! 	  abort ();
! 	ok:;
! 	}
      }
  
    /* Let alter_reg modify the reg rtx's for the modified pseudos.  */
--- 3612,3623 ----
  
    /* Fix up the register information in the insn chain.
       This involves deleting those of the spilled pseudos which did not get
!      a new hard register home from the live_throughout / pseudo_dead_or_set
!      sets.  */
    for (chain = reload_insn_chain; chain; chain = chain->next)
      {
!       AND_COMPL_REG_SET (chain->live_throughout, &spilled_pseudos);
!       AND_COMPL_REG_SET (chain->dead_or_set, &spilled_pseudos);
      }
  
    /* Let alter_reg modify the reg rtx's for the modified pseudos.  */
*************** reload_as_needed (live_known)
*** 3716,3722 ****
  	      bzero (reg_has_output_reload, max_regno);
  	      CLEAR_HARD_REG_SET (reg_is_output_reload);
  
! 	      find_reloads (insn, 1, spill_indirect_levels, live_known,
  			    spill_reg_order);
  	    }
  
--- 3785,3791 ----
  	      bzero (reg_has_output_reload, max_regno);
  	      CLEAR_HARD_REG_SET (reg_is_output_reload);
  
! 	      find_reloads (chain, 1, spill_indirect_levels, live_known,
  			    spill_reg_order);
  	    }
  
*************** static HARD_REG_SET reload_reg_used_at_a
*** 4013,4020 ****
     in the group.  */
  static HARD_REG_SET reload_reg_used_for_inherit;
  
! /* Records which hard regs are used in any way, either as explicit use or
!    by being allocated to a pseudo during any point of the current insn.  */
  static HARD_REG_SET reg_used_in_insn;
  
  /* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and
--- 4082,4090 ----
     in the group.  */
  static HARD_REG_SET reload_reg_used_for_inherit;
  
! /* Records which hard regs are used in any way not evident in the insn,
!    by being a live hard register or allocated to a pseudo throughout
!    the current insn.  */
  static HARD_REG_SET reg_used_in_insn;
  
  /* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and
*************** reload_reg_free_p (regno, opnum, type)
*** 4205,4210 ****
--- 4275,4284 ----
  {
    int i;
  
+   /* Is this a live hard reg or allocated to a pseudo?  */
+   if (TEST_HARD_REG_BIT (reg_used_in_insn, regno))
+     return 0;
+ 
    /* In use for a RELOAD_OTHER means it's not available for anything.  */
    if (TEST_HARD_REG_BIT (reload_reg_used, regno))
      return 0;
*************** reloads_conflict (r1, r2)
*** 4556,4561 ****
--- 4630,4688 ----
        abort ();
      }
  }
+ 
+ /* Return nonzero if reload OLD is a hard reload and therefore conflicts
+    with reload NEW.  return zero if there is no conflict.
+    If reloads_conflict will find a conflict, we don't care about the
+    return value of hard_reload_conflict.  */
+ static int
+ hard_reload_conflict (old, new)
+      int old, new;
+ {
+   if (rld[old].reg_rtx == rld[old].in)
+     {
+       enum reload_type old_type = rld[old].when_needed;
+ 
+       switch (rld[new].when_needed)
+ 	{
+ 	case RELOAD_FOR_OTHER_ADDRESS:
+ 	  return 1;
+ 	case RELOAD_FOR_INPADDR_ADDRESS:
+ 	case RELOAD_FOR_INPUT_ADDRESS:
+ 	  if (old_type == RELOAD_FOR_INPUT_ADDRESS
+ 	      && rld[old].opnum >= rld[new].opnum)
+ 	    return 1;
+ 	  /* Fall through.  */
+ 	case RELOAD_FOR_OPADDR_ADDR:
+ 	case RELOAD_FOR_OPERAND_ADDRESS:
+ 	  return (old_type == RELOAD_FOR_INPUT
+ 		  || old_type == RELOAD_FOR_OPERAND_ADDRESS);
+ 
+ 	case RELOAD_FOR_INPUT: case RELOAD_FOR_INSN: case RELOAD_OTHER:
+ 	case RELOAD_FOR_OUTPUT_ADDRESS: case RELOAD_FOR_OUTPUT:
+ 	case RELOAD_FOR_OUTADDR_ADDRESS:
+ 	  ;
+ 	}
+     }
+   if (rld[old].reg_rtx == rld[old].out)
+     {
+       switch (rld[new].when_needed)
+ 	{
+ 	case RELOAD_FOR_OUTPUT_ADDRESS:
+ 	case RELOAD_FOR_OUTADDR_ADDRESS:
+ 	  return (rld[old].when_needed == RELOAD_FOR_OUTPUT
+ 		  || (rld[old].when_needed == RELOAD_FOR_OUTPUT_ADDRESS
+ 		      && rld[old].opnum <= rld[new].opnum));
+ 
+ 	case RELOAD_FOR_OUTPUT: case RELOAD_FOR_INSN: case RELOAD_OTHER:
+ 	case RELOAD_FOR_OTHER_ADDRESS: case RELOAD_FOR_INPADDR_ADDRESS:
+ 	case RELOAD_FOR_INPUT_ADDRESS: case RELOAD_FOR_OPADDR_ADDR:
+ 	case RELOAD_FOR_OPERAND_ADDRESS: case RELOAD_FOR_INPUT: 
+ 	  ;
+ 	}
+     }
+   return 0;
+ }
  
  /* Indexed by reload number, 1 if incoming value
     inherited from previous insns.  */
*************** reload_reg_free_for_value_p (regno, opnu
*** 4610,4622 ****
    int i;
    int copy = 0;
  
-   /* ??? reload_reg_used is abused to hold the registers that are not
-      available as spill registers, including hard registers that are
-      earlyclobbered in asms.  As a temporary measure, reject anything
-      in reload_reg_used.  */
-   if (TEST_HARD_REG_BIT (reload_reg_used, regno))
-     return 0;
- 
    if (out == const0_rtx)
      {
        copy = 1;
--- 4737,4742 ----
*************** reload_reg_free_for_value_p (regno, opnu
*** 4776,4783 ****
  		  if (! rld[i].in || rtx_equal_p (rld[i].in, value))
  		    {
  		      time2 = MAX_RECOG_OPERANDS * 4 + 4;
! 		      /* Earlyclobbered outputs must conflict with inputs.  */
! 		      if (earlyclobber_operand_p (rld[i].out))
  			time2 = MAX_RECOG_OPERANDS * 4 + 3;
  			  
  		      break;
--- 4896,4905 ----
  		  if (! rld[i].in || rtx_equal_p (rld[i].in, value))
  		    {
  		      time2 = MAX_RECOG_OPERANDS * 4 + 4;
! 		      /* Earlyclobbered outputs must conflict with inputs.
! 			 If this is a hard reload, earlyclobber_operand_p
! 			 doesn't work, so use earlyclobber_overlap_p.  */
! 		      if (rld[i].out && earlyclobber_overlap_p (rld[i].out))
  			time2 = MAX_RECOG_OPERANDS * 4 + 3;
  			  
  		      break;
*************** reload_reg_free_for_value_p (regno, opnu
*** 4793,4799 ****
  		default:
  		  return 0;
  		}
! 	      if ((time1 >= time2
  		   && (! rld[i].in || rld[i].out
  		       || ! rtx_equal_p (rld[i].in, value)))
  		  || (out && rld[reloadnum].out_reg
--- 4915,4923 ----
  		default:
  		  return 0;
  		}
! 	      if (((time1 >= time2
! 		    /* Test for hard reloads */
! 		    || (rld[i].in && rld[i].in == rld[i].reg_rtx))
  		   && (! rld[i].in || rld[i].out
  		       || ! rtx_equal_p (rld[i].in, value)))
  		  || (out && rld[reloadnum].out_reg
*************** allocate_reload_reg (chain, r, last_relo
*** 4949,4957 ****
  	  if ((reload_reg_free_p (regnum, rld[r].opnum,
  				  rld[r].when_needed)
  	       || (rld[r].in
! 		   /* We check reload_reg_used to make sure we
! 		      don't clobber the return register.  */
! 		   && ! TEST_HARD_REG_BIT (reload_reg_used, regnum)
  		   && reload_reg_free_for_value_p (regnum,
  						   rld[r].opnum,
  						   rld[r].when_needed,
--- 5073,5083 ----
  	  if ((reload_reg_free_p (regnum, rld[r].opnum,
  				  rld[r].when_needed)
  	       || (rld[r].in
! 		   /* We check reg_used_in_insn to make sure we don't clobber
! 		      pseudos or hard regs live after the insn.
! 		      Registers that are set in the insn will be accounted
! 		      for with reloads.  */
! 		   && ! TEST_HARD_REG_BIT (reg_used_in_insn, regnum)
  		   && reload_reg_free_for_value_p (regnum,
  						   rld[r].opnum,
  						   rld[r].when_needed,
*************** choose_reload_regs_init (chain, save_rel
*** 5038,5053 ****
    CLEAR_HARD_REG_SET (reload_reg_used_in_insn);
    CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr);
  
!   CLEAR_HARD_REG_SET (reg_used_in_insn);
!   {
!     HARD_REG_SET tmp;
!     REG_SET_TO_HARD_REG_SET (tmp, chain->live_before);
!     IOR_HARD_REG_SET (reg_used_in_insn, tmp);
!     REG_SET_TO_HARD_REG_SET (tmp, chain->live_after);
!     IOR_HARD_REG_SET (reg_used_in_insn, tmp);
!     compute_use_by_pseudos (&reg_used_in_insn, chain->live_before);
!     compute_use_by_pseudos (&reg_used_in_insn, chain->live_after);
!   }
    for (i = 0; i < reload_n_operands; i++)
      {
        CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
--- 5164,5172 ----
    CLEAR_HARD_REG_SET (reload_reg_used_in_insn);
    CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr);
  
!   REG_SET_TO_HARD_REG_SET (reg_used_in_insn, chain->live_throughout);
!   compute_use_by_pseudos (&reg_used_in_insn, chain->live_throughout);
! 
    for (i = 0; i < reload_n_operands; i++)
      {
        CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
*************** choose_reload_regs_init (chain, save_rel
*** 5058,5073 ****
        CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
      }
  
-   IOR_COMPL_HARD_REG_SET (reload_reg_used, chain->used_spill_regs);
- 
    CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
  
    for (i = 0; i < n_reloads; i++)
      /* If we have already decided to use a certain register,
         don't use it in another way.  */
      if (rld[i].reg_rtx)
!       mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! 			      rld[i].when_needed, rld[i].mode);
  }
  
  /* Assign hard reg targets for the pseudo-registers we must reload
--- 5177,5234 ----
        CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
      }
  
    CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
  
    for (i = 0; i < n_reloads; i++)
      /* If we have already decided to use a certain register,
         don't use it in another way.  */
      if (rld[i].reg_rtx)
!       {
! 	mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! 				rld[i].when_needed, rld[i].mode);
! 	/* Hard reloads start out life before the first regular reload and/or
! 	   remain life till after the last regular reload.  */
! 	if (rld[i].reg_rtx == rld[i].in)
! 	  {
! 	    enum reload_type type;
! 
! 	    mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! 				    RELOAD_FOR_OTHER_ADDRESS, rld[i].mode);
! 	    type = rld[i].when_needed;
! 	    if (type == RELOAD_FOR_OPERAND_ADDRESS)
! 	      mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum,
! 				      RELOAD_FOR_INPUT, rld[i].mode);
! 	    if (type == RELOAD_FOR_INPUT_ADDRESS
! 		|| type == RELOAD_FOR_INPUT
! 		|| type == RELOAD_FOR_OPERAND_ADDRESS)
! 	      {
! 		int j;
! 
! 		for (j = rld[i].opnum; j >= 0; j--)
! 		  {
! 		    mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! 					    RELOAD_FOR_INPUT_ADDRESS,
! 					    rld[i].mode);
! 		    mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! 					    RELOAD_FOR_INPADDR_ADDRESS,
! 					    rld[i].mode);
! 		  }
! 	      }
! 	  }
! 	if (rld[i].reg_rtx == rld[i].out)
! 	  {
! 	    int j = rld[i].opnum;
! 
! 	    while (--j >= 0)
! 	      {
! 		mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! 					RELOAD_FOR_OUTPUT_ADDRESS, rld[i].mode);
! 		mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), j,
! 					RELOAD_FOR_OUTADDR_ADDRESS,
! 					rld[i].mode);
! 	      }
! 	  }
!       }
  }
  
  /* Assign hard reg targets for the pseudo-registers we must reload
*************** choose_reload_regs (chain)
*** 5294,5301 ****
  
  		      if (k == nr)
  			{
- 			  int i1;
- 
  			  last_reg = (GET_MODE (last_reg) == mode
  				      ? last_reg : gen_rtx_REG (mode, i));
  
--- 5455,5460 ----
*************** choose_reload_regs (chain)
*** 5306,5325 ****
  			     reload from since we can't use it as the
  			     reload register itself.  */
  
! 			  for (i1 = 0; i1 < n_earlyclobbers; i1++)
! 			    if (reg_overlap_mentioned_for_reload_p
! 				(reg_last_reload_reg[regno],
! 				 reload_earlyclobbers[i1]))
! 			      break;
! 
! 			  if (i1 != n_earlyclobbers
  			      || ! (reload_reg_free_for_value_p
  				    (i, rld[r].opnum, rld[r].when_needed,
  				     rld[r].in, rld[r].out, r, 1))
  			      /* Don't use it if we'd clobber a pseudo reg.  */
  			      || (TEST_HARD_REG_BIT (reg_used_in_insn, i)
! 				  && rld[r].out
! 				  && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i))
  			      /* Don't clobber the frame pointer.  */
  			      || (i == HARD_FRAME_POINTER_REGNUM && rld[r].out)
  			      /* Don't really use the inherited spill reg
--- 5465,5477 ----
  			     reload from since we can't use it as the
  			     reload register itself.  */
  
! 			  if (earlyclobber_overlap_p (last_reg)
  			      || ! (reload_reg_free_for_value_p
  				    (i, rld[r].opnum, rld[r].when_needed,
  				     rld[r].in, rld[r].out, r, 1))
  			      /* Don't use it if we'd clobber a pseudo reg.  */
  			      || (TEST_HARD_REG_BIT (reg_used_in_insn, i)
! 				  && rld[r].out)
  			      /* Don't clobber the frame pointer.  */
  			      || (i == HARD_FRAME_POINTER_REGNUM && rld[r].out)
  			      /* Don't really use the inherited spill reg
*************** choose_reload_regs (chain)
*** 5385,5390 ****
--- 5537,5545 ----
  		  && rtx_equal_p (rld[r].out, SET_DEST (set))
  		  && CONSTANT_P (SET_SRC (set)))
  		search_equiv = SET_SRC (set);
+ 		/* N.B. since this is a simple move insn, we don't actually
+ 		   change the register we use, hence we don't have to
+ 		   tell reload_reg_free_for_value_p about rld[r].out.  */
  	    }
  
  	  if (search_equiv)
*************** choose_reload_regs (chain)
*** 5417,5424 ****
  		  && ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
  		       && ! reload_reg_free_for_value_p (regno, rld[r].opnum,
  							 rld[r].when_needed,
! 							 rld[r].in,
! 							 rld[r].out, r, 1))
  		      || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
  					      regno)))
  		equiv = 0;
--- 5572,5579 ----
  		  && ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
  		       && ! reload_reg_free_for_value_p (regno, rld[r].opnum,
  							 rld[r].when_needed,
! 							 search_equiv,
! 							 NULL_RTX, r, 1))
  		      || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
  					      regno)))
  		equiv = 0;
*************** choose_reload_regs (chain)
*** 5427,5453 ****
  		equiv = 0;
  
  	      /* We found a register that contains the value we need.
! 		 If this register is the same as an `earlyclobber' operand
! 		 of the current insn, just mark it as a place to reload from
! 		 since we can't use it as the reload register itself.  */
! 
! 	      if (equiv != 0)
! 		for (i = 0; i < n_earlyclobbers; i++)
! 		  if (reg_overlap_mentioned_for_reload_p (equiv,
! 							  reload_earlyclobbers[i]))
! 		    {
! 		      reload_override_in[r] = equiv;
! 		      equiv = 0;
! 		      break;
! 		    }
! 
! 	      /* If the equiv register we have found is explicitly clobbered
! 		 in the current insn, it depends on the reload type if we
! 		 can use it, use it for reload_override_in, or not at all.
  		 In particular, we then can't use EQUIV for a
  		 RELOAD_FOR_OUTPUT_ADDRESS reload.  */
  
! 	      if (equiv != 0 && regno_clobbered_p (regno, insn))
  		{
  		  switch (rld[r].when_needed)
  		    {
--- 5582,5598 ----
  		equiv = 0;
  
  	      /* We found a register that contains the value we need.
! 		 If this register is the same as an `earlyclobber' operand,
! 		 or it is explicitly clobbered in the current insn, it depends
! 		 on the reload type if we can use it as the reload register
! 		 itself, use it only for reload_override_in (i.e as a place
! 		 to reload from), or not at all.
  		 In particular, we then can't use EQUIV for a
  		 RELOAD_FOR_OUTPUT_ADDRESS reload.  */
  
! 	      if (equiv != 0
! 		  && (earlyclobber_overlap_p (equiv)
! 		      || regno_clobbered_p (regno, insn)))
  		{
  		  switch (rld[r].when_needed)
  		    {
*************** choose_reload_regs (chain)
*** 5700,5706 ****
  
  	  if (rld[r].when_needed != RELOAD_OTHER
  	      && rld[r].when_needed != RELOAD_FOR_OUTPUT
! 	      && rld[r].when_needed != RELOAD_FOR_INSN)
  	    abort ();
  	}
      }
--- 5845,5853 ----
  
  	  if (rld[r].when_needed != RELOAD_OTHER
  	      && rld[r].when_needed != RELOAD_FOR_OUTPUT
! 	      && rld[r].when_needed != RELOAD_FOR_INSN
! 	      && (rld[r].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
! 		  || rld[r].out_reg != rld[r].reg_rtx))
  	    abort ();
  	}
      }
*************** emit_reload_insns (chain)
*** 5860,5868 ****
    int special;
    /* Values to be put in spill_reg_store are put here first.  */
    rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
-   HARD_REG_SET reg_reloaded_died;
- 
-   CLEAR_HARD_REG_SET (reg_reloaded_died);
  
    for (j = 0; j < reload_n_operands; j++)
      input_reload_insns[j] = input_address_reload_insns[j]
--- 6007,6012 ----
*************** emit_reload_insns (chain)
*** 6645,6652 ****
  
  			reload_spill_index[j] = src;
  			SET_HARD_REG_BIT (reg_is_output_reload, src);
- 			if (find_regno_note (insn, REG_DEAD, src))
- 			  SET_HARD_REG_BIT (reg_reloaded_died, src);
  		      }
  		    if (REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
  		      {
--- 6789,6794 ----
*************** emit_reload_insns (chain)
*** 6864,6870 ****
  		  /* Now do the inverse operation.  */
  		  for (k = 0; k < nr; k++)
  		    {
- 		      CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
  		      reg_reloaded_contents[i + k]
  			= (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
  			   ? nregno
--- 7006,7011 ----
*************** emit_reload_insns (chain)
*** 6921,6927 ****
  
  		  for (k = 0; k < nr; k++)
  		    {
- 		      CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
  		      reg_reloaded_contents[i + k]
  			= (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
  			   ? nregno
--- 7062,7067 ----
*************** emit_reload_insns (chain)
*** 7012,7024 ****
  		      spill_reg_stored_to[src_regno + nr] = out;
  		      reg_reloaded_contents[src_regno + nr] = nregno;
  		      reg_reloaded_insn[src_regno + nr] = store_insn;
- 		      CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + nr);
  		      SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr);
  		      SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
- 		      if (note)
- 			SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
- 		      else
- 			CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
  		    }
  		  reg_last_reload_reg[nregno] = src_reg;
  		}
--- 7152,7159 ----
*************** emit_reload_insns (chain)
*** 7032,7038 ****
  	    }
  	}
      }
-   IOR_HARD_REG_SET (reg_reloaded_dead, reg_reloaded_died);
  }
  
  /* Emit code to perform a reload from IN (which may be a reload register) to
--- 7167,7172 ----
diff -p allocpatch/stupid.c ./stupid.c
*** allocpatch/stupid.c	Tue Nov 23 22:45:42 1999
--- ./stupid.c	Mon Nov 29 22:39:17 1999
*************** static int stupid_reg_compare	PROTO((con
*** 128,170 ****
  static int stupid_find_reg	PROTO((int, enum reg_class, enum machine_mode,
  				       int, int, int));
  static void stupid_mark_refs	PROTO((rtx, struct insn_chain *));
! static void find_clobbered_regs	PROTO((rtx, rtx, void *));
! 
! /* For communication between stupid_life_analysis and find_clobbered_regs.  */
! static struct insn_chain *current_chain;
! 
! /* This function, called via note_stores, marks any hard registers that are
!    clobbered in an insn as being live in the live_after and live_before fields
!    of the appropriate insn_chain structure.  */
! 
! static void
! find_clobbered_regs (reg, setter, data)
!      rtx reg, setter;
!      void *data ATTRIBUTE_UNUSED;
! {
!   int regno, nregs;
!   if (setter == 0 || GET_CODE (setter) != CLOBBER)
!     return;
! 
!   if (GET_CODE (reg) == SUBREG)
!     reg = SUBREG_REG (reg);
! 
!   if (GET_CODE (reg) != REG)
!     return;
!   regno = REGNO (reg);
!   if (regno >= FIRST_PSEUDO_REGISTER)
!     return;
! 
!   if (GET_MODE (reg) == VOIDmode)
!     abort ();
!   else
!     nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
!   while (nregs-- > 0)
!     {
!       SET_REGNO_REG_SET (current_chain->live_after, regno);
!       SET_REGNO_REG_SET (current_chain->live_before, regno++);
!     }
! }
  
  /* Stupid life analysis is for the case where only variables declared
     `register' go in registers.  For this case, we mark all
--- 128,134 ----
  static int stupid_find_reg	PROTO((int, enum reg_class, enum machine_mode,
  				       int, int, int));
  static void stupid_mark_refs	PROTO((rtx, struct insn_chain *));
! static void mark_hard_ref	PROTO((rtx, int, struct insn_chain *));
  
  /* Stupid life analysis is for the case where only variables declared
     `register' go in registers.  For this case, we mark all
*************** stupid_life_analysis (f, nregs, file)
*** 285,291 ****
  	  chain->insn = insn;
  	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	    if (regs_live[i])
! 	      SET_REGNO_REG_SET (chain->live_before, i);
  	}
  
        /* Update which hard regs are currently live
--- 249,255 ----
  	  chain->insn = insn;
  	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	    if (regs_live[i])
! 	      SET_REGNO_REG_SET (chain->live_throughout, i);
  	}
  
        /* Update which hard regs are currently live
*************** stupid_life_analysis (f, nregs, file)
*** 334,353 ****
  	  stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), chain);
  	}
  
-       if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER)
- 	{	  
- 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- 	    if (regs_live[i])
- 	      SET_REGNO_REG_SET (chain->live_after, i);
- 
- 	  /* The regs_live array doesn't say anything about hard registers
- 	     clobbered by this insn.  So we need an extra pass over the
- 	     pattern.  */
- 	  current_chain = chain;
- 	  if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
- 	    note_stores (PATTERN (insn), find_clobbered_regs, NULL);
- 	}
- 
        if (GET_CODE (insn) == JUMP_INSN && computed_jump_p (insn))
  	current_function_has_computed_jump = 1;
      }
--- 298,303 ----
*************** stupid_life_analysis (f, nregs, file)
*** 407,427 ****
  	continue;
  
        chain = reg_where_dead_chain[i];
!       if (reg_where_dead[i] > INSN_SUID (chain->insn))
! 	SET_REGNO_REG_SET (chain->live_after, i);
  
!       while (INSN_SUID (chain->insn) > reg_where_born_exact[i])
! 	{
! 	  SET_REGNO_REG_SET (chain->live_before, i);
! 	  chain = chain->prev;
! 	  if (!chain)
! 	    break;
! 	  SET_REGNO_REG_SET (chain->live_after, i);
! 	}
  
!       if (INSN_SUID (chain->insn) == reg_where_born_exact[i]
! 	  && reg_where_born_clobber[i])
! 	SET_REGNO_REG_SET (chain->live_before, i);
      }
  
    if (file)
--- 357,370 ----
  	continue;
  
        chain = reg_where_dead_chain[i];
!       SET_REGNO_REG_SET (chain->dead_or_set, i);
  
!       while ((chain = chain->prev)
! 	     && INSN_SUID (chain->insn) > reg_where_born_exact[i])
! 	SET_REGNO_REG_SET (chain->live_throughout, i);
  
!       if (chain)
! 	SET_REGNO_REG_SET (chain->dead_or_set, i);
      }
  
    if (file)
*************** stupid_find_reg (call_preserved, class, 
*** 577,582 ****
--- 520,574 ----
    return -1;
  }
  
+ /* Note that REG is being set or referenced, and add the appropriate
+    REG_DEAD / REG_UNUSED note(s).  For sets, LIVE_BEFORE_P will be 0,
+    while for references, LIVE_BEFORE_P will be 1.
+    INSN is the instruction that the reg notes have to be added to.  */
+ static void
+ mark_hard_ref (reg, live_before_p, chain)
+      rtx reg;
+      int live_before_p;
+      struct insn_chain *chain;
+ {
+   /* Hard reg: mark it live for continuing scan of previous insns.  */
+   rtx insn = chain->insn;
+   int regno = REGNO (reg);
+   char *live = regs_live;
+   register int j;
+   int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+   int n_live = 0;
+   enum reg_note note_type = live_before_p ? REG_DEAD : REG_UNUSED;
+ 
+   for (j = nregs - 1; j >= 0; j--)
+     n_live += live[regno+j];
+ 
+   if (n_live == 0)
+     REG_NOTES (insn)
+       = gen_rtx_EXPR_LIST (note_type, reg, REG_NOTES (insn));
+   else if (n_live < nregs)
+     {
+       for (j = 0; j < nregs; )
+ 	{
+ 	  enum machine_mode mode = reg_raw_mode[regno + j];
+ 
+ 	  if (! live[regno+j])
+ 	    REG_NOTES (insn)
+ 	      = gen_rtx_EXPR_LIST (note_type, gen_rtx_REG (mode, regno + j),
+ 				   REG_NOTES (insn));
+ 	  j += HARD_REGNO_NREGS (regno + j, mode);
+ 	}
+     }
+ 
+   for (j = nregs - 1; j >= 0; j--)
+     {
+       if (! fixed_regs[regno+j]
+ 	  && (! live_before_p || ! live[regno+j]))
+ 	SET_REGNO_REG_SET (chain->dead_or_set, regno+j);
+       regs_ever_live[regno+j] = 1;
+       live[regno+j] = live_before_p;
+     }
+ }
+ 
  /* Walk X, noting all assignments and references to registers
     and recording what they imply about life spans.
     INSN is the current insn, supplied so we can find its suid.  */
*************** stupid_mark_refs (x, chain)
*** 606,616 ****
  		      >= FIRST_PSEUDO_REGISTER))))
  	{
  	  /* Register is being assigned.  */
  	  /* If setting a SUBREG, we treat the entire reg as being set.  */
  	  if (GET_CODE (SET_DEST (x)) == SUBREG)
! 	    regno = REGNO (SUBREG_REG (SET_DEST (x)));
! 	  else
! 	    regno = REGNO (SET_DEST (x));
  
  	  /* For hard regs, update the where-live info.  */
  	  if (regno < FIRST_PSEUDO_REGISTER)
--- 598,610 ----
  		      >= FIRST_PSEUDO_REGISTER))))
  	{
  	  /* Register is being assigned.  */
+ 	  rtx reg = SET_DEST (x);
+ 
  	  /* If setting a SUBREG, we treat the entire reg as being set.  */
  	  if (GET_CODE (SET_DEST (x)) == SUBREG)
! 	    reg = SUBREG_REG (reg);
! 
! 	  regno = REGNO (reg);
  
  	  /* For hard regs, update the where-live info.  */
  	  if (regno < FIRST_PSEUDO_REGISTER)
*************** stupid_mark_refs (x, chain)
*** 618,632 ****
  	      register int j
  		= HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x)));
  
  	      while (--j >= 0)
  		{
- 		  regs_ever_live[regno+j] = 1;
- 		  regs_live[regno+j] = 0;
- 
  		  /* The following line is for unused outputs;
  		     they do get stored even though never used again.  */
  		  MARK_LIVE_AFTER (insn, regno+j);
  
  		  /* When a hard reg is clobbered, mark it in use
  		     just before this insn, so it is live all through.  */
  		  if (code == CLOBBER && INSN_SUID (insn) > 0)
--- 612,627 ----
  	      register int j
  		= HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (x)));
  
+ 	      mark_hard_ref (reg, 0, chain);
+ 
  	      while (--j >= 0)
  		{
  		  /* The following line is for unused outputs;
  		     they do get stored even though never used again.  */
  		  MARK_LIVE_AFTER (insn, regno+j);
  
+ 		  CLEAR_REGNO_REG_SET (chain->live_throughout, regno + j);
+ 
  		  /* When a hard reg is clobbered, mark it in use
  		     just before this insn, so it is live all through.  */
  		  if (code == CLOBBER && INSN_SUID (insn) > 0)
*************** stupid_mark_refs (x, chain)
*** 650,657 ****
  	      if (reg_where_dead_chain[regno] == 0)
  		reg_where_dead_chain[regno] = chain;
  
  	      /* The reg must live at least one insn even
! 		 in it is never again used--because it has to go
  		 in SOME hard reg.  Mark it as dying after the current
  		 insn so that it will conflict with any other outputs of
  		 this insn.  */
--- 645,666 ----
  	      if (reg_where_dead_chain[regno] == 0)
  		reg_where_dead_chain[regno] = chain;
  
+ 	      /* If this register is clobbered or it is only used in
+ 		 this insn and is only set, mark it unused.  We have
+ 		 to do this even when not optimizing so that MD patterns
+ 		 which count on this behavior (e.g., it not causing an
+ 		 output reload on an insn setting CC) will operate
+ 		 correctly.
+ 		 We also need these notes for reload; for this purpose, we
+ 		 also have to consider the case when a pseudo is set at the
+ 		 end of its lifetime and not used.  */
+ 
+ 	      if (code == CLOBBER || ! regs_live[regno])
+ 		REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED, reg,
+ 						      REG_NOTES (insn));
+ 
  	      /* The reg must live at least one insn even
! 		 if it is never again used--because it has to go
  		 in SOME hard reg.  Mark it as dying after the current
  		 insn so that it will conflict with any other outputs of
  		 this insn.  */
*************** stupid_mark_refs (x, chain)
*** 669,690 ****
  
  	      if (last_setjmp_suid < reg_where_dead[regno])
  		regs_crosses_setjmp[regno] = 1;
- 
- 	      /* If this register is clobbered or it is only used in
- 		 this insn and is only set, mark it unused.  We have
- 		 to do this even when not optimizing so that MD patterns
- 		 which count on this behavior (e.g., it not causing an
- 		 output reload on an insn setting CC) will operate
- 		 correctly.  */
- 	      if (GET_CODE (SET_DEST (x)) == REG
- 		  && (code == CLOBBER
- 		      || (REGNO_FIRST_UID (regno) == INSN_UID (insn)
- 			  && REGNO_LAST_UID (regno) == INSN_UID (insn)
- 			  && ! reg_mentioned_p (SET_DEST (x),
- 						SET_SRC (x)))))
- 		REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
- 						      SET_DEST (x),
- 						      REG_NOTES (insn));
  	    }
  	}
  
--- 678,683 ----
*************** stupid_mark_refs (x, chain)
*** 715,729 ****
      {
        regno = REGNO (x);
        if (regno < FIRST_PSEUDO_REGISTER)
! 	{
! 	  /* Hard reg: mark it live for continuing scan of previous insns.  */
! 	  register int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
! 	  while (--j >= 0)
! 	    {
! 	      regs_ever_live[regno+j] = 1;
! 	      regs_live[regno+j] = 1;
! 	    }
! 	}
        else
  	{
  	  /* Pseudo reg: record first use, last use and number of uses.  */
--- 708,715 ----
      {
        regno = REGNO (x);
        if (regno < FIRST_PSEUDO_REGISTER)
! 	/* Hard reg: mark it live for continuing scan of previous insns.  */
! 	mark_hard_ref (x, 1, chain);
        else
  	{
  	  /* Pseudo reg: record first use, last use and number of uses.  */
*************** stupid_mark_refs (x, chain)
*** 736,741 ****
--- 722,729 ----
  	      regs_live[regno] = 1;
  	      reg_where_dead[regno] = INSN_SUID (insn);
  	      reg_where_dead_chain[regno] = chain;
+ 	      REG_NOTES (insn)
+ 		= gen_rtx_EXPR_LIST (REG_DEAD, x, REG_NOTES (insn));
  	    }
  	}
        return;


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