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]
Other format: [Raw text]

Re: reload cse may delete loads it shouldn't


On Apr 16, 2003, Alexandre Oliva <aoliva at redhat dot com> wrote:

> On Apr 15, 2003, Alexandre Oliva <aoliva at redhat dot com> wrote:
>> Ok to install if it bootstrap on athlon-pc-linux-gnu?

> It bootstrapped ok on athlon-pc-linux-gnu, and passed tests without
> regressions on mn10300-elf, but RTH asked for some additional comments
> in the code.  How's this?  Ok to install?

Err...  Of course I'd notice one second after hitting the send button
that I still hadn't updated the patch file after fixing an error I had
introduced in the last revision.  Here's the correct version, that I'm
bootstrapping again just because I'm paranoid :-)

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva at redhat dot com>

	* reload1.c (reload_cse_noop_set_p): Return false if mode of
	SET_DEST is not the same as that returned by...
	* cselib.h (cselib_reg_set_mode): ... new function.
	* cselib.c (cselib_reg_set_mode): Define it.
	(REG_VALUES): Document semantics of first element as set mode.
	(cselib_subst_to_values): Skip first element if ELT is NULL.
	(cselib_lookup): Likewise.  Insert past the first element.
	(cselib_invalidate_regno): NULLify first element.
	(cselib_record_set): Set first element.

Index: gcc/reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.387
diff -u -p -r1.387 reload1.c
--- gcc/reload1.c 9 Apr 2003 17:50:08 -0000 1.387
+++ gcc/reload1.c 16 Apr 2003 22:58:37 -0000
@@ -8025,6 +8025,9 @@ static int
 reload_cse_noop_set_p (set)
      rtx set;
 {
+  if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
+    return 0;
+
   return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
 }
 
Index: gcc/cselib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cselib.h,v
retrieving revision 1.7
diff -u -p -r1.7 cselib.h
--- gcc/cselib.h 11 Mar 2003 21:52:41 -0000 1.7
+++ gcc/cselib.h 16 Apr 2003 22:58:37 -0000
@@ -1,6 +1,6 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999 Free Software Foundation, Inc.
+   1999, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -67,6 +67,7 @@ extern void cselib_update_varray_sizes	P
 extern void cselib_init			PARAMS ((void));
 extern void cselib_finish		PARAMS ((void));
 extern void cselib_process_insn		PARAMS ((rtx));
+extern enum machine_mode cselib_reg_set_mode PARAMS ((rtx));
 extern int rtx_equal_for_cselib_p	PARAMS ((rtx, rtx));
 extern int references_value_p		PARAMS ((rtx, int));
 extern rtx cselib_subst_to_values	PARAMS ((rtx));
Index: gcc/cselib.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cselib.c,v
retrieving revision 1.26
diff -u -p -r1.26 cselib.c
--- gcc/cselib.c 14 Mar 2003 20:15:11 -0000 1.26
+++ gcc/cselib.c 16 Apr 2003 22:58:38 -0000
@@ -1,6 +1,6 @@
 /* Common subexpression elimination library for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -99,9 +99,13 @@ static int n_useless_values;
 /* Number of useless values before we remove them from the hash table.  */
 #define MAX_USELESS_VALUES 32
 
-/* This table maps from register number to values.  It does not contain
-   pointers to cselib_val structures, but rather elt_lists.  The purpose is
-   to be able to refer to the same register in different modes.  */
+/* This table maps from register number to values.  It does not
+   contain pointers to cselib_val structures, but rather elt_lists.
+   The purpose is to be able to refer to the same register in
+   different modes.  The first element of the list defines the mode in
+   which the register was set; if the mode is unknown or the value is
+   no longer valid in that mode, ELT will be NULL for the first
+   element.  */
 static GTY(()) varray_type reg_values;
 static GTY((deletable (""))) varray_type reg_values_old;
 #define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I))
@@ -402,6 +406,25 @@ remove_useless_values ()
     abort ();
 }
 
+/* Return the mode in which a register was last set.  If X is not a
+   register, return its mode.  If the mode in which the register was
+   set is not known, or the value was already clobbered, return
+   VOIDmode.  */
+
+enum machine_mode
+cselib_reg_set_mode (x)
+     rtx x;
+{
+  if (GET_CODE (x) != REG)
+    return GET_MODE (x);
+
+  if (REG_VALUES (REGNO (x)) == NULL
+      || REG_VALUES (REGNO (x))->elt == NULL)
+    return VOIDmode;
+
+  return GET_MODE (REG_VALUES (REGNO (x))->elt->u.val_rtx);
+}
+
 /* Return nonzero if we can prove that X and Y contain the same value, taking
    our gathered information into account.  */
 
