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]

[PATCH] Use refcounted shared hash tables to decrease var-tracking memory usage and speed it up


Hi!

https://bugzilla.redhat.com/show_bug.cgi?id=503816 contains a testcase where
most compile time is spent in var-tracking and var-tracking has also
an enormous memory usage.  All the var-tracking.c pools are quite lightly
used, only a few megabytes at most, the only thing that eats memory
are the hash tables.  The testcase has 13784 basic blocks, and
var-tracking.c uses two hash tables for each basic block (one is in.vars and
one is out.vars).  There are a few thousands variables tracked, so it
needs approx. num_basic_blocks * 2 * num_of_tracked_variables * 2 * sizeof (void *)
bytes of memory (the first 2 stands for in.vars + out.vars, the second for
hash tables being on average half filled, half empty).

This patch saves memory by using COW hash tables, initially predecessor's
out htab is just shared with successor's in htab (and similarly to other
cases where we'd vars_copy a hashtab around), and is unshared only right
before we decide to modify it.

With 4.4 branch x86_64-linux to s390x-linux cross compiler the compilation
times/memory usage are (in KB resp. minutes):
								MAX VSZ	  MAX RSS   COMPILE TIME
./cc1plus.vanilla -g -O2 rh503816.ii -quiet			2338528	  2233232	11:18
./cc1plus.vanilla -g -O2 rh503816.ii -fno-var-tracking -quiet	845288	  737188	4:58
./cc1plus.patched -g -O2 rh503816.ii -quiet			1315368	  1210268	8:32
./cc1plus.patched -g -O2 rh503816.ii -fno-var-tracking -quiet	846328	  738216	4:56

so the var-tracking pass memory usage shrunk from approx. 1.42GB to 460MB
and time spent in var-tracking went down from 6:20 to 3:35.

Besides introducing these COW hash tables, the patch also fixes one quite
severe bug (variable_union calling htab_find_slot_with_hash ... INSERT,
but not storing anything into the returned slot, keeping it NULL and
then calling unshare_variable which does another htab_find_slot_with_hash
... INSERT and stores something to the returned slot.  In the best
case this just screws up htab's idea how many entries are used, but possibly
could cause more harm.  Also, dataflow_set_different can now be speeded up
if both hash tables have different number of elements (then they necessarily
are different, of course this relies on the element computation to be
correct, which was not the case in variable_union), and when comparing two
htabs shared together, there is no need to traverse anything either.

2009-06-19  Jakub Jelinek  <jakub@redhat.com>

	* var-tracking.c (struct shared_hash_def, shared_hash): New types.
	(dataflow_set): Change vars type from htab_t to shared_hash.
	(shared_hash_pool, empty_shared_hash): New variables.
	(vars_clear): Removed.
	(shared_hash_shared, shared_hash_htab, shared_hash_copy): New
	static inlines.
	(shared_hash_unshare, shared_hash_destroy): New functions.
	(unshare_variable): Unshare set->vars if shared, use
	shared_hash_htab.
	(vars_copy): Use htab_traverse_noresize instead of htab_traverse.
	(get_init_value, find_src_set_src, dump_dataflow_set,
	clobber_variable_part, emit_notes_for_differences): Use
	shared_hash_htab.
	(dataflow_set_init): Remove second argument, set vars to
	empty_shared_hash instead of creating a new htab.
	(dataflow_set_clear): Call shared_hash_destroy and set vars
	to empty_shared_hash instead of calling vars_clear.
	(dataflow_set_copy): Don't call vars_copy, instead just share
	the src htab with dst.
	(variable_union): Use shared_hash_htab, use initially NO_INSERT
	lookup if set->vars is shared.  Don't keep slot cleared before
	calling unshare_variable.  Unshare set->vars if needed.
	Even ->refcount == 1 vars must be unshared if set->vars is shared
	and var needs to be modified.
	(variable_canonicalize): New function.
	(dataflow_set_union): If dst->vars is empty, just share src->vars
	with dst->vars and traverse with variable_canonicalize to canonicalize
	and unshare what is needed.
	(dataflow_set_different): If old_set and new_set use the same shared
	htab, they aren't different.  If number of htab elements is different,
	htabs are different.  Use shared_hash_htab.
	(dataflow_set_destroy): Call shared_hash_destroy instead of
	htab_delete.
	(compute_bb_dataflow, emit_notes_in_bb, vt_emit_notes): Don't pass
	second argument to dataflow_set_init.
	(vt_initialize): Likewise.  Initialize shared_hash_pool and
	empty_shared_hash, move bb in/out initialization afterwards.
	Use variable_htab_free instead of NULL as changed_variables del hook.
	(variable_was_changed): Change type of second argument to pointer to
	dataflow_set.  When inserting var into changed_variables, bump
	refcount.  Unshare set->vars if set is shared htab and slot needs to
	be cleared.
	(set_variable_part): Use shared_hash_htab, use initially NO_INSERT
	lookup if set->vars is shared.  Unshare set->vars if needed.
	Even ->refcount == 1 vars must be unshared if set->vars is shared
	and var needs to be modified.  Adjust variable_was_changed caller.
	(delete_variable_part): Use shared_hash_htab.  Even ->refcount == 1
	vars must be unshared if set->vars is shared and var needs to be
	modified.  Adjust variable_was_changed caller.
	(emit_note_insn_var_location): Don't pool_free var.
	(emit_notes_for_differences_1): Initialize empty_var->refcount to 0
	instead of 1.
	(vt_finalize): Call htab_delete on empty_shared_hash->htab and
	free_alloc_pool on shared_hash_pool.

--- gcc/var-tracking.c.jj	2009-04-25 00:12:11.000000000 +0200
+++ gcc/var-tracking.c	2009-06-19 13:08:20.000000000 +0200
@@ -182,6 +182,17 @@ typedef struct attrs_def
   HOST_WIDE_INT offset;
 } *attrs;
 
