Blame SOURCES/gcc34-var-tracking-coalesce.patch

6fdc0f
2006-12-08  Jakub Jelinek  <jakub@redhat.com>
6fdc0f
6fdc0f
	* g++.dg/debug/vartrack1.C: New test.
6fdc0f
6fdc0f
2006-09-11  Alexandre Oliva  <aoliva@redhat.com>
6fdc0f
6fdc0f
	PR target/28672
6fdc0f
	* var-tracking.c (dump_dataflow_set): Start dumping at
6fdc0f
	register zero.
6fdc0f
	(clobber_variable_part): Kill only the variable part in
6fdc0f
	registers holding it, leaving other variables alone.
6fdc0f
6fdc0f
2006-08-09  Alexandre Oliva  <aoliva@redhat.com>
6fdc0f
6fdc0f
	* var-tracking.c (enum micro_operation_type): Add MO_COPY.
6fdc0f
	(var_debug_decl): New function.
6fdc0f
	(var_reg_set): Follow debug decl link.  Add location even if
6fdc0f
	reg is already known to hold some other variable.
6fdc0f
	(var_mem_set): Follow debug decl link.
6fdc0f
	(var_reg_delete_and_set, var_mem_delete_and_set): Follow debug
6fdc0f
	decl link.  Delete other known locations of the variable part
6fdc0f
	if requested.
6fdc0f
	(var_reg_delete, var_mem_delete): Delete other known locations
6fdc0f
	of the variable part if requested.
6fdc0f
	(same_variable_part_p): New function.
6fdc0f
	(add_stores): Select MO_COPY when appropriate.
6fdc0f
	(vt_initialize): Handle it.
6fdc0f
	(compute_bb_dataflow, emit_notes_in_bb): Likewise.  Delete
6fdc0f
	known locations for MO_SET and MO_CLOBBER.
6fdc0f
	(find_variable_location_part): New function.
6fdc0f
	(set_variable_part, delete_variable_part): Use it.
6fdc0f
	(clobber_variable_part): New function.
6fdc0f
6fdc0f
--- gcc/var-tracking.c.orig	2006-12-08 02:14:36.000000000 -0200
6fdc0f
+++ gcc/var-tracking.c	2006-12-08 02:14:51.000000000 -0200
6fdc0f
@@ -112,6 +112,8 @@ enum micro_operation_type
6fdc0f
   MO_USE_NO_VAR,/* Use location which is not associated with a variable
6fdc0f
 		   or the variable is not trackable.  */
6fdc0f
   MO_SET,	/* Set location.  */
6fdc0f
+  MO_COPY,	/* Copy the same portion of a variable from one
6fdc0f
+		   loation to another.  */
6fdc0f
   MO_CLOBBER,	/* Clobber location.  */
6fdc0f
   MO_CALL,	/* Call insn.  */
6fdc0f
   MO_ADJUST	/* Adjust stack pointer.  */
6fdc0f
@@ -293,13 +295,14 @@ static void vars_clear (htab_t);
6fdc0f
 static variable unshare_variable (dataflow_set *set, variable var);
6fdc0f
 static int vars_copy_1 (void **, void *);
6fdc0f
 static void vars_copy (htab_t, htab_t);
6fdc0f
+static tree var_debug_decl (tree);
6fdc0f
 static void var_reg_set (dataflow_set *, rtx);
6fdc0f
-static void var_reg_delete_and_set (dataflow_set *, rtx);
6fdc0f
-static void var_reg_delete (dataflow_set *, rtx);
6fdc0f
+static void var_reg_delete_and_set (dataflow_set *, rtx, bool);
6fdc0f
+static void var_reg_delete (dataflow_set *, rtx, bool);
6fdc0f
 static void var_regno_delete (dataflow_set *, int);
6fdc0f
 static void var_mem_set (dataflow_set *, rtx);
6fdc0f
-static void var_mem_delete_and_set (dataflow_set *, rtx);
6fdc0f
-static void var_mem_delete (dataflow_set *, rtx);
6fdc0f
+static void var_mem_delete_and_set (dataflow_set *, rtx, bool);
6fdc0f
+static void var_mem_delete (dataflow_set *, rtx, bool);
6fdc0f
 
6fdc0f
 static void dataflow_set_init (dataflow_set *, int);
6fdc0f
 static void dataflow_set_clear (dataflow_set *);
