equivalence handling patch applied to local-alloc.c, reload1.c

Joern Rennecke amylaar@cygnus.co.uk
Wed Nov 11 19:38:00 GMT 1998


Tue Nov 10 04:12:02 1998  J"orn Rennecke <amylaar@cygnus.co.uk>

	Handle equivalences that have been obscured by gcse:

	* reload1.c (reload): Handle equivalences set up in multiple places.
	* local-alloc.c (reg_equiv_init_insns): New variable.
	(no_equiv): New function.
	(update_equiv_regs): Handle equivalences set up in multiple places.
	Don't ignore an insn just because its destination is likely to be
	spilled.

Index: local-alloc.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/local-alloc.c,v
retrieving revision 1.24
diff -p -r1.24 local-alloc.c
*** local-alloc.c	1998/10/17 01:28:51	1.24
--- local-alloc.c	1998/11/12 03:33:20
*************** static rtx this_insn;
*** 234,239 ****
--- 234,242 ----
  
  static rtx *reg_equiv_replacement;
  
+ /* Used for communication between update_equiv_regs and no_equiv.  */
+ static rtx *reg_equiv_init_insns;
+ 
  static void alloc_qty		PROTO((int, enum machine_mode, int, int));
  static void validate_equiv_mem_from_store PROTO((rtx, rtx));
  static int validate_equiv_mem	PROTO((rtx, rtx, rtx));
*************** static int contains_replace_regs PROTO((
*** 241,246 ****
--- 244,250 ----
  static int memref_referenced_p	PROTO((rtx, rtx));
  static int memref_used_between_p PROTO((rtx, rtx, rtx));
  static void update_equiv_regs	PROTO((void));
+ static void no_equiv		PROTO((rtx, rtx));
  static void block_alloc		PROTO((int));
  static int qty_sugg_compare    	PROTO((int, int));
  static int qty_sugg_compare_1	PROTO((const GENERIC_PTR, const GENERIC_PTR));
*************** memref_used_between_p (memref, start, en
*** 633,639 ****
  static void
  update_equiv_regs ()
  {
-   rtx *reg_equiv_init_insn = (rtx *) alloca (max_regno * sizeof (rtx));
    /* Set when an attempt should be made to replace a register with the
       associated reg_equiv_replacement entry at the end of this function.  */
    char *reg_equiv_replace
--- 637,642 ----
*************** update_equiv_regs ()
*** 641,649 ****
    rtx insn;
    int block, depth;
  
    reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx));
  
!   bzero ((char *) reg_equiv_init_insn, max_regno * sizeof (rtx));
    bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx));
    bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);
  
--- 644,653 ----
    rtx insn;
    int block, depth;
  
+   reg_equiv_init_insns = (rtx *) alloca (max_regno * sizeof (rtx));
    reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx));
  
!   bzero ((char *) reg_equiv_init_insns, max_regno * sizeof (rtx));
    bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx));
    bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);
  
*************** update_equiv_regs ()
*** 657,663 ****
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      {
        rtx note;
!       rtx set = single_set (insn);
        rtx dest, src;
        int regno;
  
--- 661,667 ----
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      {
        rtx note;
!       rtx set;
        rtx dest, src;
        int regno;
  
*************** update_equiv_regs ()
*** 669,678 ****
  	    loop_depth--;
  	}
  
!       /* If this insn contains more (or less) than a single SET, ignore it.  */
!       if (set == 0)
  	continue;
  
        dest = SET_DEST (set);
        src = SET_SRC (set);
  
--- 673,706 ----
  	    loop_depth--;
  	}
  
!       if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
  	continue;
  
+       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ 	if (REG_NOTE_KIND (note) == REG_INC)
+ 	  no_equiv (XEXP (note, 0), note);
+ 
+       set = single_set (insn);
+ 
+       /* If this insn contains more (or less) than a single SET,
+ 	 only mark all destinations as having no known equivalence.  */
+       if (set == 0)
+ 	{
+ 	  note_stores (PATTERN (insn), no_equiv);
+ 	  continue;
+ 	}
+       else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ 	{
+ 	  int i;
+ 
+ 	  for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ 	    {
+ 	      rtx part = XVECEXP (PATTERN (insn), 0, i);
+ 	      if (part != set)
+ 		note_stores (part, no_equiv);
+ 	    }
+ 	}
+ 
        dest = SET_DEST (set);
        src = SET_SRC (set);
  
