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]

[PR42977, VTA] stabilize cselib's remove_useless_values calls over -g


Debug insns in sched2 (and possibly elsewhere) get cselib to
garbage-collect useless values at different points, leading to
scheduling differences.

This patch keeps separate counts of useless debug and nondebug values,
switching debug to nondebug values upon the first nondebug use.  It also
counts debug values, so that they can be discounted from the number of
elements in the cselib hash table.

It turned out that this wasn't enough to call remove_useless_values() at
the same points, because n_deleted elements are still counted in
n_elements, so when we deleted debug values, element counts would go out
of sync.  I fixed this by discounting n_deleted from n_elements in the
test that guards the remove_useless_values() call.

I had to back to r156515 to duplicate the problem and verify that the
patch fixed it.  The bug is quite sensitive to codegen variations, and
the given testcase, in addition to no longer triggering the bug, is
probably too large for the testsuite.

Regstrapping on x86_64-linux-gnu and i686-linux-gnu.  Ok if it passes?

I also enclose a second patch, that is equivalent, but that applies on
top of http://gcc.gnu.org/ml/gcc-patches/2010-03/msg01038.html, which is
still pending review.

for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/42977
	* cselib.c (n_useless_values): Document handling of debug locs.
	(n_useless_debug_values, n_debug_values): New variables.
	(new_elt_loc_list): Don't add to debug values, keep count.
	(promote_debug_loc): New.
	(cselib_reset_table): Zero new variables.
	(entry_and_rtx_equal_p): Promote debug locs.
	(discard_useless_locs): Increment n_useless_debug_values for
	debug values.
	(remove_useless_values): Adjust n_useless_values and n_debug_values
	with n_useless_debug_values.
	(add_mem_for_addr): Promote debug locs.
	(cselib_lookup_mem): Likewise.
	(cselib_lookup_addr): Renamed to...
	(cselib_lookup_addr_1): ... this.  Promote debug locs.
	Don't call...
	(cselib_log_lookup): ... this.  Turn into...
	(cselib_lookup_addr): ... new wrapper.
	(cselib_lookup_from_insn): New.
	(cselib_invalidate_regno): Increment n_useless_debug_values for
	debug values.
	(cselib_invalidate_mem): Likewise.
	(cselib_process_insn): Take n_deleted and n_debug_values into
	account to guard remove_useless_value call.
	(cselib_finish): Zero n_useless_debug_values.
	* cselib.h (cselib_lookup_from_insn): Declare.
	* sched-deps.c (sched_analyze_1): Use cselib_lookup_from_insn.
	(sched_analyze_2): Likewise.

Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2010-03-30 04:49:14.000000000 -0300
+++ gcc/cselib.c	2010-03-30 04:49:46.000000000 -0300
@@ -97,9 +97,47 @@ static unsigned int next_uid;
 /* The number of registers we had when the varrays were last resized.  */
 static unsigned int cselib_nregs;
 
-/* Count values without known locations.  Whenever this grows too big, we
-   remove these useless values from the table.  */
+/* Count values without known locations, or with only locations that
+   wouldn't have been known except for debug insns.  Whenever this
+   grows too big, we remove these useless values from the table.
+
+   Counting values with only debug values is a bit tricky.  We don't
+   want to increment n_useless_values when we create a value for a
+   debug insn, for this would get n_useless_values out of sync, but we
+   want increment it if all locs in the list that were ever referenced
+   in nondebug insns are removed from the list.
+
+   In the general case, once we do that, we'd have to stop accepting
+   nondebug expressions in the loc list, to avoid having two values
+   equivalent that, without debug insns, would have been made into
+   separate values.  However, because debug insns never introduce
+   equivalences themselves (no assignments), the only means for
+   growing loc lists is through nondebug assignments.  If the locs
+   also happen to be referenced in debug insns, it will work just fine.
+
+   A consequence of this is that there's at most one debug-only loc in
+   each loc list.  If we keep it in the first entry, testing whether
+   we have a debug-only loc list takes O(1).
+
+   Furthermore, since any additional entry in a loc list containing a
+   debug loc would have to come from an assignment (nondebug) that
+   references both the initial debug loc and the newly-equivalent loc,
+   the initial debug loc would be promoted to a nondebug loc, and the
+   loc list would not contain debug locs any more.
+
+   So the only case we have to be careful with in order to keep
+   n_useless_values in sync between debug and nondebug compilations is
+   to avoid incrementing n_useless_values when removing the single loc
+   from a value that turns out to not appear outside debug values.  We
+   increment n_useless_debug_values instead, and leave such values
+   alone until, for other reasons, we garbage-collect useless
+   values.  */
 static int n_useless_values;