+/* Structure holding a refcounted hash table.  If refcount > 1,
+   it must be first unshared before modified.  */
+typedef struct shared_hash_def
+{
+  /* Reference count.  */
+  int refcount;
+
+  /* Actual hash table.  */
+  htab_t htab;
+} *shared_hash;
+
 /* Structure holding the IN or OUT set for a basic block.  */
 typedef struct dataflow_set_def
 {
@@ -192,7 +203,7 @@ typedef struct dataflow_set_def
   attrs regs[FIRST_PSEUDO_REGISTER];
 
   /* Variable locations.  */
-  htab_t vars;
+  shared_hash vars;
 } dataflow_set;
 
 /* The structure (one for each basic block) containing the information
@@ -280,12 +291,18 @@ static alloc_pool var_pool;
 /* Alloc pool for struct location_chain_def.  */
 static alloc_pool loc_chain_pool;
 
+/* Alloc pool for struct shared_hash_def.  */
+static alloc_pool shared_hash_pool;
+
 /* Changed variables, notes will be emitted for them.  */
 static htab_t changed_variables;
 
 /* Shall notes be emitted?  */
 static bool emit_notes;
 
+/* Empty shared hashtable.  */
+static shared_hash empty_shared_hash;
+
 /* Local function prototypes.  */
 static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
 					  HOST_WIDE_INT *);
@@ -305,7 +322,6 @@ static void attrs_list_insert (attrs *, 
 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, 
 				  enum var_init_status);
 static int vars_copy_1 (void **, void *);
@@ -321,11 +337,12 @@ static void var_mem_delete_and_set (data
 				    enum var_init_status, rtx);
 static void var_mem_delete (dataflow_set *, rtx, bool);
 
-static void dataflow_set_init (dataflow_set *, int);
+static void dataflow_set_init (dataflow_set *);
 static void dataflow_set_clear (dataflow_set *);
 static void dataflow_set_copy (dataflow_set *, dataflow_set *);
 static int variable_union_info_cmp_pos (const void *, const void *);
 static int variable_union (void **, void *);
+static int variable_canonicalize (void **, void *);
 static void dataflow_set_union (dataflow_set *, dataflow_set *);
 static bool variable_part_different_p (variable_part *, variable_part *);
 static bool variable_different_p (variable, variable, bool);