6fdc0f
@@ -316,6 +319,7 @@ static void dataflow_set_destroy (datafl
6fdc0f
 
6fdc0f
 static bool contains_symbol_ref (rtx);
6fdc0f
 static bool track_expr_p (tree);
6fdc0f
+static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
6fdc0f
 static int count_uses (rtx *, void *);
6fdc0f
 static void count_uses_1 (rtx *, void *);
6fdc0f
 static void count_stores (rtx, rtx, void *);
6fdc0f
@@ -333,6 +337,7 @@ static void dump_dataflow_sets (void);
6fdc0f
 
6fdc0f
 static void variable_was_changed (variable, htab_t);
6fdc0f
 static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
6fdc0f
+static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
6fdc0f
 static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
6fdc0f
 static int emit_note_insn_var_location (void **, void *);
6fdc0f
 static void emit_notes_for_changes (rtx, enum emit_note_where);
6fdc0f
@@ -794,6 +799,14 @@ vars_copy (htab_t dst, htab_t src)
6fdc0f
   htab_traverse (src, vars_copy_1, dst);
6fdc0f
 }
6fdc0f
 
6fdc0f
+/* Map a decl to its main debug decl.  */
6fdc0f
+
6fdc0f
+static inline tree
6fdc0f
+var_debug_decl (tree decl)
6fdc0f
+{
6fdc0f
+  return decl;
6fdc0f
+}
6fdc0f
+
6fdc0f
 /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
6fdc0f
 
6fdc0f
 static void
6fdc0f
@@ -801,23 +814,35 @@ var_reg_set (dataflow_set *set, rtx loc)
6fdc0f
 {
6fdc0f
   tree decl = REG_EXPR (loc);
6fdc0f
   HOST_WIDE_INT offset = REG_OFFSET (loc);
6fdc0f
+  attrs node;
6fdc0f
+
6fdc0f
+  decl = var_debug_decl (decl);
6fdc0f
 
6fdc0f
-  if (set->regs[REGNO (loc)] == NULL)
6fdc0f
+  for (node = set->regs[REGNO (loc)]; node; node = node->next)
6fdc0f
+    if (node->decl == decl && node->offset == offset)
6fdc0f
+      break;
6fdc0f
+  if (!node)
6fdc0f
     attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
6fdc0f
   set_variable_part (set, loc, decl, offset);
6fdc0f
 }
6fdc0f
 
6fdc0f
-/* Delete current content of register LOC in dataflow set SET
6fdc0f
-   and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
6fdc0f
+/* Delete current content of register LOC in dataflow set SET and set
6fdc0f
+   the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  If
6fdc0f
+   MODIFY is true, any other live copies of the same variable part are
6fdc0f
+   also deleted from the dataflow set, otherwise the variable part is
6fdc0f
+   assumed to be copied from another location holding the same
6fdc0f
+   part.  */
6fdc0f
 
6fdc0f
 static void
6fdc0f
-var_reg_delete_and_set (dataflow_set *set, rtx loc)
6fdc0f
+var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
6fdc0f
 {
6fdc0f
   tree decl = REG_EXPR (loc);
6fdc0f
   HOST_WIDE_INT offset = REG_OFFSET (loc);
6fdc0f
   attrs node, next;
6fdc0f
   attrs *nextp;
6fdc0f
 
6fdc0f
+  decl = var_debug_decl (decl);
6fdc0f
+
6fdc0f
   nextp = &set->regs[REGNO (loc)];
6fdc0f
   for (node = *nextp; node; node = next)
6fdc0f
     {
6fdc0f
@@ -834,17 +859,31 @@ var_reg_delete_and_set (dataflow_set *se
6fdc0f
 	  nextp = &node->next;
6fdc0f
 	}
6fdc0f
     }
6fdc0f
+  if (modify)
6fdc0f
+    clobber_variable_part (set, loc, decl, offset);
6fdc0f
   var_reg_set (set, loc);
6fdc0f
 }
6fdc0f
 
6fdc0f
-/* Delete current content of register LOC in dataflow set SET.  */
6fdc0f
+/* Delete current content of register LOC in dataflow set SET.  If
6fdc0f
+   CLOBBER is true, also delete any other live copies of the same
6fdc0f
+   variable part.  */
6fdc0f
 
6fdc0f
 static void
