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]

Re: hard register reload patch


> Otherwise I'm happy with the patch and it should be installed once the 
> SUBREG issue is dealt with and we've got some initial performance #s.

I have changed the if to a while in add_stored_regs.
However, after Bernd's last checkin, I had to fix up the merged sources
by hand.  The timings I have just posted were made with these merged
sources.
Here is the updated patch:

Tue Dec 14 21:03:04 1999  J"orn Rennecke <amylaar@cygnus.co.uk>

	* caller-save.c (insert_one_insn): Returns struct insn_chain *.
	Handle live_throughout / dead_or_set instead of live_before /
	live_after.
	(save_call_clobbered_regs): Get register livenessinformation from
	chain->live_throughout.
	(add_stored_regs): New function.
	(insert_restore, insert_save): Add restored / saved registers to
	dead_or_set.
	* 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.h (struct insn_chain): Replace members live_before /
	live_after with live_throughout / dead_or_set.
	* reload1.c (new_insn_chain): Handle live_throughout / dead_or_set
	instead of live_before / live_after.
	(maybe_fix_stack_asms, find_reload_regs, finish_spills): Likewise.
	(order_regs_for_reload, find_reg, finish_spills): Likewise.
	(choose_reload_regs_init): Likewise.
	* 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. Clear chain->live_throughout.

Index: caller-save.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/caller-save.c,v
retrieving revision 1.24
diff -p -r1.24 caller-save.c
*** caller-save.c	1999/10/27 19:27:40	1.24
--- caller-save.c	1999/12/14 20:45:40
*************** static int insert_save			PROTO((struct i
*** 90,97 ****
  					       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.
  
--- 90,97 ----
  					       HARD_REG_SET *));
  static int insert_restore		PROTO((struct insn_chain *, int, int,
  					       int));
! static struct insn_chain *insert_one_insn PROTO((struct insn_chain *, int,
! 						 enum insn_code, rtx));
  
  /* Initialize for caller-save.
  
*************** 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;
+ 
+   while (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_restore (chain, before_p, regno, 
*** 568,577 ****
       int regno;
       int maxrestore;
  {
!   int i;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
    int numregs = 0;
  
    /* 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
--- 565,575 ----
       int regno;
       int maxrestore;
  {
!   int i, k;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
    int numregs = 0;
+   struct insn_chain *new;
  
    /* 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
*************** insert_restore (chain, before_p, regno, 
*** 589,595 ****
       backwards to the single register case.  */
    for (i = maxrestore; i > 0; i--)
      {
!       int j, k;
        int ok = 1;
  
        if (regno_save_mem[regno][i] == 0)
--- 587,593 ----
       backwards to the single register case.  */
    for (i = maxrestore; i > 0; i--)
      {
!       int j;
        int ok = 1;
  
        if (regno_save_mem[regno][i] == 0)
*************** insert_restore (chain, before_p, regno, 
*** 605,629 ****
        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_saved, regno + k);
- 	  n_regs_saved--;
- 	}
- 
        numregs = i;
        break;
      }
  
!   insert_one_insn (chain, before_p, code, pat);
  
    /* Tell our callers how many extra registers we saved/restored */
    return numregs - 1;
  }
--- 603,629 ----
        if (! ok)
  	continue;
  
        numregs = i;
        break;
      }
  
!   pat = gen_rtx_SET (VOIDmode,
! 		     gen_rtx_REG (GET_MODE (regno_save_mem[regno][numregs]), 
! 				  regno), 
! 		     regno_save_mem[regno][numregs]);
!   code = reg_restore_code[regno][numregs];
!   new = insert_one_insn (chain, before_p, code, pat);
! 
!   /* Clear status for all registers we restored.  */
!   for (k = 0; k < i; k++)
!     {
!       CLEAR_HARD_REG_BIT (hard_regs_saved, regno + k);
!       SET_REGNO_REG_SET (new->dead_or_set, regno + k);
!       n_regs_saved--;
!     }
  
+ 
+ 
    /* Tell our callers how many extra registers we saved/restored */
    return numregs - 1;
  }