@@ -352,7 +369,7 @@ static void dump_vars (htab_t);
 static void dump_dataflow_set (dataflow_set *);
 static void dump_dataflow_sets (void);
 
-static void variable_was_changed (variable, htab_t);
+static void variable_was_changed (variable, dataflow_set *);
 static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, 
 			       enum var_init_status, rtx);
 static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, 
@@ -742,12 +759,50 @@ attrs_list_union (attrs *dstp, attrs src
     }
 }
 
-/* Delete all variables from hash table VARS.  */
+/* Shared hashtable support.  */
+
+static inline bool
+shared_hash_shared (shared_hash vars)
+{
+  return vars->refcount > 1;
+}
+
+static inline htab_t
+shared_hash_htab (shared_hash vars)
+{
+  return vars->htab;
+}
+
+static shared_hash
+shared_hash_unshare (shared_hash vars)
+{
+  shared_hash new_vars = (shared_hash) pool_alloc (shared_hash_pool);
+  gcc_assert (vars->refcount > 1);
+  new_vars->refcount = 1;
+  new_vars->htab
+    = htab_create (htab_elements (vars->htab) + 3, variable_htab_hash,
+		   variable_htab_eq, variable_htab_free);
+  vars_copy (new_vars->htab, vars->htab);
+  vars->refcount--;
+  return new_vars;
+}
+
+static inline shared_hash
+shared_hash_copy (shared_hash vars)
+{
+  vars->refcount++;
+  return vars;
+}
 
 static void
-vars_clear (htab_t vars)
+shared_hash_destroy (shared_hash vars)
 {
-  htab_empty (vars);
+  gcc_assert (vars->refcount > 0);
+  if (--vars->refcount == 0)
+    {
+      htab_delete (vars->htab);
+      pool_free (shared_hash_pool, vars);
+    }
 }
 
 /* Return a copy of a variable VAR and insert it to dataflow set SET.  */
@@ -801,7 +856,9 @@ unshare_variable (dataflow_set *set, var
 	new_var->var_part[i].cur_loc = NULL;
     }
 
-  slot = htab_find_slot_with_hash (set->vars, new_var->decl,
+  if (shared_hash_shared (set->vars))
+    set->vars = shared_hash_unshare (set->vars);
+  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars), new_var->decl,
 				   VARIABLE_HASH_VAL (new_var->decl),
 				   INSERT);
   *slot = new_var;
@@ -834,8 +891,7 @@ vars_copy_1 (void **slot, void *data)
 static void
 vars_copy (htab_t dst, htab_t src)
 {
-  vars_clear (dst);
-  htab_traverse (src, vars_copy_1, dst);
+  htab_traverse_noresize (src, vars_copy_1, dst);
 }
 
 /* Map a decl to its main debug decl.  */