+static int n_useless_debug_values;
+
+/* Count values whose locs have been taken exclusively from debug
+   insns for the entire life of the value.  */
+static int n_debug_values;
 
 /* Number of useless values before we remove them from the hash table.  */
 #define MAX_USELESS_VALUES 32
@@ -188,9 +226,33 @@ new_elt_loc_list (struct elt_loc_list *n
   el->next = next;
   el->loc = loc;
   el->setting_insn = cselib_current_insn;
+  gcc_assert (!next || !next->setting_insn
+	      || !DEBUG_INSN_P (next->setting_insn));
+
+  /* If we're creating the first loc in a debug insn context, we've
+     just created a debug value.  Count it.  */
+  if (!next && cselib_current_insn && DEBUG_INSN_P (cselib_current_insn))
+    n_debug_values++;
+
   return el;
 }
 
+/* Promote loc L to a nondebug cselib_current_insn if L is marked as
+   originating from a debug insn, maintaining the debug values
+   count.  */
+
+static inline void
+promote_debug_loc (struct elt_loc_list *l)
+{
+  if (l->setting_insn && DEBUG_INSN_P (l->setting_insn)
+      && (!cselib_current_insn || !DEBUG_INSN_P (cselib_current_insn)))
+    {
+      n_debug_values--;
+      l->setting_insn = cselib_current_insn;
+      gcc_assert (!l->next);
+    }
+}
+
 /* The elt_list at *PL is no longer needed.  Unchain it and free its
    storage.  */
 
@@ -305,6 +367,8 @@ cselib_reset_table (unsigned int num)
     htab_empty (cselib_hash_table);
 
   n_useless_values = 0;
+  n_useless_debug_values = 0;
+  n_debug_values = 0;
 
   next_uid = num;
 
@@ -349,7 +413,10 @@ entry_and_rtx_equal_p (const void *entry
      so we need to do a comparison.  */
   for (l = v->locs; l; l = l->next)
     if (rtx_equal_for_cselib_p (l->loc, x))
-      return 1;
+      {
+	promote_debug_loc (l);
+	return 1;
+      }
 
   return 0;
 }