6fdc0f
-var_reg_delete (dataflow_set *set, rtx loc)
6fdc0f
+var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
6fdc0f
 {
6fdc0f
   attrs *reg = &set->regs[REGNO (loc)];
6fdc0f
   attrs node, next;
6fdc0f
 
6fdc0f
+  if (clobber)
6fdc0f
+    {
6fdc0f
+      tree decl = REG_EXPR (loc);
6fdc0f
+      HOST_WIDE_INT offset = REG_OFFSET (loc);
6fdc0f
+
6fdc0f
+      decl = var_debug_decl (decl);
6fdc0f
+
6fdc0f
+      clobber_variable_part (set, NULL, decl, offset);
6fdc0f
+    }
6fdc0f
+
6fdc0f
   for (node = *reg; node; node = next)
6fdc0f
     {
6fdc0f
       next = node->next;
6fdc0f
@@ -881,28 +920,44 @@ var_mem_set (dataflow_set *set, rtx loc)
6fdc0f
   tree decl = MEM_EXPR (loc);
6fdc0f
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
6fdc0f
 
6fdc0f
+  decl = var_debug_decl (decl);
6fdc0f
+
6fdc0f
   set_variable_part (set, loc, decl, offset);
6fdc0f
 }
6fdc0f
 
6fdc0f
-/* Delete and set the location part of variable MEM_EXPR (LOC)
6fdc0f
-   in dataflow set SET to LOC.
6fdc0f
+/* Delete and set the location part of variable MEM_EXPR (LOC) in
6fdc0f
+   dataflow set SET to LOC.  If MODIFY is true, any other live copies
6fdc0f
+   of the same variable part are also deleted from the dataflow set,
6fdc0f
+   otherwise the variable part is assumed to be copied from another
6fdc0f
+   location holding the same part.
6fdc0f
    Adjust the address first if it is stack pointer based.  */
6fdc0f
 
6fdc0f
 static void
6fdc0f
-var_mem_delete_and_set (dataflow_set *set, rtx loc)
6fdc0f
+var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify)
6fdc0f
 {
6fdc0f
+  tree decl = MEM_EXPR (loc);
6fdc0f
+  HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
6fdc0f
+
6fdc0f
+  decl = var_debug_decl (decl);
6fdc0f
+
6fdc0f
+  if (modify)
6fdc0f
+    clobber_variable_part (set, NULL, decl, offset);
6fdc0f
   var_mem_set (set, loc);
6fdc0f
 }
6fdc0f
 
6fdc0f
-/* Delete the location part LOC from dataflow set SET.
6fdc0f
+/* Delete the location part LOC from dataflow set SET.  If CLOBBER is
6fdc0f
+   true, also delete any other live copies of the same variable part.
6fdc0f
    Adjust the address first if it is stack pointer based.  */
6fdc0f
 
6fdc0f
 static void
6fdc0f
-var_mem_delete (dataflow_set *set, rtx loc)
6fdc0f
+var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
6fdc0f
 {
6fdc0f
   tree decl = MEM_EXPR (loc);
6fdc0f
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
6fdc0f
 
6fdc0f
+  decl = var_debug_decl (decl);
6fdc0f
+  if (clobber)
6fdc0f
+    clobber_variable_part (set, NULL, decl, offset);
6fdc0f
   delete_variable_part (set, loc, decl, offset);
6fdc0f
 }
6fdc0f
 
6fdc0f
@@ -1476,6 +1531,41 @@ track_expr_p (tree expr)
6fdc0f
   return 1;
6fdc0f
 }
6fdc0f
 
6fdc0f
+/* Determine whether a given LOC refers to the same variable part as
6fdc0f
+   EXPR+OFFSET.  */
6fdc0f
+
6fdc0f
+static bool
6fdc0f
+same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
6fdc0f
+{
6fdc0f
+  tree expr2;
6fdc0f
+  HOST_WIDE_INT offset2;
6fdc0f
+
6fdc0f
+  if (! DECL_P (expr))
6fdc0f
+    return false;
6fdc0f
+
6fdc0f
+  if (GET_CODE (loc) == REG)
6fdc0f
+    {
6fdc0f
+      expr2 = REG_EXPR (loc);
6fdc0f
+      offset2 = REG_OFFSET (loc);
6fdc0f
+    }
6fdc0f
+  else if (GET_CODE (loc) == MEM)
6fdc0f
+    {
6fdc0f
+      expr2 = MEM_EXPR (loc);
6fdc0f
+      offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
6fdc0f
+    }
6fdc0f
+  else
6fdc0f
+    return false;
6fdc0f
+
6fdc0f
+  if (! expr2 || ! DECL_P (expr2))
6fdc0f
+    return false;
6fdc0f
+
6fdc0f
+  expr = var_debug_decl (expr);
6fdc0f
+  expr2 = var_debug_decl (expr2);
6fdc0f
+
6fdc0f
+  return (expr == expr2 && offset == offset2);
6fdc0f
+}
6fdc0f
+
6fdc0f
+
6fdc0f
 /* Count uses (register and memory references) LOC which will be tracked.
6fdc0f
    INSN is instruction which the LOC is part of.  */