@@ -882,8 +938,8 @@ get_init_value (dataflow_set *set, rtx l
   if (! flag_var_tracking_uninit)
     return VAR_INIT_STATUS_INITIALIZED;
 
-  slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
-				   NO_INSERT);
+  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars), decl,
+				   VARIABLE_HASH_VAL (decl), NO_INSERT);
   if (slot)
     {
       var = * (variable *) slot;
@@ -1050,11 +1106,10 @@ var_mem_delete (dataflow_set *set, rtx l
    VARS_SIZE is the initial size of hash table VARS.  */
 
 static void
-dataflow_set_init (dataflow_set *set, int vars_size)
+dataflow_set_init (dataflow_set *set)
 {
   init_attrs_list_set (set->regs);
-  set->vars = htab_create (vars_size, variable_htab_hash, variable_htab_eq,
-			   variable_htab_free);
+  set->vars = shared_hash_copy (empty_shared_hash);
   set->stack_adjust = 0;
 }
 
@@ -1068,7 +1123,8 @@ dataflow_set_clear (dataflow_set *set)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     attrs_list_clear (&set->regs[i]);
 
-  vars_clear (set->vars);
+  shared_hash_destroy (set->vars);
+  set->vars = shared_hash_copy (empty_shared_hash);
 }
 
 /* Copy the contents of dataflow set SRC to DST.  */
@@ -1081,7 +1137,8 @@ dataflow_set_copy (dataflow_set *dst, da
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     attrs_list_copy (&dst->regs[i], src->regs[i]);
 
-  vars_copy (dst->vars, src->vars);
+  shared_hash_destroy (dst->vars);
+  dst->vars = shared_hash_copy (src->vars);
   dst->stack_adjust = src->stack_adjust;
 }
 
@@ -1134,10 +1191,12 @@ variable_union (void **slot, void *data)
   int i, j, k;
 
   src = *(variable *) slot;
-  dstp = (variable *) htab_find_slot_with_hash (set->vars, src->decl,
+  dstp = (variable *) htab_find_slot_with_hash (shared_hash_htab (set->vars),
+						src->decl,
 						VARIABLE_HASH_VAL (src->decl),
-						INSERT);
-  if (!*dstp)
+						shared_hash_shared (set->vars)
+						? NO_INSERT : INSERT);
+  if (!dstp || !*dstp)
     {
       src->refcount++;
 
@@ -1162,10 +1221,24 @@ variable_union (void **slot, void *data)
 	  if (! flag_var_tracking_uninit)
 	    status = VAR_INIT_STATUS_INITIALIZED;
 
+	  if (dstp)
+	    *dstp = src;
 	  unshare_variable (set, src, status);
 	}
       else
-	*dstp = src;
+	{
+	  if (!dstp)
+	    {
+	      if (shared_hash_shared (set->vars))
+		set->vars = shared_hash_unshare (set->vars);
+	      dstp = (variable *)
+		     htab_find_slot_with_hash (shared_hash_htab (set->vars),
+					       src->decl,
+					       VARIABLE_HASH_VAL (src->decl),
+					       INSERT);
+	    }
+	  *dstp = src;
+	}
 
       /* Continue traversing the hash table.  */
       return 1;
@@ -1196,7 +1269,8 @@ variable_union (void **slot, void *data)
      thus there are at most MAX_VAR_PARTS different offsets.  */
   gcc_assert (k <= MAX_VAR_PARTS);
 
-  if (dst->refcount > 1 && dst->n_var_parts != k)
+  if ((dst->refcount > 1 || shared_hash_shared (set->vars))
+      && dst->n_var_parts != k)
     {
       enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
       
@@ -1226,7 +1300,7 @@ variable_union (void **slot, void *data)
 	  /* 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)
+	  if (dst->refcount > 1 || shared_hash_shared (set->vars))
 	    {
 	      for (node = src->var_part[i].loc_chain,
 		   node2 = dst->var_part[j].loc_chain; node && node2;
@@ -1379,6 +1453,46 @@ variable_union (void **slot, void *data)
   return 1;
 }
 
+/* Like variable_union, but only used when doing dataflow_set_union
+   into an empty hashtab.  To allow sharing, dst is initially shared
+   with src (so all variables are "copied" from src to dst hashtab),
+   so only unshare_variable for variables that need canonicalization
+   are needed.  */
+
+static int
+variable_canonicalize (void **slot, void *data)
+{
+  variable src;
+  dataflow_set *set = (dataflow_set *) data;
+  int k;
+
+  src = *(variable *) slot;
+
+  /* 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++)
+    {
+      gcc_assert (!src->var_part[k].loc_chain == !src->var_part[k].cur_loc);
+      if (src->var_part[k].loc_chain)
+	{
+	  gcc_assert (src->var_part[k].cur_loc);
+	  if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
+	    break;
+	}
+    }
+  if (k < src->n_var_parts)
+    {
+      enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+
+      if (! flag_var_tracking_uninit)
+	status = VAR_INIT_STATUS_INITIALIZED;
+
+      unshare_variable (set, src, status);
+    }
+  return 1;
+}
+
 /* Compute union of dataflow sets SRC and DST and store it to DST.  */
 
 static void
@@ -1389,7 +1503,14 @@ dataflow_set_union (dataflow_set *dst, d
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     attrs_list_union (&dst->regs[i], src->regs[i]);
 
-  htab_traverse (src->vars, variable_union, dst);
+  if (dst->vars == empty_shared_hash)
+    {
+      shared_hash_destroy (dst->vars);
+      dst->vars = shared_hash_copy (src->vars);
+      htab_traverse (shared_hash_htab (src->vars), variable_canonicalize, dst);
+    }
+  else
+    htab_traverse (shared_hash_htab (src->vars), variable_union, dst);
 }
 
 /* Flag whether two dataflow sets being compared contain different data.  */
@@ -1522,15 +1643,24 @@ dataflow_set_different_2 (void **slot, v
 static bool
 dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
 {
+  if (old_set->vars == new_set->vars)
+    return false;
+
+  if (htab_elements (shared_hash_htab (old_set->vars))
+      != htab_elements (shared_hash_htab (new_set->vars)))
+    return true;
+
   dataflow_set_different_value = false;
 
-  htab_traverse (old_set->vars, dataflow_set_different_1, new_set->vars);
+  htab_traverse (shared_hash_htab (old_set->vars), dataflow_set_different_1,
+		 shared_hash_htab (new_set->vars));
   if (!dataflow_set_different_value)
     {
       /* We have compared the variables which are in both hash tables
 	 so now only check whether there are some variables in NEW_SET->VARS
 	 which are not in OLD_SET->VARS.  */
-      htab_traverse (new_set->vars, dataflow_set_different_2, old_set->vars);
+      htab_traverse (shared_hash_htab (new_set->vars), dataflow_set_different_2,
+		     shared_hash_htab (old_set->vars));
     }
   return dataflow_set_different_value;
 }
@@ -1545,7 +1675,7 @@ dataflow_set_destroy (dataflow_set *set)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     attrs_list_clear (&set->regs[i]);
 
-  htab_delete (set->vars);
+  shared_hash_destroy (set->vars);
   set->vars = NULL;
 }
 
@@ -1998,7 +2128,7 @@ find_src_set_src (dataflow_set *set, rtx
 
   if (src && decl)
     {
-      slot = htab_find_slot_with_hash (set->vars, decl, 
+      slot = htab_find_slot_with_hash (shared_hash_htab (set->vars), decl,
 				       VARIABLE_HASH_VAL (decl), NO_INSERT);
 
       if (slot)
@@ -2031,7 +2161,7 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set *in = &VTI (bb)->in;
   dataflow_set *out = &VTI (bb)->out;
 
-  dataflow_set_init (&old_out, htab_elements (VTI (bb)->out.vars) + 3);
+  dataflow_set_init (&old_out);
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
@@ -2323,7 +2453,7 @@ dump_dataflow_set (dataflow_set *set)
 	  dump_attrs_list (set->regs[i]);
 	}
     }
-  dump_vars (set->vars);
+  dump_vars (shared_hash_htab (set->vars));
   fprintf (dump_file, "\n");
 }
 
@@ -2345,10 +2475,10 @@ dump_dataflow_sets (void)
 }
 
 /* Add variable VAR to the hash table of changed variables and
-   if it has no locations delete it from hash table HTAB.  */
+   if it has no locations delete it from SET's hash table.  */
 
 static void
-variable_was_changed (variable var, htab_t htab)
+variable_was_changed (variable var, dataflow_set *set)
 {
   hashval_t hash = VARIABLE_HASH_VAL (var->decl);
 
@@ -2359,36 +2489,44 @@ variable_was_changed (variable var, htab
       slot = (variable *) htab_find_slot_with_hash (changed_variables,
 						    var->decl, hash, INSERT);
 
-      if (htab && var->n_var_parts == 0)
+      if (set && var->n_var_parts == 0)
 	{
 	  variable empty_var;
-	  void **old;
 
 	  empty_var = (variable) pool_alloc (var_pool);
 	  empty_var->decl = var->decl;
 	  empty_var->refcount = 1;
 	  empty_var->n_var_parts = 0;
 	  *slot = empty_var;
-
-	  old = htab_find_slot_with_hash (htab, var->decl, hash,
-					  NO_INSERT);
-	  if (old)
-	    htab_clear_slot (htab, old);
+	  goto drop_var;
 	}
       else
 	{
+	  var->refcount++;
 	  *slot = var;
 	}
     }
   else
     {
-      gcc_assert (htab);
+      gcc_assert (set);
       if (var->n_var_parts == 0)
 	{
-	  void **slot = htab_find_slot_with_hash (htab, var->decl, hash,
-						  NO_INSERT);
+	  void **slot;
+
+	drop_var:
+	  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars),
+					   var->decl, hash, NO_INSERT);
 	  if (slot)
-	    htab_clear_slot (htab, slot);
+	    {
+	      if (shared_hash_shared (set->vars))
+		{
+		  set->vars = shared_hash_unshare (set->vars);
+		  slot
+		    = htab_find_slot_with_hash (shared_hash_htab (set->vars),
+						var->decl, hash, NO_INSERT);
+		}
+	      htab_clear_slot (shared_hash_htab (set->vars), slot);
+	    }
 	}
     }
 }
