From 81f2eadbedaf8048f749b2a6c7f550740ece94a4 Mon Sep 17 00:00:00 2001
From: Josef Zlomek <zlomekj@suse.cz>
Date: Thu, 11 Mar 2004 09:05:14 +0100
Subject: [PATCH] var-tracking.c (struct variable_def): Added field refcount.

	PR/14362
	* var-tracking.c (struct variable_def): Added field refcount.
	(variable_htab_free): Decrease the refcount and delete variable
	only if there are no more references.
	(unshare_variable): New function.
	(vars_copy_1): Increase refcount instead of copying the variable.
	(variable_union): Share the variables where possible, unshare
	the variables if needed.
	(variable_different_p): Return false if var1 and var2 are
	the same structure.
	(variable_was_changed): Init the refcount of new variable.
	(set_frame_base_location): Unshare variable if needed.
	(set_variable_part): Init the refcount of new variable.
	Unshare the variables if needed.
	(delete_variable_part): Unshare the variables if needed.
	(emit_notes_for_differences_1): Init the refcount of new variable.
	(vt_add_function_parameters): Do not add function parameters to
	IN set of ENTRY_BLOCK_PTR because it is unused anyway.
	(vt_initialize): Do not add frame_base_decl to IN set of
	ENTRY_BLOCK_PTR because it is unused anyway.

From-SVN: r79307
---
 gcc/ChangeLog      |  23 +++++
 gcc/var-tracking.c | 204 ++++++++++++++++++++++++++++++++++++---------
 2 files changed, 189 insertions(+), 38 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c1df556d0324..6707f581326e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,26 @@
+2004-03-11  Josef Zlomek  <zlomekj@suse.cz>
+
+	PR/14362
+	* var-tracking.c (struct variable_def): Added field refcount.
+	(variable_htab_free): Decrease the refcount and delete variable
+	only if there are no more references.
+	(unshare_variable): New function.
+	(vars_copy_1): Increase refcount instead of copying the variable.
+	(variable_union): Share the variables where possible, unshare
+	the variables if needed.
+	(variable_different_p): Return false if var1 and var2 are
+	the same structure.
+	(variable_was_changed): Init the refcount of new variable.
+	(set_frame_base_location): Unshare variable if needed.
+	(set_variable_part): Init the refcount of new variable.
+	Unshare the variables if needed.
+	(delete_variable_part): Unshare the variables if needed. 
+	(emit_notes_for_differences_1): Init the refcount of new variable.
+	(vt_add_function_parameters): Do not add function parameters to
+	IN set of ENTRY_BLOCK_PTR because it is unused anyway.
+	(vt_initialize): Do not add frame_base_decl to IN set of
+	ENTRY_BLOCK_PTR because it is unused anyway.
+
 2004-03-11  Josef Zlomek  <zlomekj@suse.cz>
 
 	* var-tracking.c (vars_copy_1): Cleanup and speedup chain operations.
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 5b586bc55aa2..5da237683665 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -233,6 +233,9 @@ typedef struct variable_def
   /* The declaration of the variable.  */
   tree decl;
 
+  /* Reference count.  */
+  int refcount;
+
   /* Number of variable parts.  */
   int n_var_parts;
 
@@ -285,6 +288,7 @@ static void attrs_list_copy (attrs *, attrs);
 static void attrs_list_union (attrs *, attrs);
 
 static void vars_clear (htab_t);
+static variable unshare_variable (dataflow_set *set, variable var);
 static int vars_copy_1 (void **, void *);
 static void vars_copy (htab_t, htab_t);
 static void var_reg_delete_and_set (dataflow_set *, rtx);
@@ -629,6 +633,15 @@ variable_htab_free (void *elem)
   variable var = (variable) elem;
   location_chain node, next;
 