@@ -403,7 +470,8 @@ discard_useless_locs (void **x, void *in
 {
   cselib_val *v = (cselib_val *)*x;
   struct elt_loc_list **p = &v->locs;
-  int had_locs = v->locs != 0;
+  bool had_locs = v->locs != NULL;
+  rtx setting_insn = v->locs ? v->locs->setting_insn : NULL;
 
   while (*p)
     {
@@ -415,7 +483,10 @@ discard_useless_locs (void **x, void *in
 
   if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
     {
-      n_useless_values++;
+      if (setting_insn && DEBUG_INSN_P (setting_insn))
+	n_useless_debug_values++;
+      else
+	n_useless_values++;
       values_became_useless = 1;
     }
   return 1;
@@ -449,6 +520,7 @@ static void
 remove_useless_values (void)
 {
   cselib_val **p, *v;
+
   /* First pass: eliminate locations that reference the value.  That in
      turn can make more values useless.  */
   do
@@ -469,6 +541,10 @@ remove_useless_values (void)
       }
   *p = &dummy_val;
 
+  n_useless_values += n_useless_debug_values;
+  n_debug_values -= n_useless_debug_values;
+  n_useless_debug_values = 0;
+
   htab_traverse (cselib_hash_table, discard_useless_values, 0);
 
   gcc_assert (!n_useless_values);
@@ -947,7 +1023,10 @@ add_mem_for_addr (cselib_val *addr_elt, 
   for (l = mem_elt->locs; l; l = l->next)
     if (MEM_P (l->loc)
 	&& CSELIB_VAL_PTR (XEXP (l->loc, 0)) == addr_elt)
-      return;
+      {
+	promote_debug_loc (l);
+	return;
+      }
 
   addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt);
   mem_elt->locs
@@ -985,7 +1064,10 @@ cselib_lookup_mem (rtx x, int create)
   /* Find a value that describes a value of our mode at that address.  */
   for (l = addr->addr_list; l; l = l->next)
     if (GET_MODE (l->elt->val_rtx) == mode)
-      return l->elt;
+      {
+	promote_debug_loc (l->elt->locs);
+	return l->elt;
+      }
 
   if (! create)
     return 0;
@@ -1516,30 +1598,13 @@ cselib_subst_to_values (rtx x)
   return copy;
 }
 
-/* Log a lookup of X to the cselib table along with the result RET.  */
-
-static cselib_val *
-cselib_log_lookup (rtx x, cselib_val *ret)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fputs ("cselib lookup ", dump_file);
-      print_inline_rtx (dump_file, x, 2);
-      fprintf (dump_file, " => %u:%u\n",
-	       ret ? ret->uid : 0,
-	       ret ? ret->hash : 0);
-    }
-
-  return ret;
-}
-
 /* Look up the rtl expression X in our tables and return the value it has.
    If CREATE is zero, we return NULL if we don't know the value.  Otherwise,
    we create a new one if possible, using mode MODE if X doesn't have a mode
    (i.e. because it's a constant).  */
 
-cselib_val *
-cselib_lookup (rtx x, enum machine_mode mode, int create)
+static cselib_val *
+cselib_lookup_1 (rtx x, enum machine_mode mode, int create)
 {
   void **slot;
   cselib_val *e;
@@ -1561,10 +1626,13 @@ cselib_lookup (rtx x, enum machine_mode 
 	l = l->next;
       for (; l; l = l->next)
 	if (mode == GET_MODE (l->elt->val_rtx))
-	  return cselib_log_lookup (x, l->elt);
+	  {
+	    promote_debug_loc (l->elt->locs);
+	    return l->elt;
+	  }
 
       if (! create)
-	return cselib_log_lookup (x, 0);
+	return 0;
 
       if (i < FIRST_PSEUDO_REGISTER)
 	{
@@ -1587,25 +1655,25 @@ cselib_lookup (rtx x, enum machine_mode 
       REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
       slot = htab_find_slot_with_hash (cselib_hash_table, x, e->hash, INSERT);
       *slot = e;
-      return cselib_log_lookup (x, e);
+      return e;
     }
 
   if (MEM_P (x))
-    return cselib_log_lookup (x, cselib_lookup_mem (x, create));
+    return cselib_lookup_mem (x, create);
 
   hashval = cselib_hash_rtx (x, create);
   /* Can't even create if hashing is not possible.  */
   if (! hashval)
-    return cselib_log_lookup (x, 0);
+    return 0;
 
   slot = htab_find_slot_with_hash (cselib_hash_table, wrap_constant (mode, x),
 				   hashval, create ? INSERT : NO_INSERT);
   if (slot == 0)
-    return cselib_log_lookup (x, 0);
+    return 0;
 
   e = (cselib_val *) *slot;
   if (e)
-    return cselib_log_lookup (x, e);
+    return e;
 
   e = new_cselib_val (hashval, mode, x);
 
@@ -1614,7 +1682,51 @@ cselib_lookup (rtx x, enum machine_mode 
      cselib_subst_to_values will need to do lookups.  */
   *slot = (void *) e;
   e->locs = new_elt_loc_list (e->locs, cselib_subst_to_values (x));
-  return cselib_log_lookup (x, e);
+  return e;
+}
+
+/* Wrapper for cselib_lookup, that indicates X is in INSN.  */
+
+cselib_val *
+cselib_lookup_from_insn (rtx x, enum machine_mode mode,
+			 int create, rtx insn)
+{
+  cselib_val *ret;
+
+  gcc_assert (!cselib_current_insn);
+  cselib_current_insn = insn;
+
+  ret = cselib_lookup (x, mode, create);
+
+  cselib_current_insn = NULL;
+
+  return ret;
+}
+
+/* Wrapper for cselib_lookup_1, that logs the lookup result and
+   maintains invariants related with debug insns.  */
+
+cselib_val *
+cselib_lookup (rtx x, enum machine_mode mode, int create)
+{
+  cselib_val *ret = cselib_lookup_1 (x, mode, create);
+
+  /* ??? Should we return NULL if we're not to create an entry, the
+     found loc is a debug loc and cselib_current_insn is not DEBUG?
+     If so, we should also avoid converting val to non-DEBUG; probably
+     easiest setting cselib_current_insn to NULL before the call
+     above.  */
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fputs ("cselib lookup ", dump_file);
+      print_inline_rtx (dump_file, x, 2);
+      fprintf (dump_file, " => %u:%u\n",
+	       ret ? ret->uid : 0,
+	       ret ? ret->hash : 0);
+    }
+
+  return ret;
 }
 
 /* Invalidate any entries in reg_values that overlap REGNO.  This is called
@@ -1663,6 +1775,8 @@ cselib_invalidate_regno (unsigned int re
       while (*l)
 	{
 	  cselib_val *v = (*l)->elt;
+	  bool had_locs;
+	  rtx setting_insn;
 	  struct elt_loc_list **p;
 	  unsigned int this_last = i;
 
@@ -1689,6 +1803,9 @@ cselib_invalidate_regno (unsigned int re
 	  else
 	    unchain_one_elt_list (l);
 
+	  had_locs = v->locs != NULL;
+	  setting_insn = v->locs ? v->locs->setting_insn : NULL;
+
 	  /* Now, we clear the mapping from value to reg.  It must exist, so
 	     this code will crash intentionally if it doesn't.  */
 	  for (p = &v->locs; ; p = &(*p)->next)
@@ -1701,8 +1818,14 @@ cselib_invalidate_regno (unsigned int re
 		  break;
 		}
 	    }
-	  if (v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
-	    n_useless_values++;
+
+	  if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
+	    {
+	      if (setting_insn && DEBUG_INSN_P (setting_insn))
+		n_useless_debug_values++;
+	      else
+		n_useless_values++;
+	    }
 	}
     }
 }