@@ -2440,10 +2578,19 @@ set_variable_part (dataflow_set *set, rt
   variable var;
   void **slot;
   
-  slot = htab_find_slot_with_hash (set->vars, decl,
-				   VARIABLE_HASH_VAL (decl), INSERT);
-  if (!*slot)
-    {
+  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars), decl,
+				   VARIABLE_HASH_VAL (decl),
+				   shared_hash_shared (set->vars)
+				   ? NO_INSERT : INSERT);
+  if (!slot || !*slot)
+    {
+      if (!slot)
+	{
+	  set->vars = shared_hash_unshare (set->vars);
+	  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars),
+					   decl, VARIABLE_HASH_VAL (decl),
+					   INSERT);
+	}
       /* Create new variable information.  */
       var = (variable) pool_alloc (var_pool);
       var->decl = decl;
@@ -2479,13 +2626,12 @@ set_variable_part (dataflow_set *set, rt
 	      if (set_src != NULL)
 		node->set_src = set_src;
 
-	      *slot = var;
 	      return;
 	    }
 	  else
 	    {
 	      /* We have to make a copy of a shared variable.  */
-	      if (var->refcount > 1)
+	      if (var->refcount > 1 || shared_hash_shared (set->vars))
 		var = unshare_variable (set, var, initialized);
 	    }
 	}