+#ifdef ENABLE_CHECKING
+  if (var->refcount <= 0)
+    abort ();
+#endif
+
+  var->refcount--;
+  if (var->refcount > 0)
+    return;
+
   for (i = 0; i < var->n_var_parts; i++)
     {
       for (node = var->var_part[i].loc_chain; node; node = next)
@@ -732,32 +745,29 @@ vars_clear (htab_t vars)
   htab_empty (vars);
 }
 
-/* Copy one variable from *SLOT to hash table DATA.  */
+/* Return a copy of a variable VAR and insert it to dataflow set SET.  */
 
-static int
-vars_copy_1 (void **slot, void *data)
+static variable
+unshare_variable (dataflow_set *set, variable var)
 {
-  htab_t dst = (htab_t) data;
-  variable src, *dstp, var;
+  void **slot;
+  variable new_var;
   int i;
 
-  src = *(variable *) slot;
-  dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
-						VARIABLE_HASH_VAL (src->decl),
-						INSERT);
-  var = pool_alloc (var_pool);
-  var->decl = src->decl;
-  var->n_var_parts = src->n_var_parts;
-  *dstp = (void *) var;
+  new_var = pool_alloc (var_pool);
+  new_var->decl = var->decl;
+  new_var->refcount = 1;
+  var->refcount--;
+  new_var->n_var_parts = var->n_var_parts;
 
   for (i = 0; i < var->n_var_parts; i++)
     {
       location_chain node;
       location_chain *nextp;
 
-      var->var_part[i].offset = src->var_part[i].offset;
-      nextp = &var->var_part[i].loc_chain;
-      for (node = src->var_part[i].loc_chain; node; node = node->next)
+      new_var->var_part[i].offset = var->var_part[i].offset;
+      nextp = &new_var->var_part[i].loc_chain;
+      for (node = var->var_part[i].loc_chain; node; node = node->next)
 	{
 	  location_chain new_lc;
 
@@ -771,12 +781,36 @@ vars_copy_1 (void **slot, void *data)
 
       /* We are at the basic block boundary when copying variable description
 	 so set the CUR_LOC to be the first element of the chain.  */
-      if (var->var_part[i].loc_chain)
-	var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
+      if (new_var->var_part[i].loc_chain)
+	new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
       else
-	var->var_part[i].cur_loc = NULL;
+	new_var->var_part[i].cur_loc = NULL;
     }
 
+  slot = htab_find_slot_with_hash (set->vars, new_var->decl,
+				   VARIABLE_HASH_VAL (new_var->decl),
+				   INSERT);
+  *slot = new_var;
+  return new_var;
+}
+
+/* Add a variable from *SLOT to hash table DATA and increase its reference
+   count.  */
+
+static int
+vars_copy_1 (void **slot, void *data)
+{
+  htab_t dst = (htab_t) data;
+  variable src, *dstp;
+
+  src = *(variable *) slot;
+  src->refcount++;
+
+  dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
+						VARIABLE_HASH_VAL (src->decl),
+						INSERT);
+  *dstp = src;
+
   /* Continue traversing the hash table.  */
   return 1;
 }
@@ -972,9 +1006,37 @@ variable_union (void **slot, void *data)
 						INSERT);
   if (!*dstp)
     {
-      *dstp = dst = pool_alloc (var_pool);
-      dst->decl = src->decl;
-      dst->n_var_parts = 0;
+      src->refcount++;
+
+      /* If CUR_LOC of some variable part is not the first element of
+	 the location chain we are going to change it so we have to make
+	 a copy of the variable.  */
+      for (k = 0; k < src->n_var_parts; k++)
+	{
+	  if (src->var_part[k].loc_chain)
+	    {
+#ifdef ENABLE_CHECKING
+	      if (src->var_part[k].cur_loc == NULL)
+		abort ();
+#endif
+	      if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
+		break;
+	    }
+#ifdef ENABLE_CHECKING
+	  else
+	    {
+	      if (src->var_part[k].cur_loc != NULL)
+		abort ();
+	    }
+#endif
+	}
+      if (k < src->n_var_parts)
+	unshare_variable (set, src);
+      else
+	*dstp = src;
+
+      /* Continue traversing the hash table.  */
+      return 1;
     }
   else
     dst = *dstp;