@@ -812,7 +835,10 @@ cselib_subst_to_values (x)
   switch (code)
     {
     case REG:
-      for (l = REG_VALUES (REGNO (x)); l; l = l->next)
+      l = REG_VALUES (REGNO (x));
+      if (l && l->elt == NULL)
+	l = l->next;
+      for (; l; l = l->next)
 	if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x))
 	  return l->elt->u.val_rtx;
 
@@ -909,7 +935,10 @@ cselib_lookup (x, mode, create)
       struct elt_list *l;
       unsigned int i = REGNO (x);
 
-      for (l = REG_VALUES (i); l; l = l->next)
+      l = REG_VALUES (i);
+      if (l && l->elt == NULL)
+	l = l->next;
+      for (; l; l = l->next)
 	if (mode == GET_MODE (l->elt->u.val_rtx))
 	  return l->elt;
 
@@ -927,8 +956,14 @@ cselib_lookup (x, mode, create)
       e = new_cselib_val (++next_unknown_value, GET_MODE (x));
       e->locs = new_elt_loc_list (e->locs, x);
       if (REG_VALUES (i) == 0)
-        VARRAY_PUSH_UINT (used_regs, i);
-      REG_VALUES (i) = new_elt_list (REG_VALUES (i), e);
+	{
+	  /* Maintain the invariant that the first entry of
+	     REG_VALUES, if present, must be the value used to set the
+	     register, or NULL.  */
+	  VARRAY_PUSH_UINT (used_regs, i);
+	  REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL);
+	}
+      REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
       slot = htab_find_slot_with_hash (hash_table, x, e->value, INSERT);
       *slot = e;
       return e;
@@ -1011,17 +1046,28 @@ cselib_invalidate_regno (regno, mode)
 	  struct elt_loc_list **p;
 	  unsigned int this_last = i;
 
-	  if (i < FIRST_PSEUDO_REGISTER)
+	  if (i < FIRST_PSEUDO_REGISTER && v != NULL)
 	    this_last += HARD_REGNO_NREGS (i, GET_MODE (v->u.val_rtx)) - 1;
 
-	  if (this_last < regno)
+	  if (this_last < regno || v == NULL)
 	    {
 	      l = &(*l)->next;
 	      continue;
 	    }
 
 	  /* We have an overlap.  */
-	  unchain_one_elt_list (l);
+	  if (*l == REG_VALUES (i))
+	    {
+	      /* Maintain the invariant that the first entry of
+		 REG_VALUES, if present, must be the value used to set
+		 the register, or NULL.  This is also nice because
+		 then we won't push the same regno onto user_regs
+		 multiple times.  */
+	      (*l)->elt = NULL;
+	      l = &(*l)->next;
+	    }
+	  else
+	    unchain_one_elt_list (l);
 
 	  /* Now, we clear the mapping from value to reg.  It must exist, so
 	     this code will crash intentionally if it doesn't.  */
@@ -1213,9 +1259,6 @@ cselib_record_set (dest, src_elt, dest_a
 
   if (dreg >= 0)
     {
-      if (REG_VALUES (dreg) == 0)
-        VARRAY_PUSH_UINT (used_regs, dreg);
-
       if (dreg < FIRST_PSEUDO_REGISTER)
 	{
 	  unsigned int n = HARD_REGNO_NREGS (dreg, GET_MODE (dest));
@@ -1224,7 +1267,20 @@ cselib_record_set (dest, src_elt, dest_a
 	    max_value_regs = n;
 	}
 
-      REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt);
+      if (REG_VALUES (dreg) == 0)
+	{
+	  VARRAY_PUSH_UINT (used_regs, dreg);
+	  REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt);
+	}
+      else
+	{
+	  if (REG_VALUES (dreg)->elt == 0)
+	    REG_VALUES (dreg)->elt = src_elt;
+	  else
+	    /* The register should have been invalidated.  */
+	    abort ();
+	}
+
       if (src_elt->locs == 0)
 	n_useless_values--;
       src_elt->locs = new_elt_loc_list (src_elt->locs, dest);
-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                 aoliva at {redhat dot com, gcc.gnu.org}
CS PhD student at IC-Unicamp        oliva at {lsd dot ic dot unicamp dot br, gnu.org}
Free Software Evangelist                Professional serial bug killer

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