@@ -2494,7 +2640,7 @@ set_variable_part (dataflow_set *set, rt
 	  /* 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)
+	  if (var->refcount > 1 || shared_hash_shared (set->vars))
 	    var = unshare_variable (set, var, initialized);
 
 	  /* We track only variables whose size is <= MAX_VAR_PARTS bytes
@@ -2548,7 +2694,7 @@ set_variable_part (dataflow_set *set, rt
   if (var->var_part[pos].cur_loc == NULL)
     {
       var->var_part[pos].cur_loc = loc;
-      variable_was_changed (var, set->vars);
+      variable_was_changed (var, set);
     }
 }
 
@@ -2566,8 +2712,8 @@ clobber_variable_part (dataflow_set *set
   if (! decl || ! DECL_P (decl))
     return;
 
-  slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
-				   NO_INSERT);
+  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars), decl,
+				   VARIABLE_HASH_VAL (decl), NO_INSERT);
   if (slot)
     {
       variable var = (variable) *slot;
@@ -2629,8 +2775,8 @@ delete_variable_part (dataflow_set *set,
 {
   void **slot;
     
-  slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
-				   NO_INSERT);
+  slot = htab_find_slot_with_hash (shared_hash_htab (set->vars), decl,
+				   VARIABLE_HASH_VAL (decl), NO_INSERT);
   if (slot)
     {
       variable var = (variable) *slot;
@@ -2642,7 +2788,7 @@ delete_variable_part (dataflow_set *set,
 	  location_chain *nextp;
 	  bool changed;
 
-	  if (var->refcount > 1)
+	  if (var->refcount > 1 || shared_hash_shared (set->vars))
 	    {
 	      /* If the variable contains the location part we have to
 		 make a copy of the variable.  */
@@ -2705,7 +2851,7 @@ delete_variable_part (dataflow_set *set,
 		}
 	    }
 	  if (changed)
-	    variable_was_changed (var, set->vars);
+	    variable_was_changed (var, set);
 	}
     }
 }