*************** insert_save (chain, before_p, regno, to_
*** 636,645 ****
       int regno;
       HARD_REG_SET *to_save;
  {
!   int i;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
    int numregs = 0;
  
    /* 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
--- 636,646 ----
       int regno;
       HARD_REG_SET *to_save;
  {
!   int i, k;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
    int numregs = 0;
+   struct insn_chain *new;
  
    /* 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
*************** insert_save (chain, before_p, regno, to_
*** 657,663 ****
       Work backwards to the single register case.  */
    for (i = MOVE_MAX_WORDS; i > 0; i--)
      {
!       int j, k;
        int ok = 1;
        if (regno_save_mem[regno][i] == 0)
  	continue;
--- 658,664 ----
       Work backwards to the single register case.  */
    for (i = MOVE_MAX_WORDS; i > 0; i--)
      {
!       int j;
        int ok = 1;
        if (regno_save_mem[regno][i] == 0)
  	continue;
*************** insert_save (chain, before_p, regno, to_
*** 672,701 ****
        if (! ok)
  	continue;
  
-       pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i],
- 			 gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
- 				      regno));
-       code = reg_save_code[regno][i];
- 
-       /* Set hard_regs_saved for all the registers we saved.  */
-       for (k = 0; k < i; k++)
- 	{
- 	  SET_HARD_REG_BIT (hard_regs_saved, regno + k);
- 	  n_regs_saved++;
- 	}
- 
        numregs = i;
        break;
      }
  
!   insert_one_insn (chain, before_p, code, pat);
  
    /* Tell our callers how many extra registers we saved/restored */
    return numregs - 1;
  }
  
  /* Emit a new caller-save insn and set the code.  */
! static void
  insert_one_insn (chain, before_p, code, pat)
       struct insn_chain *chain;
       int before_p;
--- 673,702 ----
        if (! ok)
  	continue;
  
        numregs = i;
        break;
      }
  
!   pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][numregs],
! 		     gen_rtx_REG (GET_MODE (regno_save_mem[regno][numregs]),
! 				  regno));
!   code = reg_save_code[regno][numregs];
!   new = insert_one_insn (chain, before_p, code, pat);
! 
!   /* Set hard_regs_saved and dead_or_set for all the registers we saved.  */
!   for (k = 0; k < numregs; k++)
!     {
!       SET_HARD_REG_BIT (hard_regs_saved, regno + k);
!       SET_REGNO_REG_SET (new->dead_or_set, regno + k);
!       n_regs_saved++;
!     }
  
    /* Tell our callers how many extra registers we saved/restored */
    return numregs - 1;
  }
  
  /* Emit a new caller-save insn and set the code.  */
! static struct insn_chain *
  insert_one_insn (chain, before_p, code, pat)
       struct insn_chain *chain;
       int before_p;
*************** insert_one_insn (chain, before_p, code, 
*** 721,726 ****
--- 722,729 ----
    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;
      }
--- 735,763 ----
        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;
      }
--- 771,783 ----
        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;
      }
*************** insert_one_insn (chain, before_p, code, 
*** 756,759 ****
--- 785,789 ----
    new->is_caller_save_insn = 1;
  
    INSN_CODE (new->insn) = code;
+   return new;
  }