@@ -1740,7 +1863,8 @@ cselib_invalidate_mem (rtx mem_rtx)
     {
       bool has_mem = false;
       struct elt_loc_list **p = &v->locs;
-      int had_locs = v->locs != 0;
+      bool had_locs = v->locs != NULL;
+      rtx setting_insn = v->locs ? v->locs->setting_insn : NULL;
 
       while (*p)
 	{
@@ -1785,7 +1909,12 @@ cselib_invalidate_mem (rtx mem_rtx)
 	}
 
       if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
-	n_useless_values++;
+	{
+	  if (setting_insn && DEBUG_INSN_P (setting_insn))
+	    n_useless_debug_values++;
+	  else
+	    n_useless_values++;
+	}
 
       next = v->next_containing_mem;
       if (has_mem)
@@ -2079,7 +2208,10 @@ cselib_process_insn (rtx insn)
       /* remove_useless_values is linear in the hash table size.  Avoid
          quadratic behavior for very large hashtables with very few
 	 useless elements.  */
-      && (unsigned int)n_useless_values > cselib_hash_table->n_elements / 4)
+      && ((unsigned int)n_useless_values
+	  > (cselib_hash_table->n_elements
+	     - cselib_hash_table->n_deleted
+	     - n_debug_values) / 4))
     remove_useless_values ();
 }
 
@@ -2143,6 +2275,8 @@ cselib_finish (void)
   used_regs = 0;
   cselib_hash_table = 0;
   n_useless_values = 0;
+  n_useless_debug_values = 0;
+  n_debug_values = 0;
   next_uid = 0;
 }
 
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2010-03-30 04:49:13.000000000 -0300
+++ gcc/sched-deps.c	2010-03-30 04:49:46.000000000 -0300
@@ -2286,7 +2286,7 @@ sched_analyze_1 (struct deps *deps, rtx 
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
 	  t = shallow_copy_rtx (dest);
-	  cselib_lookup (XEXP (t, 0), address_mode, 1);
+	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
 	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
 	}
       t = canon_rtx (t);
@@ -2443,7 +2443,7 @@ sched_analyze_2 (struct deps *deps, rtx 
 	      = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
 	    t = shallow_copy_rtx (t);
-	    cselib_lookup (XEXP (t, 0), address_mode, 1);
+	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, insn);
 	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
 	  }
 
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2010-03-30 04:49:14.000000000 -0300
+++ gcc/cselib.h	2010-03-30 04:51:05.000000000 -0300
@@ -77,6 +77,7 @@ extern void (*cselib_record_sets_hook) (
 					int n_sets);
 
 extern cselib_val *cselib_lookup (rtx, enum machine_mode, int);
+extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode, int, rtx);
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
for  gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	PR debug/42977
	* cselib.c (n_useless_values): Document handling of debug locs.
	(n_useless_debug_values, n_debug_values): New variables.
	(new_elt_loc_list): Don't add to debug values, keep count.
	(promote_debug_loc): New.
	(cselib_reset_table): Zero new variables.
	(entry_and_rtx_equal_p): Promote debug locs.
	(discard_useless_locs): Increment n_useless_debug_values for
	debug values.
	(remove_useless_values): Adjust n_useless_values and n_debug_values
	with n_useless_debug_values.
	(add_mem_for_addr): Promote debug locs.
	(cselib_lookup_mem): Likewise.
	(cselib_lookup_addr): Renamed to...
	(cselib_lookup_addr_1): ... this.  Promote debug locs.
	Don't call...
	(cselib_log_lookup): ... this.  Turn into...
	(cselib_lookup_addr): ... new wrapper.
	(cselib_lookup_from_insn): New.
	(cselib_invalidate_regno): Increment n_useless_debug_values for
	debug values.
	(cselib_invalidate_mem): Likewise.
	(cselib_process_insn): Take n_deleted and n_debug_values into
	account to guard remove_useless_value call.
	(cselib_finish): Zero n_useless_debug_values.
	* cselib.h (cselib_lookup_from_insn): Declare.
	* sched-deps.c (sched_analyze_1): Use cselib_lookup_from_insn.
	(sched_analyze_2): Likewise.

Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c.orig	2010-03-30 04:47:03.000000000 -0300
+++ gcc/cselib.c	2010-03-30 04:47:19.000000000 -0300
@@ -99,9 +99,47 @@ static unsigned int next_uid;
 /* The number of registers we had when the varrays were last resized.  */
 static unsigned int cselib_nregs;
 
-/* Count values without known locations.  Whenever this grows too big, we
-   remove these useless values from the table.  */
+/* Count values without known locations, or with only locations that
+   wouldn't have been known except for debug insns.  Whenever this
+   grows too big, we remove these useless values from the table.
+
+   Counting values with only debug values is a bit tricky.  We don't
+   want to increment n_useless_values when we create a value for a
+   debug insn, for this would get n_useless_values out of sync, but we
+   want increment it if all locs in the list that were ever referenced
+   in nondebug insns are removed from the list.
+
+   In the general case, once we do that, we'd have to stop accepting
+   nondebug expressions in the loc list, to avoid having two values
+   equivalent that, without debug insns, would have been made into
+   separate values.  However, because debug insns never introduce
+   equivalences themselves (no assignments), the only means for
+   growing loc lists is through nondebug assignments.  If the locs
+   also happen to be referenced in debug insns, it will work just fine.
+
+   A consequence of this is that there's at most one debug-only loc in
+   each loc list.  If we keep it in the first entry, testing whether
+   we have a debug-only loc list takes O(1).
+
+   Furthermore, since any additional entry in a loc list containing a
+   debug loc would have to come from an assignment (nondebug) that
+   references both the initial debug loc and the newly-equivalent loc,
+   the initial debug loc would be promoted to a nondebug loc, and the
+   loc list would not contain debug locs any more.
+
+   So the only case we have to be careful with in order to keep
+   n_useless_values in sync between debug and nondebug compilations is
+   to avoid incrementing n_useless_values when removing the single loc
+   from a value that turns out to not appear outside debug values.  We
+   increment n_useless_debug_values instead, and leave such values
+   alone until, for other reasons, we garbage-collect useless
+   values.  */
 static int n_useless_values;
+static int n_useless_debug_values;
+
+/* Count values whose locs have been taken exclusively from debug
+   insns for the entire life of the value.  */
+static int n_debug_values;
 
 /* Number of useless values before we remove them from the hash table.  */
 #define MAX_USELESS_VALUES 32