@@ -2864,14 +3010,6 @@ emit_note_insn_var_location (void **varp
 
   htab_clear_slot (changed_variables, varp);
 
-  /* When there are no location parts the variable has been already
-     removed from hash table and a new empty variable was created.
-     Free the empty variable.  */
-  if (var->n_var_parts == 0)
-    {
-      pool_free (var_pool, var);
-    }
-
   /* Continue traversing the hash table.  */
   return 1;
 }
@@ -2910,7 +3048,7 @@ emit_notes_for_differences_1 (void **slo
 
       empty_var = (variable) pool_alloc (var_pool);
       empty_var->decl = old_var->decl;
-      empty_var->refcount = 1;
+      empty_var->refcount = 0;
       empty_var->n_var_parts = 0;
       variable_was_changed (empty_var, NULL);
     }
@@ -2952,8 +3090,12 @@ static void
 emit_notes_for_differences (rtx insn, dataflow_set *old_set,
 			    dataflow_set *new_set)
 {
-  htab_traverse (old_set->vars, emit_notes_for_differences_1, new_set->vars);
-  htab_traverse (new_set->vars, emit_notes_for_differences_2, old_set->vars);
+  htab_traverse (shared_hash_htab (old_set->vars),
+		 emit_notes_for_differences_1,
+		 shared_hash_htab (new_set->vars));
+  htab_traverse (shared_hash_htab (new_set->vars),
+		 emit_notes_for_differences_2,
+		 shared_hash_htab (old_set->vars));
   emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
 }
 
@@ -2965,7 +3107,7 @@ emit_notes_in_bb (basic_block bb)
   int i;
   dataflow_set set;
 
-  dataflow_set_init (&set, htab_elements (VTI (bb)->in.vars) + 3);
+  dataflow_set_init (&set);
   dataflow_set_copy (&set, &VTI (bb)->in);
 
   for (i = 0; i < VTI (bb)->n_mos; i++)
@@ -3098,7 +3240,7 @@ vt_emit_notes (void)
      delete_variable_part).  */
   emit_notes = true;
 
-  dataflow_set_init (&empty, 7);
+  dataflow_set_init (&empty);
   last_out = &empty;
 
   FOR_EACH_BB (bb)
@@ -3343,14 +3485,6 @@ vt_initialize (void)
 	}
     }
 
-  /* Init the IN and OUT sets.  */
-  FOR_ALL_BB (bb)
-    {
-      VTI (bb)->visited = false;
-      dataflow_set_init (&VTI (bb)->in, 7);
-      dataflow_set_init (&VTI (bb)->out, 7);
-    }
-
   attrs_pool = create_alloc_pool ("attrs_def pool",
 				  sizeof (struct attrs_def), 1024);
   var_pool = create_alloc_pool ("variable_def pool",
@@ -3358,8 +3492,24 @@ vt_initialize (void)
   loc_chain_pool = create_alloc_pool ("location_chain_def pool",
 				      sizeof (struct location_chain_def),
 				      1024);
+  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
+					sizeof (struct shared_hash_def), 256);
+  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
+  empty_shared_hash->refcount = 1;
+  empty_shared_hash->htab
+    = htab_create (1, variable_htab_hash, variable_htab_eq,
+		   variable_htab_free);
   changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
-				   NULL);
+				   variable_htab_free);
+
+  /* Init the IN and OUT sets.  */
+  FOR_ALL_BB (bb)
+    {
+      VTI (bb)->visited = false;
+      dataflow_set_init (&VTI (bb)->in);
+      dataflow_set_init (&VTI (bb)->out);
+    }
+
   vt_add_function_parameters ();
 }
 
@@ -3381,10 +3531,12 @@ vt_finalize (void)
       dataflow_set_destroy (&VTI (bb)->out);
     }
   free_aux_for_blocks ();
+  htab_delete (empty_shared_hash->htab);
+  htab_delete (changed_variables);
   free_alloc_pool (attrs_pool);
   free_alloc_pool (var_pool);
   free_alloc_pool (loc_chain_pool);
-  htab_delete (changed_variables);
+  free_alloc_pool (shared_hash_pool);
 }
 
 /* The entry point to variable tracking pass.  */

	Jakub


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