6fdc0f
 
6fdc0f
@@ -1570,9 +1660,18 @@ add_stores (rtx loc, rtx expr, void *ins
6fdc0f
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
6fdc0f
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
6fdc0f
 
6fdc0f
-      mo->type = ((GET_CODE (expr) != CLOBBER && REG_EXPR (loc)
6fdc0f
-		   && track_expr_p (REG_EXPR (loc)))
6fdc0f
-		  ? MO_SET : MO_CLOBBER);
6fdc0f
+      if (GET_CODE (expr) == CLOBBER
6fdc0f
+	  || ! REG_EXPR (loc)
6fdc0f
+	  || ! track_expr_p (REG_EXPR (loc)))
6fdc0f
+	mo->type = MO_CLOBBER;
6fdc0f
+      else if (GET_CODE (expr) == SET
6fdc0f
+	       && SET_DEST (expr) == loc
6fdc0f
+	       && same_variable_part_p (SET_SRC (expr),
6fdc0f
+					REG_EXPR (loc),
6fdc0f
+					REG_OFFSET (loc)))
6fdc0f
+	mo->type = MO_COPY;
6fdc0f
+      else
6fdc0f
+	mo->type = MO_SET;
6fdc0f
       mo->u.loc = loc;
6fdc0f
       mo->insn = NEXT_INSN ((rtx) insn);
6fdc0f
     }
6fdc0f
@@ -1583,7 +1682,17 @@ add_stores (rtx loc, rtx expr, void *ins
6fdc0f
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
6fdc0f
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
6fdc0f
 
6fdc0f
-      mo->type = GET_CODE (expr) == CLOBBER ? MO_CLOBBER : MO_SET;
6fdc0f
+      if (GET_CODE (expr) == CLOBBER)
6fdc0f
+	mo->type = MO_CLOBBER;
6fdc0f
+      else if (GET_CODE (expr) == SET
6fdc0f
+	       && SET_DEST (expr) == loc
6fdc0f
+	       && same_variable_part_p (SET_SRC (expr),
6fdc0f
+					MEM_EXPR (loc),
6fdc0f
+					MEM_OFFSET (loc)
6fdc0f
+					? INTVAL (MEM_OFFSET (loc)) : 0))
6fdc0f
+	mo->type = MO_COPY;
6fdc0f
+      else
6fdc0f
+	mo->type = MO_SET;
6fdc0f
       mo->u.loc = loc;
6fdc0f
       mo->insn = NEXT_INSN ((rtx) insn);
6fdc0f
     }
6fdc0f
@@ -1631,21 +1740,42 @@ compute_bb_dataflow (basic_block bb)
6fdc0f
 	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
 
6fdc0f
 	      if (GET_CODE (loc) == REG)
6fdc0f
-		var_reg_delete_and_set (out, loc);
6fdc0f
+		var_reg_delete_and_set (out, loc, true);
6fdc0f
 	      else if (GET_CODE (loc) == MEM)
6fdc0f
-		var_mem_delete_and_set (out, loc);
6fdc0f
+		var_mem_delete_and_set (out, loc, true);
6fdc0f
+	    }
6fdc0f
+	    break;
6fdc0f
+
6fdc0f
+	  case MO_COPY:
6fdc0f
+	    {
6fdc0f
+	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
+
6fdc0f
+	      if (GET_CODE (loc) == REG)
6fdc0f
+		var_reg_delete_and_set (out, loc, false);
6fdc0f
+	      else if (GET_CODE (loc) == MEM)
6fdc0f
+		var_mem_delete_and_set (out, loc, false);
6fdc0f
 	    }
6fdc0f
 	    break;
6fdc0f
 
6fdc0f
 	  case MO_USE_NO_VAR:
6fdc0f
+	    {
6fdc0f
+	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
+
6fdc0f
+	      if (GET_CODE (loc) == REG)
6fdc0f
+		var_reg_delete (out, loc, false);
6fdc0f
+	      else if (GET_CODE (loc) == MEM)
6fdc0f
+		var_mem_delete (out, loc, false);
6fdc0f
+	    }
6fdc0f
+	    break;
6fdc0f
+
6fdc0f
 	  case MO_CLOBBER:
6fdc0f
 	    {
6fdc0f
 	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
 
6fdc0f
 	      if (GET_CODE (loc) == REG)
6fdc0f
-		var_reg_delete (out, loc);
6fdc0f
+		var_reg_delete (out, loc, true);
6fdc0f
 	      else if (GET_CODE (loc) == MEM)
6fdc0f
-		var_mem_delete (out, loc);
6fdc0f
+		var_mem_delete (out, loc, true);
6fdc0f
 	    }
6fdc0f
 	    break;
6fdc0f
 
6fdc0f
@@ -1824,7 +1954,7 @@ dump_dataflow_set (dataflow_set *set)
6fdc0f
 
6fdc0f
   fprintf (rtl_dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
6fdc0f
 	   set->stack_adjust);
6fdc0f
-  for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
6fdc0f
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
6fdc0f
     {
6fdc0f
       if (set->regs[i])
6fdc0f
 	{
6fdc0f
@@ -1905,6 +2035,39 @@ variable_was_changed (variable var, htab
6fdc0f
     }
6fdc0f
 }
6fdc0f
 
6fdc0f
+/* Look for the index in VAR->var_part corresponding to OFFSET.
6fdc0f
+   Return -1 if not found.  If INSERTION_POINT is non-NULL, the
6fdc0f
+   referenced int will be set to the index that the part has or should
6fdc0f
+   have, if it should be inserted.  */
6fdc0f
+
6fdc0f
+static inline int
6fdc0f
+find_variable_location_part (variable var, HOST_WIDE_INT offset,
6fdc0f
+			     int *insertion_point)
6fdc0f
+{
6fdc0f
+  int pos, low, high;
6fdc0f
+
6fdc0f
+  /* Find the location part.  */
6fdc0f
+  low = 0;
6fdc0f
+  high = var->n_var_parts;
6fdc0f
+  while (low != high)
6fdc0f
+    {
6fdc0f
+      pos = (low + high) / 2;
6fdc0f
+      if (var->var_part[pos].offset < offset)
6fdc0f
+	low = pos + 1;
6fdc0f
+      else
6fdc0f
+	high = pos;
6fdc0f
+    }
6fdc0f
+  pos = low;
6fdc0f
+
6fdc0f
+  if (insertion_point)
6fdc0f
+    *insertion_point = pos;
6fdc0f
+
6fdc0f
+  if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
6fdc0f
+    return pos;
6fdc0f
+
6fdc0f
+  return -1;
6fdc0f
+}
6fdc0f
+
6fdc0f
 /* Set the part of variable's location in the dataflow set SET.  The variable
6fdc0f
    part is specified by variable's declaration DECL and offset OFFSET and the
6fdc0f
    part's location by LOC.  */
6fdc0f
@@ -1912,7 +2075,7 @@ variable_was_changed (variable var, htab
6fdc0f
 static void
6fdc0f
 set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
6fdc0f
 {
6fdc0f
-  int pos, low, high;
6fdc0f
+  int pos;
6fdc0f
   location_chain node, next;
6fdc0f
   location_chain *nextp;
6fdc0f
   variable var;
6fdc0f
@@ -1935,22 +2098,13 @@ set_variable_part (dataflow_set *set, rt
6fdc0f
     }
6fdc0f
   else
6fdc0f
     {
6fdc0f
+      int inspos = 0;
6fdc0f
+
6fdc0f
       var = (variable) *slot;
6fdc0f
 
6fdc0f
-      /* Find the location part.  */
6fdc0f
-      low = 0;
6fdc0f
-      high = var->n_var_parts;
6fdc0f
-      while (low != high)
6fdc0f
-	{
6fdc0f
-	  pos = (low + high) / 2;
6fdc0f
-	  if (var->var_part[pos].offset < offset)
6fdc0f
-	    low = pos + 1;
6fdc0f
-	  else
6fdc0f
-	    high = pos;
6fdc0f
-	}
6fdc0f
-      pos = low;
6fdc0f
+      pos = find_variable_location_part (var, offset, &inspos);
6fdc0f
 
6fdc0f
-      if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
6fdc0f
+      if (pos >= 0)
6fdc0f
 	{
6fdc0f
 	  node = var->var_part[pos].loc_chain;
6fdc0f
 
6fdc0f
@@ -1985,10 +2139,10 @@ set_variable_part (dataflow_set *set, rt
6fdc0f
 	    abort ();
6fdc0f
 #endif
6fdc0f
 
6fdc0f
-	  /* We have to move the elements of array starting at index low to the
6fdc0f
-	     next position.  */
6fdc0f
-	  for (high = var->n_var_parts; high > low; high--)
6fdc0f
-	    var->var_part[high] = var->var_part[high - 1];
6fdc0f
+	  /* We have to move the elements of array starting at index
6fdc0f
+	     inspos to the next position.  */
6fdc0f
+	  for (pos = var->n_var_parts; pos > inspos; pos--)
6fdc0f
+	    var->var_part[pos] = var->var_part[pos - 1];
6fdc0f
 
6fdc0f
 	  var->n_var_parts++;
6fdc0f
 	  var->var_part[pos].offset = offset;
6fdc0f
@@ -2028,6 +2182,67 @@ set_variable_part (dataflow_set *set, rt
6fdc0f
     }
6fdc0f
 }
6fdc0f
 
6fdc0f
+/* Remove all recorded register locations for the given variable part
6fdc0f
+   from dataflow set SET, except for those that are identical to loc.
6fdc0f
+   The variable part is specified by variable's declaration DECL and
6fdc0f
+   offset OFFSET.  */
6fdc0f
+
6fdc0f
+static void
6fdc0f
+clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
6fdc0f
+		      HOST_WIDE_INT offset)
6fdc0f
+{
6fdc0f
+  void **slot;
6fdc0f
+
6fdc0f
+  if (! decl || ! DECL_P (decl))
6fdc0f
+    return;
6fdc0f
+
6fdc0f
+  slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
6fdc0f
+				   NO_INSERT);
6fdc0f
+  if (slot)
6fdc0f
+    {
6fdc0f
+      variable var = (variable) *slot;
6fdc0f
+      int pos = find_variable_location_part (var, offset, NULL);
6fdc0f
+
6fdc0f
+      if (pos >= 0)
6fdc0f
+	{
6fdc0f
+	  location_chain node, next;
6fdc0f
+
6fdc0f
+	  /* Remove the register locations from the dataflow set.  */
6fdc0f
+	  next = var->var_part[pos].loc_chain;
6fdc0f
+	  for (node = next; node; node = next)
6fdc0f
+	    {
6fdc0f
+	      next = node->next;
6fdc0f
+	      if (node->loc != loc)
6fdc0f
+		{
6fdc0f
+		  if (REG_P (node->loc))
6fdc0f
+		    {
6fdc0f
+		      attrs anode, anext;
6fdc0f
+		      attrs *anextp;
6fdc0f
+
6fdc0f
+		      /* Remove the variable part from the register's
6fdc0f
+			 list, but preserve any other variable parts
6fdc0f
+			 that might be regarded as live in that same
6fdc0f
+			 register.  */
6fdc0f
+		      anextp = &set->regs[REGNO (node->loc)];
6fdc0f
+		      for (anode = *anextp; anode; anode = anext)
6fdc0f
+			{
6fdc0f
+			  anext = anode->next;
6fdc0f
+			  if (anode->decl == decl
6fdc0f
+			      && anode->offset == offset)
6fdc0f
+			    {
6fdc0f
+			      pool_free (attrs_pool, anode);
6fdc0f
+			      *anextp = anext;
6fdc0f
+			    }
6fdc0f
+			}
6fdc0f
+		    }
6fdc0f
+
6fdc0f
+		  delete_variable_part (set, node->loc, decl, offset);
6fdc0f
+		}
6fdc0f
+	    }
6fdc0f
+	}
6fdc0f
+    }
6fdc0f
+}
6fdc0f
+
6fdc0f
 /* Delete the part of variable's location from dataflow set SET.  The variable
6fdc0f
    part is specified by variable's declaration DECL and offset OFFSET and the
6fdc0f
    part's location by LOC.  */
6fdc0f
@@ -2036,7 +2251,6 @@ static void
6fdc0f
 delete_variable_part (dataflow_set *set, rtx loc, tree decl,
6fdc0f
 		      HOST_WIDE_INT offset)
6fdc0f
 {
6fdc0f
-  int pos, low, high;
6fdc0f
   void **slot;
6fdc0f
     
6fdc0f
   slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
6fdc0f
@@ -2044,21 +2258,9 @@ delete_variable_part (dataflow_set *set,
6fdc0f
   if (slot)
6fdc0f
     {
6fdc0f
       variable var = (variable) *slot;
6fdc0f
+      int pos = find_variable_location_part (var, offset, NULL);
6fdc0f
 
6fdc0f
-      /* Find the location part.  */
6fdc0f
-      low = 0;
6fdc0f
-      high = var->n_var_parts;
6fdc0f
-      while (low != high)
6fdc0f
-	{
6fdc0f
-	  pos = (low + high) / 2;
6fdc0f
-	  if (var->var_part[pos].offset < offset)
6fdc0f
-	    low = pos + 1;
6fdc0f
-	  else
6fdc0f
-	    high = pos;
6fdc0f
-	}
6fdc0f
-      pos = low;
6fdc0f
-
6fdc0f
-      if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
6fdc0f
+      if (pos >= 0)
6fdc0f
 	{
6fdc0f
 	  location_chain node, next;
6fdc0f
 	  location_chain *nextp;
6fdc0f
@@ -2124,7 +2326,7 @@ delete_variable_part (dataflow_set *set,
6fdc0f
 		}
6fdc0f
 	    }
6fdc0f
 	  if (changed)
6fdc0f
-	      variable_was_changed (var, set->vars);
6fdc0f
+	    variable_was_changed (var, set->vars);
6fdc0f
 	}
6fdc0f
     }
6fdc0f
 }
6fdc0f
@@ -2418,28 +2620,50 @@ emit_notes_in_bb (basic_block bb)
6fdc0f
 	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
 
6fdc0f
 	      if (GET_CODE (loc) == REG)
6fdc0f
-		var_reg_delete_and_set (&set, loc);
6fdc0f
+		var_reg_delete_and_set (&set, loc, true);
6fdc0f
+	      else
6fdc0f
+		var_mem_delete_and_set (&set, loc, true);
6fdc0f
+
6fdc0f
+	      emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
6fdc0f
+	    }
6fdc0f
+	    break;
6fdc0f
+
6fdc0f
+	  case MO_COPY:
6fdc0f
+	    {
6fdc0f
+	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
+
6fdc0f
+	      if (GET_CODE (loc) == REG)
6fdc0f
+		var_reg_delete_and_set (&set, loc, false);
6fdc0f
 	      else
6fdc0f
-		var_mem_delete_and_set (&set, loc);
6fdc0f
+		var_mem_delete_and_set (&set, loc, false);
6fdc0f
 
6fdc0f
 	      emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
6fdc0f
 	    }
6fdc0f
 	    break;
6fdc0f
 
6fdc0f
 	  case MO_USE_NO_VAR:
6fdc0f
-	  case MO_CLOBBER:
6fdc0f
 	    {
6fdc0f
 	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
 
6fdc0f
 	      if (GET_CODE (loc) == REG)
6fdc0f
-		var_reg_delete (&set, loc);
6fdc0f
+		var_reg_delete (&set, loc, false);
6fdc0f
 	      else
6fdc0f
-		var_mem_delete (&set, loc);
6fdc0f
+		var_mem_delete (&set, loc, false);
6fdc0f
+
6fdc0f
+	      emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
6fdc0f
+	    }
6fdc0f
+	    break;
6fdc0f
+
6fdc0f
+	  case MO_CLOBBER:
6fdc0f
+	    {
6fdc0f
+	      rtx loc = VTI (bb)->mos[i].u.loc;
6fdc0f
 
6fdc0f
-	      if (VTI (bb)->mos[i].type == MO_USE_NO_VAR)
6fdc0f
-		emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
6fdc0f
+	      if (GET_CODE (loc) == REG)
6fdc0f
+		var_reg_delete (&set, loc, true);
6fdc0f
 	      else
6fdc0f
-		emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
6fdc0f
+		var_mem_delete (&set, loc, true);
6fdc0f
+
6fdc0f
+	      emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
6fdc0f
 	    }
6fdc0f
 	    break;
6fdc0f
 
6fdc0f
@@ -2673,7 +2897,8 @@ vt_initialize (void)
6fdc0f
 		{
6fdc0f
 		  while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
6fdc0f
 		    n1++;
6fdc0f
-		  while (n1 < n2 && VTI (bb)->mos[n2].type == MO_SET)
6fdc0f
+		  while (n1 < n2 && (VTI (bb)->mos[n2].type == MO_SET
6fdc0f
+				     || VTI (bb)->mos[n2].type == MO_COPY))
6fdc0f
 		    n2--;
6fdc0f
 		  if (n1 < n2)
6fdc0f
 		    {
6fdc0f
--- gcc/testsuite/g++.dg/debug/vartrack1.C	2004-06-24 14:04:38.000000000 -0400
6fdc0f
+++ gcc/testsuite/g++.dg/debug/vartrack1.C	2006-12-08 05:29:41.000000000 -0500
6fdc0f
@@ -0,0 +1,99 @@
6fdc0f
+// This testcase used to hang the compiler in vt_find_locations.
6fdc0f
+// { dg-do compile }
6fdc0f
+// { dg-options "-O2 -g" }
6fdc0f
+
6fdc0f
+struct S
6fdc0f
+{
6fdc0f
+  int a;
6fdc0f
+  S *b, *c, *d;
6fdc0f
+};
6fdc0f
+
6fdc0f
+struct T
6fdc0f
+{
6fdc0f
+  void f1 (S *x);
6fdc0f
+  void f2 (S *x);
6fdc0f
+  void f3 (S *x, S *y);
6fdc0f
+  S *e;
6fdc0f
+};
6fdc0f
+
6fdc0f
+void
6fdc0f
+T::f3 (S *x, S *y)
6fdc0f
+{
6fdc0f
+  while (x != this->e && (!x || x->a == 1))
6fdc0f
+    {
6fdc0f
+      if (x == y->c)
6fdc0f
+	{
6fdc0f
+	  S *w = y->d;
6fdc0f
+	  if (w && w->a == 0)
6fdc0f
+	    {
6fdc0f
+	      w->a = 1;
6fdc0f
+	      y->a = 0;
6fdc0f
+	      f2 (y);
6fdc0f
+	      w = y->d;
6fdc0f
+	    }
6fdc0f
+	  if (w && (!w->c || w->c->a == 1) && (!w->d || w->d->a == 1))
6fdc0f
+	    {
6fdc0f
+	      w->a = 0;
6fdc0f
+	      x = y;
6fdc0f
+	      y = x->b;
6fdc0f
+	    }
6fdc0f
+	  else
6fdc0f
+	    {
6fdc0f
+	      if (w && (!w->d || w->d->a == 1))
6fdc0f
+		{
6fdc0f
+		  if (w->c)
6fdc0f
+		    w->c->a = 1;
6fdc0f
+		  w->a = 0;
6fdc0f
+		  f1 (w);
6fdc0f
+		  w = y->d;
6fdc0f
+		}
6fdc0f
+	      if (w)
6fdc0f
+		{
6fdc0f
+		  w->a = y->a;
6fdc0f
+		  if (w->d)
6fdc0f
+		    w->d->a = 1;
6fdc0f
+		}
6fdc0f
+	      y->a = 1;
6fdc0f
+	      f2 (y);
6fdc0f
+	      x = e;
6fdc0f
+	    }
6fdc0f
+	}
6fdc0f
+      else
6fdc0f
+	{
6fdc0f
+	  S *w = y->c;
6fdc0f
+	  if (w && w->a == 0)
6fdc0f
+	    {
6fdc0f
+	      w->a = 1;
6fdc0f
+	      y->a = 0;
6fdc0f
+	      f1 (y);
6fdc0f
+	      w = y->c;
6fdc0f
+	    }
6fdc0f
+	  if (w && (!w->c || w->c->a == 1) && (!w->d || w->d->a == 1))
6fdc0f
+	    {
6fdc0f
+	      w->a = 0;
6fdc0f
+	      x = y;
6fdc0f
+	      y = x->b;
6fdc0f
+	    }
6fdc0f
+	  else
6fdc0f
+	    {
6fdc0f
+	      if (w && (!w->c || w->c->a == 1))
6fdc0f
+		{
6fdc0f
+		  w->a = 0;
6fdc0f
+		  if (w->d)
6fdc0f
+		    w->d->a = 1;
6fdc0f
+		  f2 (w);
6fdc0f
+		  w = y->c;
6fdc0f
+		}
6fdc0f
+	      if (w)
6fdc0f
+		{
6fdc0f
+		  w->a = y->a;
6fdc0f
+		  if (w->c)
6fdc0f
+		    w->c->a = 1;
6fdc0f
+		}
6fdc0f
+	      y->a = 1;
6fdc0f
+	      f1 (y);
6fdc0f
+	      x = e;
6fdc0f
+	    }
6fdc0f
+	}
6fdc0f
+    }
6fdc0f
+}