*************** update_equiv_regs ()
*** 688,722 ****
  	 If one of the regs in the address is marked as reg_equiv_replace,
  	 then we can't add this REG_EQUIV note.  The reg_equiv_replace
  	 optimization may move the set of this register immediately before
! 	 insn, which puts it after reg_equiv_init_insn[regno], and hence
  	 the mention in the REG_EQUIV note would be to an uninitialized
  	 pseudo.  */
  
!       if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG
! 	  && (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
  	  && REG_BASIC_BLOCK (regno) >= 0
! 	  && reg_equiv_init_insn[regno] != 0
  	  && ! find_reg_note (insn, REG_EQUIV, NULL_RTX)
! 	  && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace)
! 	  && validate_equiv_mem (reg_equiv_init_insn[regno], SET_SRC (set),
! 				 dest)
! 	  && ! memref_used_between_p (SET_DEST (set),
! 				      reg_equiv_init_insn[regno], insn))
! 	REG_NOTES (reg_equiv_init_insn[regno])
! 	  = gen_rtx_EXPR_LIST (REG_EQUIV, dest,
! 			       REG_NOTES (reg_equiv_init_insn[regno]));
  
        /* We only handle the case of a pseudo register being set
! 	 once and only if neither the source nor the destination are
! 	 in a register class that's likely to be spilled.  */
        if (GET_CODE (dest) != REG
  	  || (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
! 	  || REG_N_SETS (regno) != 1
! 	  || CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (dest)))
! 	  || (GET_CODE (src) == REG
! 	      && REGNO (src) >= FIRST_PSEUDO_REGISTER
! 	      && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src)))))
! 	continue;
  
        note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
  
--- 716,778 ----
  	 If one of the regs in the address is marked as reg_equiv_replace,
  	 then we can't add this REG_EQUIV note.  The reg_equiv_replace
  	 optimization may move the set of this register immediately before
! 	 insn, which puts it after reg_equiv_init_insns[regno], and hence
  	 the mention in the REG_EQUIV note would be to an uninitialized
  	 pseudo.  */
+       /* ????? This test isn't good enough; we might see a MEM with a use of
+ 	 a pseudo register before we see its setting insn that will cause
+ 	 reg_equiv_replace for that pseudo to be set.
+ 	 Equivalences to MEMs should be made in another pass, after the
+ 	 reg_equiv_replace information has been gathered.  */
  
!       if (GET_CODE (dest) == MEM && GET_CODE (src) == REG
! 	  && (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
  	  && REG_BASIC_BLOCK (regno) >= 0
! 	  && REG_N_SETS (regno) == 1
! 	  && reg_equiv_init_insns[regno] != 0
! 	  && reg_equiv_init_insns[regno] != const0_rtx
  	  && ! find_reg_note (insn, REG_EQUIV, NULL_RTX)
! 	  && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace))
! 	{
! 	  rtx init_insn = XEXP (reg_equiv_init_insns[regno], 0);
! 	  if (validate_equiv_mem (init_insn, src, dest)
! 	      && ! memref_used_between_p (dest, init_insn, insn))
! 	    REG_NOTES (init_insn)
! 	      = gen_rtx_EXPR_LIST (REG_EQUIV, dest, REG_NOTES (init_insn));
! 	}
  
        /* We only handle the case of a pseudo register being set
! 	 once, or always to the same value.  */
!       /* ??? The mn10200 port breaks if we add equivalences for
! 	 values that need an ADDRESS_REGS register and set them equivalent
! 	 to a MEM of a pseudo.  The actual problem is in the over-conservative
! 	 handling of INPADDR_ADDRESS / INPUT_ADDRESS / INPUT triples in
! 	 calculate_needs, but we traditionally work around this problem
! 	 here by rejecting equivalences when the destination is in a register
! 	 that's likely spilled.  This is fragile, of course, since the
! 	 preferred class of a pseudo depends on all intructions that set
! 	 or use it.  */
! 
        if (GET_CODE (dest) != REG
  	  || (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
! 	  || reg_equiv_init_insns[regno] == const0_rtx
! 	  || (CLASS_LIKELY_SPILLED_P (reg_preferred_class (regno))
! 	      && GET_CODE (src) == MEM))
! 	{
! 	  /* This might be seting a SUBREG of a pseudo, a pseudo that is
! 	     also set somewhere else to a constant.  */
! 	  note_stores (set, no_equiv);
! 	  continue;
! 	}
!       /* Don't handle the equivalence if the source is in a register
! 	 class that's likely to be spilled.  */
!       if (GET_CODE (src) == REG
! 	  && REGNO (src) >= FIRST_PSEUDO_REGISTER
! 	  && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src))))
! 	{
! 	  no_equiv (dest, set);
! 	  continue;
! 	}
  
        note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
  