@@ -998,10 +1060,8 @@ variable_union (void **slot, void *data)
       else
 	j++;
     }
-  if (i < src->n_var_parts)
-    k += src->n_var_parts - i;
-  if (j < dst->n_var_parts)
-    k += dst->n_var_parts - j;
+  k += src->n_var_parts - i;
+  k += dst->n_var_parts - j;
 #ifdef ENABLE_CHECKING
   /* We track only variables whose size is <= MAX_VAR_PARTS bytes
      thus there are at most MAX_VAR_PARTS different offsets.  */
@@ -1009,13 +1069,16 @@ variable_union (void **slot, void *data)
     abort ();
 #endif
 
+  if (dst->refcount > 1 && dst->n_var_parts != k)
+    dst = unshare_variable (set, dst);
+
   i = src->n_var_parts - 1;
   j = dst->n_var_parts - 1;
   dst->n_var_parts = k;
 
   for (k--; k >= 0; k--)
     {
-      location_chain node;
+      location_chain node, node2;
 
       if (i >= 0 && j >= 0
 	  && src->var_part[i].offset == dst->var_part[j].offset)
@@ -1026,7 +1089,26 @@ variable_union (void **slot, void *data)
 	  int dst_l, src_l;
 	  int ii, jj, n;
 	  struct variable_union_info *vui;
-	  
+
+	  /* If DST is shared compare the location chains.
+	     If they are different we will modify the chain in DST with
+	     high probability so make a copy of DST.  */
+	  if (dst->refcount > 1)
+	    {
+	      for (node = src->var_part[i].loc_chain,
+		   node2 = dst->var_part[j].loc_chain; node && node2;
+		   node = node->next, node2 = node2->next)
+		{
+		  if (!((GET_CODE (node2->loc) == REG
+			 && GET_CODE (node->loc) == REG
+			 && REGNO (node2->loc) == REGNO (node->loc))
+			|| rtx_equal_p (node2->loc, node->loc)))
+		    break;
+		}
+	      if (node || node2)
+		dst = unshare_variable (set, dst);
+	    }
+
 	  src_l = 0;
 	  for (node = src->var_part[i].loc_chain; node; node = node->next)
 	    src_l++;
@@ -1187,6 +1269,9 @@ variable_different_p (variable var1, variable var2)
 {
   int i;
 
+  if (var1 == var2)
+    return false;
+
   if (var1->n_var_parts != var2->n_var_parts)
     return true;
 
@@ -1791,6 +1876,7 @@ variable_was_changed (variable var, htab_t htab)
 
 	  empty_var = pool_alloc (var_pool);
 	  empty_var->decl = var->decl;
+	  empty_var->refcount = 1;
 	  empty_var->n_var_parts = 0;
 	  *slot = empty_var;
 
@@ -1843,7 +1929,12 @@ set_frame_base_location (dataflow_set *set, rtx loc)
     abort ();
 #endif
 
+  /* If frame_base_decl is shared unshare it first.  */
+  if (var->refcount > 1)
+    var = unshare_variable (set, var);
+
   var->var_part[0].loc_chain->loc = loc;
+  var->var_part[0].cur_loc = loc;
   variable_was_changed (var, set->vars);
 }
 
@@ -1867,6 +1958,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
       /* Create new variable information.  */
       var = pool_alloc (var_pool);
       var->decl = decl;
+      var->refcount = 1;
       var->n_var_parts = 1;
       var->var_part[0].offset = offset;
       var->var_part[0].loc_chain = NULL;
@@ -1891,9 +1983,33 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
 	}
       pos = low;
 