Index: global.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/global.c,v
retrieving revision 1.50
diff -p -r1.50 global.c
*** global.c	1999/12/12 01:34:39	1.50
--- global.c	1999/12/14 20:45:46
*************** static void mark_reg_live_nc	PROTO((int,
*** 303,309 ****
  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));
  
  /* Perform allocation of pseudo-registers not allocated by local_alloc.
--- 303,310 ----
  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));
  
  /* Perform allocation of pseudo-registers not allocated by local_alloc.
*************** mark_elimination (from, to)
*** 1693,1705 ****
     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;
  
--- 1694,1706 ----
     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)
*** 1714,1739 ****
      {
        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,
--- 1715,1758 ----
      {
        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)
*** 1778,1785 ****
  	  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;
--- 1797,1802 ----
*************** build_insn_chain (first)
*** 1789,1804 ****
  	      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')
  	    {
--- 1806,1823 ----
  	      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)
*** 1809,1815 ****
  	      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)));
  	    }
  	}
  
--- 1828,1835 ----
  	      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);
  	    }
  	}
  
Index: reload.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.h,v
retrieving revision 1.22
diff -p -r1.22 reload.h
*** reload.h	1999/12/13 13:21:34	1.22
--- reload.h	1999/12/14 20:45:46
*************** struct insn_chain 
*** 224,235 ****
    /* 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;
--- 224,232 ----
    /* 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;
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload1.c,v
retrieving revision 1.186
diff -p -r1.186 reload1.c
*** reload1.c	1999/12/14 12:40:02	1.186
--- reload1.c	1999/12/14 20:45:49
*************** 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
      {
--- 514,521 ----
      {
        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
      {
*************** maybe_fix_stack_asms ()
*** 1295,1302 ****
        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);
  	  }
      }
  
--- 1295,1302 ----
        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	if (TEST_HARD_REG_BIT (allowed, i))
  	  {
! 	    CLEAR_REGNO_REG_SET (chain->live_throughout, i);
! 	    CLEAR_REGNO_REG_SET (chain->dead_or_set, i);
  	  }
      }
  
*************** order_regs_for_reload (chain)
*** 1516,1523 ****
        /* 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
--- 1516,1523 ----
        /* 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)
! 	  || REGNO_REG_SET_P (chain->dead_or_set, i))
  	SET_HARD_REG_BIT (bad_spill_regs, i);
      }
    /* Now find out which pseudos are allocated to it, and update
*************** order_regs_for_reload (chain)
*** 1525,1536 ****
    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);
       });
--- 1525,1536 ----
    CLEAR_REG_SET (&pseudos_counted);
  
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
       {
         count_pseudo (j);
       });
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
       {
         count_pseudo (j);
       });
*************** find_reg (chain, order, dumpfile)
*** 1645,1656 ****
    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);
       });
--- 1645,1656 ----
    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);
       });
    EXECUTE_IF_SET_IN_REG_SET
!     (chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
       {
         count_spilled_pseudo (best_reg, rl->nregs, j);
       });
*************** finish_spills (global, dumpfile)
*** 3489,3501 ****
        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);
--- 3489,3501 ----
        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);
  	     });
  	  EXECUTE_IF_SET_IN_REG_SET
! 	    (chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
  	     {
  	       ior_hard_reg_set (pseudo_forbidden_regs + i,
  				 &chain->used_spill_regs);
*************** finish_spills (global, dumpfile)
*** 3528,3549 ****
        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);
  
--- 3528,3549 ----
        HARD_REG_SET used_by_pseudos;
        HARD_REG_SET used_by_pseudos2;
  
!       AND_COMPL_REG_SET (chain->live_throughout, &spilled_pseudos);
!       AND_COMPL_REG_SET (chain->dead_or_set, &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_throughout);
! 	  REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->dead_or_set);
  	  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_throughout);
! 	  compute_use_by_pseudos (&used_by_pseudos, chain->dead_or_set);
  	  COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
  	  AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
  
*************** choose_reload_regs_init (chain, save_rel
*** 5033,5044 ****
    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++)
      {
--- 5033,5044 ----
    CLEAR_HARD_REG_SET (reg_used_in_insn);
    {
      HARD_REG_SET tmp;
!     REG_SET_TO_HARD_REG_SET (tmp, chain->live_throughout);
      IOR_HARD_REG_SET (reg_used_in_insn, tmp);
!     REG_SET_TO_HARD_REG_SET (tmp, chain->dead_or_set);
      IOR_HARD_REG_SET (reg_used_in_insn, tmp);
!     compute_use_by_pseudos (&reg_used_in_insn, chain->live_throughout);
!     compute_use_by_pseudos (&reg_used_in_insn, chain->dead_or_set);
    }
    for (i = 0; i < reload_n_operands; i++)
      {
Index: stupid.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/stupid.c,v
retrieving revision 1.24
diff -p -r1.24 stupid.c
*** stupid.c	1999/11/30 12:16:55	1.24
--- stupid.c	1999/12/14 20:45:49
*************** static int stupid_find_reg	PROTO((int, e
*** 129,140 ****
  				       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
--- 129,141 ----
  				       int, int, int));
  static void stupid_mark_refs	PROTO((rtx, struct insn_chain *));
  static void find_clobbered_regs	PROTO((rtx, rtx, void *));
+ static void mark_hard_ref	PROTO((rtx, int, struct insn_chain *));
  
  /* 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_throughout field
     of the appropriate insn_chain structure.  */
  
  static void
*************** find_clobbered_regs (reg, setter, data)
*** 161,168 ****
      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++);
      }
  }
  
--- 162,168 ----
      nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
    while (nregs-- > 0)
      {
!       SET_REGNO_REG_SET (current_chain->live_throughout, regno++);
      }
  }
  
*************** 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
--- 285,291 ----
  	  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)
*** 336,345 ****
  
        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.  */
--- 336,341 ----
*************** 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)
--- 403,416 ----
  	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, 
*** 568,573 ****
--- 557,588 ----
    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.  */
+   int regno = REGNO (reg);
+   char *live = regs_live;
+   register int j;
+   int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ 
+   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)
*** 597,623 ****
  		      >= 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)
  	    {
  	      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,641 ----
  		      >= 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)
  	    {
  	      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)
*** 706,720 ****
      {
        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.  */
--- 724,731 ----
      {
        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.  */


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