@@ -190,9 +228,33 @@ new_elt_loc_list (struct elt_loc_list *n
   el->next = next;
   el->loc = loc;
   el->setting_insn = cselib_current_insn;
+  gcc_assert (!next || !next->setting_insn
+	      || !DEBUG_INSN_P (next->setting_insn));
+
+  /* If we're creating the first loc in a debug insn context, we've
+     just created a debug value.  Count it.  */
+  if (!next && cselib_current_insn && DEBUG_INSN_P (cselib_current_insn))
+    n_debug_values++;
+
   return el;
 }
 
+/* Promote loc L to a nondebug cselib_current_insn if L is marked as
+   originating from a debug insn, maintaining the debug values
+   count.  */
+
+static inline void
+promote_debug_loc (struct elt_loc_list *l)
+{
+  if (l->setting_insn && DEBUG_INSN_P (l->setting_insn)
+      && (!cselib_current_insn || !DEBUG_INSN_P (cselib_current_insn)))
+    {
+      n_debug_values--;
+      l->setting_insn = cselib_current_insn;
+      gcc_assert (!l->next);
+    }
+}
+
 /* The elt_list at *PL is no longer needed.  Unchain it and free its
    storage.  */
 
@@ -307,6 +369,8 @@ cselib_reset_table (unsigned int num)
     htab_empty (cselib_hash_table);
 
   n_useless_values = 0;
+  n_useless_debug_values = 0;
+  n_debug_values = 0;
 
   next_uid = num;
 
@@ -371,7 +435,10 @@ entry_and_rtx_equal_p (const void *entry
      so we need to do a comparison.  */
   for (l = v->locs; l; l = l->next)
     if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode))
-      return 1;
+      {
+	promote_debug_loc (l);
+	return 1;
+      }
 
   return 0;
 }