-      if (pos == var->n_var_parts || var->var_part[pos].offset != offset)
+      if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
 	{
-	  /* We have not find the location part, new one will be created.  */
+	  node = var->var_part[pos].loc_chain;
+
+	  if (node
+	      && ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+		   && REGNO (node->loc) == REGNO (loc))
+		  || rtx_equal_p (node->loc, loc)))
+	    {
+	      /* LOC is in the beginning of the chain so we have nothing
+		 to do.  */
+	      return;
+	    }
+	  else
+	    {
+	      /* We have to make a copy of a shared variable.  */
+	      if (var->refcount > 1)
+		var = unshare_variable (set, var);
+	    }
+	}
+      else
+	{
+	  /* We have not found the location part, new one will be created.  */
+
+	  /* We have to make a copy of the shared variable.  */
+	  if (var->refcount > 1)
+	    var = unshare_variable (set, var);
 
 #ifdef ENABLE_CHECKING
 	  /* We track only variables whose size is <= MAX_VAR_PARTS bytes
@@ -1914,7 +2030,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
 	}
     }
 
-  /* Delete the location from list.  */
+  /* Delete the location from the list.  */
   nextp = &var->var_part[pos].loc_chain;
   for (node = var->var_part[pos].loc_chain; node; node = next)
     {
@@ -1981,6 +2097,23 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
 	  location_chain *nextp;
 	  bool changed;
 
+	  if (var->refcount > 1)
+	    {
+	      /* If the variable contains the location part we have to
+		 make a copy of the variable.  */
+	      for (node = var->var_part[pos].loc_chain; node;
+		   node = node->next)
+		{
+		  if ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+		       && REGNO (node->loc) == REGNO (loc))
+		      || rtx_equal_p (node->loc, loc))
+		    {
+		      var = unshare_variable (set, var);
+		      break;
+		    }
+		}
+	    }
+
 	  /* Delete the location part.  */
 	  nextp = &var->var_part[pos].loc_chain;
 	  for (node = *nextp; node; node = next)
@@ -2149,6 +2282,7 @@ emit_notes_for_differences_1 (void **slot, void *data)
 
       empty_var = pool_alloc (var_pool);
       empty_var->decl = old_var->decl;
+      empty_var->refcount = 1;
       empty_var->n_var_parts = 0;
       variable_was_changed (empty_var, NULL);
     }
@@ -2357,7 +2491,7 @@ vt_add_function_parameters (void)
       rtx incoming = DECL_INCOMING_RTL (parm);
       tree decl;
       HOST_WIDE_INT offset;
-      dataflow_set *in, *out;
+      dataflow_set *out;
 
       if (TREE_CODE (parm) != PARM_DECL)
 	continue;
@@ -2386,7 +2520,6 @@ vt_add_function_parameters (void)
       incoming = eliminate_regs (incoming, 0, NULL_RTX);
       if (!frame_pointer_needed && GET_CODE (incoming) == MEM)
 	incoming = adjust_stack_reference (incoming, -stack_adjust);
-      in = &VTI (ENTRY_BLOCK_PTR)->in;
       out = &VTI (ENTRY_BLOCK_PTR)->out;
 
       if (GET_CODE (incoming) == REG)
@@ -2395,16 +2528,12 @@ vt_add_function_parameters (void)
 	  if (REGNO (incoming) >= FIRST_PSEUDO_REGISTER)
 	    abort ();
 #endif
-	  attrs_list_insert (&in->regs[REGNO (incoming)],
-			     parm, offset, incoming);
 	  attrs_list_insert (&out->regs[REGNO (incoming)],
 			     parm, offset, incoming);
-	  set_variable_part (in, incoming, parm, offset);
 	  set_variable_part (out, incoming, parm, offset);
 	}
       else if (GET_CODE (incoming) == MEM)
 	{
-	  set_variable_part (in, incoming, parm, offset);
 	  set_variable_part (out, incoming, parm, offset);
 	}
     }
@@ -2564,7 +2693,6 @@ vt_initialize (void)
 
       /* Set its initial "location".  */
       base = gen_rtx_MEM (Pmode, stack_pointer_rtx);
-      set_variable_part (&VTI (ENTRY_BLOCK_PTR)->in, base, frame_base_decl, 0);
       set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
     }
   else
-- 
GitLab