*************** update_equiv_regs ()
*** 736,743 ****
          note = NULL;
  #endif
  
        /* Record this insn as initializing this register.  */
!       reg_equiv_init_insn[regno] = insn;
  
        /* If this register is known to be equal to a constant, record that
  	 it is always equivalent to the constant.  */
--- 792,810 ----
          note = NULL;
  #endif
  
+       if (REG_N_SETS (regno) != 1
+ 	  && (! note
+ 	      || ! CONSTANT_P (XEXP (note, 0))
+ 	      || (reg_equiv_replacement[regno]
+ 		  && ! rtx_equal_p (XEXP (note, 0),
+ 				    reg_equiv_replacement[regno]))))
+ 	{
+ 	  no_equiv (dest, set);
+ 	  continue;
+ 	}
        /* Record this insn as initializing this register.  */
!       reg_equiv_init_insns[regno]
! 	= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init_insns[regno]);
  
        /* If this register is known to be equal to a constant, record that
  	 it is always equivalent to the constant.  */
*************** update_equiv_regs ()
*** 849,855 ****
  	      if (! reg_equiv_replace[regno])
  		continue;
  
! 	      equiv_insn = reg_equiv_init_insn[regno];
  
  	      if (validate_replace_rtx (regno_reg_rtx[regno],
  					reg_equiv_replacement[regno], insn))
--- 916,927 ----
  	      if (! reg_equiv_replace[regno])
  		continue;
  
! 	      /* reg_equiv_replace[REGNO] gets set only when
! 		 REG_N_REFS[REGNO] is 2, i.e. the register is set
! 		 once and used once.  (If it were only set, but not used,
! 		 flow would have deleted the setting insns.)  Hence 
! 		 there can only be one insn in reg_equiv_init_insns.  */
! 	      equiv_insn = XEXP (reg_equiv_init_insns[regno], 0);
  
  	      if (validate_replace_rtx (regno_reg_rtx[regno],
  					reg_equiv_replacement[regno], insn))
*************** update_equiv_regs ()
*** 895,900 ****
--- 967,1001 ----
  	    }
  	}
      }
+ }
+ 
+ /* Mark REG as having no known equivalence.
+    Some instructions might have been proceessed before and furnished
+    with REG_EQUIV notes for this register; these notes will have to be
+    removed.
+    STORE is the piece of RTL that does the non-constant / conflicting
+    assignment - a SET, CLOBBER or REG_INC note.  It is currently not used,
+    but needs to be there because this function is called from note_stores.  */
+ static void
+ no_equiv (reg, store)
+      rtx reg, store;
+ {
+   int regno;
+   rtx list;
+ 
+   if (GET_CODE (reg) != REG)
+     return;
+   regno = REGNO (reg);
+   list = reg_equiv_init_insns[regno];
+   if (list == const0_rtx)
+     return;
+   for (; list; list =  XEXP (list, 1))
+     {
+       rtx insn = XEXP (list, 0);
+       remove_note (insn, find_reg_note (insn, REG_EQUIV, NULL_RTX));
+     }
+   reg_equiv_init_insns[regno] = const0_rtx;
+   reg_equiv_replacement[regno] = NULL_RTX;
  }
  
  /* Allocate hard regs to the pseudo regs used only within block number B.
Index: reload1.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/reload1.c,v
retrieving revision 1.97
diff -p -r1.97 reload1.c
*** reload1.c	1998/11/09 02:12:55	1.97
--- reload1.c	1998/11/12 03:33:23
*************** rtx *reg_equiv_mem;
*** 114,120 ****
  /* Widest width in which each pseudo reg is referred to (via subreg).  */
  static int *reg_max_ref_width;
  