@@ -425,7 +492,8 @@ discard_useless_locs (void **x, void *in
 {
   cselib_val *v = (cselib_val *)*x;
   struct elt_loc_list **p = &v->locs;
-  int had_locs = v->locs != 0;
+  bool had_locs = v->locs != NULL;
+  rtx setting_insn = v->locs ? v->locs->setting_insn : NULL;
 
   while (*p)
     {
@@ -437,7 +505,10 @@ discard_useless_locs (void **x, void *in
 
   if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
     {
-      n_useless_values++;
+      if (setting_insn && DEBUG_INSN_P (setting_insn))
+	n_useless_debug_values++;
+      else
+	n_useless_values++;
       values_became_useless = 1;
     }
   return 1;
@@ -471,6 +542,7 @@ static void
 remove_useless_values (void)
 {
   cselib_val **p, *v;
+
   /* First pass: eliminate locations that reference the value.  That in
      turn can make more values useless.  */
   do
@@ -491,6 +563,10 @@ remove_useless_values (void)
       }
   *p = &dummy_val;
 
+  n_useless_values += n_useless_debug_values;
+  n_debug_values -= n_useless_debug_values;
+  n_useless_debug_values = 0;
+
   htab_traverse (cselib_hash_table, discard_useless_values, 0);
 
   gcc_assert (!n_useless_values);
@@ -1063,7 +1139,10 @@ add_mem_for_addr (cselib_val *addr_elt, 
   for (l = mem_elt->locs; l; l = l->next)
     if (MEM_P (l->loc)
 	&& CSELIB_VAL_PTR (XEXP (l->loc, 0)) == addr_elt)
-      return;
+      {
+	promote_debug_loc (l);
+	return;
+      }
 
   addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt);
   mem_elt->locs
@@ -1104,7 +1183,10 @@ cselib_lookup_mem (rtx x, int create)
   /* Find a value that describes a value of our mode at that address.  */
   for (l = addr->addr_list; l; l = l->next)
     if (GET_MODE (l->elt->val_rtx) == mode)
-      return l->elt;
+      {
+	promote_debug_loc (l->elt->locs);
+	return l->elt;
+      }
 
   if (! create)
     return 0;
@@ -1657,23 +1739,6 @@ cselib_subst_to_values_addr (rtx x, enum
   return copy;
 }
 
-/* Log a lookup of X to the cselib table along with the result RET.  */
-
-static cselib_val *
-cselib_log_lookup (rtx x, cselib_val *ret)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fputs ("cselib lookup ", dump_file);
-      print_inline_rtx (dump_file, x, 2);
-      fprintf (dump_file, " => %u:%u\n",
-	       ret ? ret->uid : 0,
-	       ret ? ret->hash : 0);
-    }
-
-  return ret;
-}
-
 /* Look up the rtl expression X in our tables and return the value it
    has.  If CREATE is zero, we return NULL if we don't know the value.
    Otherwise, we create a new one if possible, using mode MODE if X
@@ -1681,9 +1746,9 @@ cselib_log_lookup (rtx x, cselib_val *re
    of an address, MEMMODE should be the mode of the enclosing MEM if
    we're tracking autoinc expressions.  */
 
-cselib_val *
-cselib_lookup_addr (rtx x, enum machine_mode mode,
-		    int create, enum machine_mode memmode)
+static cselib_val *
+cselib_lookup_addr_1 (rtx x, enum machine_mode mode,
+		      int create, enum machine_mode memmode)
 {
   void **slot;
   cselib_val *e;
@@ -1705,10 +1770,13 @@ cselib_lookup_addr (rtx x, enum machine_
 	l = l->next;
       for (; l; l = l->next)
 	if (mode == GET_MODE (l->elt->val_rtx))
-	  return cselib_log_lookup (x, l->elt);
+	  {
+	    promote_debug_loc (l->elt->locs);
+	    return l->elt;
+	  }
 
       if (! create)
-	return cselib_log_lookup (x, 0);
+	return 0;
 
       if (i < FIRST_PSEUDO_REGISTER)
 	{
@@ -1731,25 +1799,25 @@ cselib_lookup_addr (rtx x, enum machine_
       REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e);
       slot = cselib_find_slot (x, e->hash, INSERT, memmode);
       *slot = e;
-      return cselib_log_lookup (x, e);
+      return e;
     }
 
   if (MEM_P (x))
-    return cselib_log_lookup (x, cselib_lookup_mem (x, create));
+    return cselib_lookup_mem (x, create);
 
   hashval = cselib_hash_rtx (x, create, memmode);
   /* Can't even create if hashing is not possible.  */
   if (! hashval)
-    return cselib_log_lookup (x, 0);
+    return 0;
 
   slot = cselib_find_slot (wrap_constant (mode, x), hashval,
 			   create ? INSERT : NO_INSERT, memmode);
   if (slot == 0)
-    return cselib_log_lookup (x, 0);
+    return 0;
 
   e = (cselib_val *) *slot;
   if (e)
-    return cselib_log_lookup (x, e);
+    return e;
 
   e = new_cselib_val (hashval, mode, x);
 
@@ -1759,7 +1827,52 @@ cselib_lookup_addr (rtx x, enum machine_
   *slot = (void *) e;
   e->locs = new_elt_loc_list (e->locs,
 			      cselib_subst_to_values_addr (x, memmode));
-  return cselib_log_lookup (x, e);
+  return e;
+}
+
+/* Wrapper for cselib_lookup_addr, that indicates X is in INSN.  */
+
+cselib_val *
+cselib_lookup_from_insn (rtx x, enum machine_mode mode,
+			 int create, enum machine_mode memmode, rtx insn)
+{
+  cselib_val *ret;
+
+  gcc_assert (!cselib_current_insn);
+  cselib_current_insn = insn;
+
+  ret = cselib_lookup_addr (x, mode, create, memmode);
+
+  cselib_current_insn = NULL;
+
+  return ret;
+}
+
+/* Wrapper for cselib_lookup_addr_1, that logs the lookup result and
+   maintains invariants related with debug insns.  */
+
+cselib_val *
+cselib_lookup_addr (rtx x, enum machine_mode mode,
+		    int create, enum machine_mode memmode)
+{
+  cselib_val *ret = cselib_lookup_addr_1 (x, mode, create, memmode);
+
+  /* ??? Should we return NULL if we're not to create an entry, the
+     found loc is a debug loc and cselib_current_insn is not DEBUG?
+     If so, we should also avoid converting val to non-DEBUG; probably
+     easiest setting cselib_current_insn to NULL before the call
+     above.  */
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fputs ("cselib lookup ", dump_file);
+      print_inline_rtx (dump_file, x, 2);
+      fprintf (dump_file, " => %u:%u\n",
+	       ret ? ret->uid : 0,
+	       ret ? ret->hash : 0);
+    }
+
+  return ret;
 }
 
 /* Invalidate any entries in reg_values that overlap REGNO.  This is called
@@ -1808,6 +1921,8 @@ cselib_invalidate_regno (unsigned int re
       while (*l)
 	{
 	  cselib_val *v = (*l)->elt;
+	  bool had_locs;
+	  rtx setting_insn;
 	  struct elt_loc_list **p;
 	  unsigned int this_last = i;
 
@@ -1834,6 +1949,9 @@ cselib_invalidate_regno (unsigned int re
 	  else
 	    unchain_one_elt_list (l);
 
+	  had_locs = v->locs != NULL;
+	  setting_insn = v->locs ? v->locs->setting_insn : NULL;
+
 	  /* Now, we clear the mapping from value to reg.  It must exist, so
 	     this code will crash intentionally if it doesn't.  */
 	  for (p = &v->locs; ; p = &(*p)->next)
@@ -1846,8 +1964,14 @@ cselib_invalidate_regno (unsigned int re
 		  break;
 		}
 	    }
-	  if (v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
-	    n_useless_values++;
+
+	  if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
+	    {
+	      if (setting_insn && DEBUG_INSN_P (setting_insn))
+		n_useless_debug_values++;
+	      else
+		n_useless_values++;
+	    }
 	}
     }
 }