! /* Element N is the insn that initialized reg N from its equivalent
     constant or memory slot.  */
  static rtx *reg_equiv_init;
  
--- 114,120 ----
  /* Widest width in which each pseudo reg is referred to (via subreg).  */
  static int *reg_max_ref_width;
  
! /* Element N is the list of insns that initialized reg N from its equivalent
     constant or memory slot.  */
  static rtx *reg_equiv_init;
  
*************** reload (first, global, dumpfile)
*** 710,716 ****
  		     So don't mark this insn now.  */
  		  if (GET_CODE (x) != MEM
  		      || rtx_equal_p (SET_SRC (set), x))
! 		    reg_equiv_init[i] = insn;
  		}
  	    }
  	}
--- 710,717 ----
  		     So don't mark this insn now.  */
  		  if (GET_CODE (x) != MEM
  		      || rtx_equal_p (SET_SRC (set), x))
! 		    reg_equiv_init[i]
! 		      = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[i]);
  		}
  	    }
  	}
*************** reload (first, global, dumpfile)
*** 722,728 ****
  	       && reg_equiv_memory_loc[REGNO (SET_SRC (set))]
  	       && rtx_equal_p (SET_DEST (set),
  			       reg_equiv_memory_loc[REGNO (SET_SRC (set))]))
! 	reg_equiv_init[REGNO (SET_SRC (set))] = insn;
  
        if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
  	scan_paradoxical_subregs (PATTERN (insn));
--- 723,731 ----
  	       && reg_equiv_memory_loc[REGNO (SET_SRC (set))]
  	       && rtx_equal_p (SET_DEST (set),
  			       reg_equiv_memory_loc[REGNO (SET_SRC (set))]))
! 	reg_equiv_init[REGNO (SET_SRC (set))]
! 	  = gen_rtx_INSN_LIST (VOIDmode, insn,
! 			       reg_equiv_init[REGNO (SET_SRC (set))]);
  
        if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
  	scan_paradoxical_subregs (PATTERN (insn));
*************** reload (first, global, dumpfile)
*** 971,992 ****
       If that insn didn't set the register (i.e., it copied the register to
       memory), just delete that insn instead of the equivalencing insn plus
       anything now dead.  If we call delete_dead_insn on that insn, we may
!      delete the insn that actually sets the register if the register die
       there and that is incorrect.  */
  
    for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
!     if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0
! 	&& GET_CODE (reg_equiv_init[i]) != NOTE)
!       {
! 	if (reg_set_p (regno_reg_rtx[i], PATTERN (reg_equiv_init[i])))
! 	  delete_dead_insn (reg_equiv_init[i]);
! 	else
! 	  {
! 	    PUT_CODE (reg_equiv_init[i], NOTE);
! 	    NOTE_SOURCE_FILE (reg_equiv_init[i]) = 0;
! 	    NOTE_LINE_NUMBER (reg_equiv_init[i]) = NOTE_INSN_DELETED;
! 	  }
!       }
  
    /* Use the reload registers where necessary
       by generating move instructions to move the must-be-register
--- 974,1003 ----
       If that insn didn't set the register (i.e., it copied the register to
       memory), just delete that insn instead of the equivalencing insn plus
       anything now dead.  If we call delete_dead_insn on that insn, we may
!      delete the insn that actually sets the register if the register dies
       there and that is incorrect.  */
  
    for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
!     {
!       if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0)
! 	{
! 	  rtx list;
! 	  for (list = reg_equiv_init[i]; list; list = XEXP (list, 1))
! 	    {
! 	      rtx equiv_insn = XEXP (list, 0);
! 	      if (GET_CODE (equiv_insn) == NOTE)
! 		continue;
! 	      if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
! 		delete_dead_insn (equiv_insn);
! 	      else
! 		{
! 		  PUT_CODE (equiv_insn, NOTE);
! 		  NOTE_SOURCE_FILE (equiv_insn) = 0;
! 		  NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
! 		}
! 	    }
! 	}
!     }
  
    /* Use the reload registers where necessary
       by generating move instructions to move the must-be-register



More information about the Gcc-patches mailing list