@@ -1885,7 +2009,8 @@ cselib_invalidate_mem (rtx mem_rtx)
     {
       bool has_mem = false;
       struct elt_loc_list **p = &v->locs;
-      int had_locs = v->locs != 0;
+      bool had_locs = v->locs != NULL;
+      rtx setting_insn = v->locs ? v->locs->setting_insn : NULL;
 
       while (*p)
 	{
@@ -1930,7 +2055,12 @@ cselib_invalidate_mem (rtx mem_rtx)
 	}
 
       if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
-	n_useless_values++;
+	{
+	  if (setting_insn && DEBUG_INSN_P (setting_insn))
+	    n_useless_debug_values++;
+	  else
+	    n_useless_values++;
+	}
 
       next = v->next_containing_mem;
       if (has_mem)
@@ -2264,7 +2394,10 @@ cselib_process_insn (rtx insn)
       /* remove_useless_values is linear in the hash table size.  Avoid
          quadratic behavior for very large hashtables with very few
 	 useless elements.  */
-      && (unsigned int)n_useless_values > cselib_hash_table->n_elements / 4)
+      && ((unsigned int)n_useless_values
+	  > (cselib_hash_table->n_elements
+	     - cselib_hash_table->n_deleted
+	     - n_debug_values) / 4))
     remove_useless_values ();
 }
 
@@ -2329,6 +2462,8 @@ cselib_finish (void)
   used_regs = 0;
   cselib_hash_table = 0;
   n_useless_values = 0;
+  n_useless_debug_values = 0;
+  n_debug_values = 0;
   next_uid = 0;
 }
 
Index: gcc/cselib.h
===================================================================
--- gcc/cselib.h.orig	2010-03-30 04:47:03.000000000 -0300
+++ gcc/cselib.h	2010-03-30 04:47:03.000000000 -0300
@@ -81,6 +81,8 @@ extern cselib_val *cselib_lookup_addr (r
 				       int, enum machine_mode);
 #define cselib_lookup(x, mode, create) \
   (cselib_lookup_addr (x, mode, create, VOIDmode))
+extern cselib_val *cselib_lookup_from_insn (rtx, enum machine_mode,
+					    int, enum machine_mode, rtx);
 extern void cselib_init (int);
 extern void cselib_clear_table (void);
 extern void cselib_finish (void);
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2010-03-30 04:45:35.000000000 -0300
+++ gcc/sched-deps.c	2010-03-30 04:47:04.000000000 -0300
@@ -2286,7 +2286,8 @@ sched_analyze_1 (struct deps *deps, rtx 
 	    = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
 
 	  t = shallow_copy_rtx (dest);
-	  cselib_lookup (XEXP (t, 0), address_mode, 1);
+	  cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				   GET_MODE (dest), insn);
 	  XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
 	}
       t = canon_rtx (t);
@@ -2443,7 +2444,8 @@ sched_analyze_2 (struct deps *deps, rtx 
 	      = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
 	    t = shallow_copy_rtx (t);
-	    cselib_lookup (XEXP (t, 0), address_mode, 1);
+	    cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+				     GET_MODE (x), insn);
 	    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
 	  }
 
-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

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