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]

[vta] Port of r148760 to vta branch


Hi!

Here is a port of the r148760 trunk commit to vta branch, on top of the
patch I've posted yesterday.
On the HTML401F.class testcase from x86_64-linux bootstrap the
compile times and maximum memory usage are:
			maxVIRT	maxRSS	TIME
vanilla VTA		2973004	2880412	24:47
VTA with 1st patch	2972964	2880396	18:54
VTA with both patches	1696492	1603936	17:55

So while the patch I've posted yesterday mainly improved compile time, this
one shaves off almost 1.3GB of memory used by the jc1 process.

I've bootstrapped/regtested this on x86_64-linux with the patch from
yesterday, this patch and the attached first P2-checking patch on top of it
for some extra checking.  Not sure if that checking isn't too ugly (looking
at hashtab entries bounds) or expensive even for ENABLE_CHECKING (the
!dataflow_set_different assert, so I'm not including that in this patch.

There are some small differences in debuginfo generated by this patch, but
they don't look wrong to me.  The last attached patch on top of it are
changes which result in no debuginfo differences on a > 2 x 500 preprocessed
sources (-m32 and -m64) set, but means we no longer can share any hashtables
if a basic block had two or more predecessors, so the patch is meant mainly
to show what changes in this large patch actually can make a difference in
the debuginfo.  It is mainly preferring variable objects from the former dst
set (i.e. one where we accumulate merges into) instead of from src (the bb
we are merging into it).

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

	* var-tracking.c (decl_or_value): Change from struct to just void *
	typedef.
	(struct shared_hash_def, shared_hash): New types.
	(dataflow_set): Change vars type from htab_t to shared_hash.
	Add traversed_vars.
	(shared_hash_pool, empty_shared_hash): New variables.
	(dv_is_decl_p, dv_is_value_p, dv_as_decl, dv_as_value,
	dv_as_opaque, dv_from_decl, dv_from_value): Adjust for decl_or_value
	changes.
	(variable_htab_eq): Don't expect y to be a pointer to decl_or_value,
	but decl_or_value itself.
	(vars_clear): Removed.
	(shared_hash_shared, shared_hash_htab, shared_hash_copy,
	shared_hash_find_slot_unshare, shared_hash_find_slot,
	shared_hash_find_slot_noinsert, shared_hash_find,
	shared_hash_find_slot_unshare_1, shared_hash_find_slot_1,
	shared_hash_find_slot_noinsert_1, shared_hash_find_1): New
	static inlines.
	(shared_hash_unshare, shared_hash_destroy): New functions.
	(dst_can_be_shared): New variable.
	(unshare_variable): Add set argument.  Unshare set->vars if shared,
	use shared_hash_*.  Clear dst_can_be_shared.  If set->traversed_vars
	is non-NULL and different from set->vars, look up slot again instead
	of using the passed in slot.
	(vars_copy_1): Pass src->dv to htab_find* instead of &src->dv.
	(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, val_reset): Use
	shared_hash_*.
	(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_*, use initially NO_INSERT
	lookup if set->vars is shared.  Don't keep slot cleared before
	calling unshare_variable.  Unshare set->vars if needed.  Adjust
	unshare_variable callers.  Clear dst_can_be_shared 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.
	(find_loc_in_1pdv, find_mem_expr_in_1pdv, vt_expand_loc_callback): Use
	htab_find_with_hash instead of htab_find_slot_with_hash, pass dv to
	it instead of &dv.
	(struct dfset_merge): Add src_onepart_cnt field.
	(intersect_loc_chains, canonicalize_values_mark,
	canonicalize_values_star): Use shared_hash_*.
	(variable_merge_over_cur): Likewise.  Clear dst_can_be_shared if
	needed.  Decrement dsm->src_onepart_cnt if s2var found.  Prefer
	s2var over s1var when not different.
	(variable_merge_over_src): Call variable_canonicalize after inserting
	the var into the hashtable instead of calling variable_union.
	For onepart dv increment dsm->src_onepart_cnt.
	(dataflow_set_merge): Create a new unshared empty hashtab for src,
	traverse first with variable_merge_over_src and then with
	variable_merge_over_cur, set dst_can_be_shared if dsm.src_onepart_cnt
	is non-zero.
	(dataflow_set_equiv_regs, variable_post_merge_perm_vals,
	dataflow_post_merge_adjust): Use shared_hash_*.
	(variable_post_merge_new_vals): Likewise.  Adjust unshare_variable and
	dataflow_set_init callers.
	(dataflow_set_preserve_mem_locs, dataflow_set_remove_mem_locs): Use
	shared_hash_*.  Adjust unshare_variable and variable_was_changed
	callers.
	(dataflow_set_clear_at_call): Use shared_hash_*.
	(dataflow_set_different_1): Pass var1->dv instead of &var1->dv to
	htab_find_with_hash.
	(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_*.
	(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.
	(vt_find_locations): Use shared_hash_*.  Use htab_size
	and htab_elements instead of ->size and ->n_elements.  Remove code
	to print out differences with -fdump-rtl-vartrack-details.  Initialize
	dst_can_be_shared, if it is true after merges and adjust, share
	in->vars with first_out->out->vars.
	(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.  Call htab_find_slot_with_hash with var->dv instead of
	&var->dv.
	(set_slot_part): Use shared_hash_*.  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.
	(set_variable_part): Use shared_hash_*.  If iopt is INSERT, unshare
	set->vars if shared and dv hasn't been found.
	(delete_slot_part): Use shared_hash_*.  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_*.
	(emit_note_insn_var_location): Don't pool_free var.
	(emit_notes_for_changes): Change last argument to shared_hash.
	(emit_notes_for_differences_1): Initialize empty_var->refcount to 0
	instead of 1.  Pass old_var->dv instead of &old_var->dv to
	htab_find_with_hash.
	(emit_notes_for_differences_2): Pass new_var->dv instead of
	&new_var->dv to htab_find_with_hash.
	(vt_finalize): Call htab_delete on empty_shared_hash->htab and
	free_alloc_pool on shared_hash_pool.

--- gcc/var-tracking.c.jj	2009-06-25 12:05:23.000000000 +0200
+++ gcc/var-tracking.c	2009-06-25 20:12:15.000000000 +0200
@@ -180,11 +180,7 @@ typedef struct micro_operation_def
 
 /* A declaration of a variable, or an RTL value being handled like a
    declaration.  */
-typedef struct decl_or_value
-{
-  /* An opaque pointer to the decl or the value.  */
-  void *ptr;
-} decl_or_value;
+typedef void *decl_or_value;
 
 /* Structure for passing some other parameters to function
    emit_note_insn_var_location.  */
@@ -219,6 +215,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
 {
@@ -229,7 +236,10 @@ typedef struct dataflow_set_def
   attrs regs[FIRST_PSEUDO_REGISTER];
 
   /* Variable locations.  */
-  htab_t vars;
+  shared_hash vars;
+
+  /* Vars that is being traversed.  */
+  shared_hash traversed_vars;
 } dataflow_set;
 
 /* The structure (one for each basic block) containing the information
@@ -331,12 +341,18 @@ static alloc_pool valvar_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;
+
 /* Scratch register bitmap used by cselib_expand_value_rtx.  */
 static bitmap scratch_regs = NULL;
 
@@ -362,8 +378,7 @@ 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 (void **slot, variable var,
+static variable unshare_variable (dataflow_set *set, void **slot, variable var,
 				  enum var_init_status);
 static int vars_copy_1 (void **, void *);
 static void vars_copy (htab_t, htab_t);
@@ -378,11 +393,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 location_chain find_loc_in_1pdv (rtx, variable, htab_t);
 static bool canon_value_cmp (rtx, rtx);
@@ -414,7 +430,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_slot_part (dataflow_set *, rtx, void **,
 			   decl_or_value, HOST_WIDE_INT,
 			   enum var_init_status, rtx);
@@ -429,7 +445,7 @@ static void delete_slot_part (dataflow_s
 static void delete_variable_part (dataflow_set *, rtx,
 				  decl_or_value, HOST_WIDE_INT);
 static int emit_note_insn_var_location (void **, void *);
-static void emit_notes_for_changes (rtx, enum emit_note_where, htab_t vars);
+static void emit_notes_for_changes (rtx, enum emit_note_where, shared_hash);
 static int emit_notes_for_differences_1 (void **, void *);
 static int emit_notes_for_differences_2 (void **, void *);
 static void emit_notes_for_differences (rtx, dataflow_set *, dataflow_set *);
@@ -684,10 +700,10 @@ adjust_stack_reference (rtx mem, HOST_WI
 static inline bool
 dv_is_decl_p (decl_or_value dv)
 {
-  if (!dv.ptr)
+  if (!dv)
     return false;
 
-  if (GET_CODE ((rtx)dv.ptr) == VALUE)
+  if (GET_CODE ((rtx)dv) == VALUE)
     return false;
 
   return true;
@@ -697,7 +713,7 @@ dv_is_decl_p (decl_or_value dv)
 static inline bool
 dv_is_value_p (decl_or_value dv)
 {
-  return dv.ptr && !dv_is_decl_p (dv);
+  return dv && !dv_is_decl_p (dv);
 }
 
 /* Return the decl in the decl_or_value.  */
@@ -705,7 +721,7 @@ static inline tree
 dv_as_decl (decl_or_value dv)
 {
   gcc_assert (dv_is_decl_p (dv));
-  return (tree) dv.ptr;
+  return (tree) dv;
 }
 
 /* Return the value in the decl_or_value.  */
@@ -713,14 +729,14 @@ static inline rtx
 dv_as_value (decl_or_value dv)
 {
   gcc_assert (dv_is_value_p (dv));
-  return (rtx)dv.ptr;
+  return (rtx)dv;
 }
 
 /* Return the opaque pointer in the decl_or_value.  */
 static inline void *
 dv_as_opaque (decl_or_value dv)
 {
-  return dv.ptr;
+  return dv;
 }
 
 /* Return true if a decl_or_value must not have more than one variable
@@ -766,7 +782,7 @@ dv_from_decl (tree decl)
 {
   decl_or_value dv;
   gcc_assert (!decl || IS_DECL_CODE (TREE_CODE (decl)));
-  dv.ptr = decl;
+  dv = decl;
   return dv;
 }
 
@@ -776,7 +792,7 @@ dv_from_value (rtx value)
 {
   decl_or_value dv;
   gcc_assert (value);
-  dv.ptr = value;
+  dv = value;
   return dv;
 }
 
@@ -806,7 +822,7 @@ static int
 variable_htab_eq (const void *x, const void *y)
 {
   const_variable const v = (const_variable) x;
-  decl_or_value dv = *(decl_or_value const*)y;
+  decl_or_value dv = CONST_CAST2 (decl_or_value, const void *, y);
 
   if (dv_as_opaque (v->dv) == dv_as_opaque (dv))
     return true;
@@ -964,18 +980,137 @@ attrs_list_mpdv_union (attrs *dstp, attr
     }
 }
 
-/* Delete all variables from hash table VARS.  */
+/* Shared hashtable support.  */
+
+/* Return true if VARS is shared.  */
+
+static inline bool
+shared_hash_shared (shared_hash vars)
+{
+  return vars->refcount > 1;
+}
+
+/* Return the hash table for VARS.  */
+
+static inline htab_t
+shared_hash_htab (shared_hash vars)
+{
+  return vars->htab;
+}
+
+/* Copy variables into a new hash table.  */
+
+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;
+}
+
+/* Increment reference counter on VARS and return it.  */
+
+static inline shared_hash
+shared_hash_copy (shared_hash vars)
+{
+  vars->refcount++;
+  return vars;
+}
+
+/* Decrement reference counter and destroy hash table if not shared
+   anymore.  */
 
 static void
-vars_clear (htab_t vars)
+shared_hash_destroy (shared_hash vars)
+{
+  gcc_assert (vars->refcount > 0);
+  if (--vars->refcount == 0)
+    {
+      htab_delete (vars->htab);
+      pool_free (shared_hash_pool, vars);
+    }
+}
+
+/* Unshare *PVARS if shared and return slot for DV.  If INS is
+   INSERT, insert it if not already present.  */
+
+static inline void **
+shared_hash_find_slot_unshare_1 (shared_hash *pvars, decl_or_value dv,
+				 hashval_t dvhash, enum insert_option ins)
+{
+  if (shared_hash_shared (*pvars))
+    *pvars = shared_hash_unshare (*pvars);
+  return htab_find_slot_with_hash (shared_hash_htab (*pvars), dv, dvhash, ins);
+}
+
+static inline void **
+shared_hash_find_slot_unshare (shared_hash *pvars, decl_or_value dv,
+			       enum insert_option ins)
+{
+  return shared_hash_find_slot_unshare_1 (pvars, dv, dv_htab_hash (dv), ins);
+}
+
+/* Return slot for DV, if it is already present in the hash table.
+   If it is not present, insert it only VARS is not shared, otherwise
+   return NULL.  */
+
+static inline void **
+shared_hash_find_slot_1 (shared_hash vars, decl_or_value dv, hashval_t dvhash)
+{
+  return htab_find_slot_with_hash (shared_hash_htab (vars), dv, dvhash,
+				   shared_hash_shared (vars)
+				   ? NO_INSERT : INSERT);
+}
+
+static inline void **
+shared_hash_find_slot (shared_hash vars, decl_or_value dv)
+{
+  return shared_hash_find_slot_1 (vars, dv, dv_htab_hash (dv));
+}
+
+/* Return slot for DV only if it is already present in the hash table.  */
+
+static inline void **
+shared_hash_find_slot_noinsert_1 (shared_hash vars, decl_or_value dv,
+				  hashval_t dvhash)
 {
-  htab_empty (vars);
+  return htab_find_slot_with_hash (shared_hash_htab (vars), dv, dvhash,
+				   NO_INSERT);
+}
+
+static inline void **
+shared_hash_find_slot_noinsert (shared_hash vars, decl_or_value dv)
+{
+  return shared_hash_find_slot_noinsert_1 (vars, dv, dv_htab_hash (dv));
 }
 
+/* Return variable for DV or NULL if not already present in the hash
+   table.  */
+
+static inline variable
+shared_hash_find_1 (shared_hash vars, decl_or_value dv, hashval_t dvhash)
+{
+  return (variable) htab_find_with_hash (shared_hash_htab (vars), dv, dvhash);
+}
+
+static inline variable
+shared_hash_find (shared_hash vars, decl_or_value dv)
+{
+  return shared_hash_find_1 (vars, dv, dv_htab_hash (dv));
+}
+
+static bool dst_can_be_shared;
+
 /* Return a copy of a variable VAR and insert it to dataflow set SET.  */
 
 static variable
-unshare_variable (void **slot, variable var,
+unshare_variable (dataflow_set *set, void **slot, variable var,
 		  enum var_init_status initialized)
 {
   variable new_var;
@@ -1022,6 +1157,11 @@ unshare_variable (void **slot, variable 
 	new_var->var_part[i].cur_loc = NULL;
     }
 
+  dst_can_be_shared = false;
+  if (shared_hash_shared (set->vars))
+    slot = shared_hash_find_slot_unshare (&set->vars, var->dv, NO_INSERT);
+  else if (set->traversed_vars && set->vars != set->traversed_vars)
+    slot = shared_hash_find_slot_noinsert (set->vars, var->dv);
   *slot = new_var;
   return new_var;
 }
@@ -1039,7 +1179,7 @@ vars_copy_1 (void **slot, void *data)
   src = (variable) *slot;
   src->refcount++;
 
-  dstp = htab_find_slot_with_hash (dst, &src->dv,
+  dstp = htab_find_slot_with_hash (dst, src->dv,
 				   dv_htab_hash (src->dv),
 				   INSERT);
   *dstp = src;
@@ -1053,8 +1193,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.  */
@@ -1108,7 +1247,6 @@ var_reg_set (dataflow_set *set, rtx loc,
 static enum var_init_status
 get_init_value (dataflow_set *set, rtx loc, decl_or_value dv)
 {
-  void **slot;
   variable var;
   int i;
   enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN;
@@ -1116,11 +1254,9 @@ 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, &dv,
-				   dv_htab_hash (dv), NO_INSERT);
-  if (slot)
+  var = shared_hash_find (set->vars, dv);
+  if (var)
     {
-      var = (variable) *slot;
       for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
 	{
 	  location_chain nextp;
@@ -1339,17 +1475,11 @@ val_store (dataflow_set *set, rtx val, r
 static void
 val_reset (dataflow_set *set, decl_or_value dv)
 {
-  void **slot = htab_find_slot_with_hash (set->vars, &dv, dv_htab_hash (dv),
-					  NO_INSERT);
-  variable var;
+  variable var = shared_hash_find (set->vars, dv) ;
   location_chain node;
   rtx cval;
 
-  if (!slot)
-    return;
-
-  var = (variable)*slot;
-  if (!var->n_var_parts)
+  if (!var || !var->n_var_parts)
     return;
 
   gcc_assert (var->n_var_parts == 1);
@@ -1474,12 +1604,12 @@ val_resolve (dataflow_set *set, rtx val,
    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;
+  set->traversed_vars = NULL;
 }
 
 /* Delete the contents of dataflow set SET.  */
@@ -1492,7 +1622,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.  */
@@ -1505,7 +1636,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;
 }
 
@@ -1559,13 +1691,17 @@ variable_union (void **slot, void *data)
   int i, j, k;
 
   src = (variable) *slot;
-  dstp = htab_find_slot_with_hash (set->vars, &src->dv,
-				   dv_htab_hash (src->dv),
-				   INSERT);
-  if (!*dstp)
+  dstp = shared_hash_find_slot (set->vars, src->dv);
+  if (!dstp || !*dstp)
     {
       src->refcount++;
 
+      dst_can_be_shared = false;
+      if (!dstp)
+	dstp = shared_hash_find_slot_unshare (&set->vars, src->dv, INSERT);
+
+      *dstp = src;
+
       /* 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.  */
@@ -1587,10 +1723,8 @@ variable_union (void **slot, void *data)
 	  if (! flag_var_tracking_uninit)
 	    status = VAR_INIT_STATUS_INITIALIZED;
 
-	  unshare_variable (dstp, src, status);
+	  unshare_variable (set, dstp, src, status);
 	}
-      else
-	*dstp = src;
 
       /* Continue traversing the hash table.  */
       return 1;
@@ -1625,9 +1759,9 @@ variable_union (void **slot, void *data)
 	    {
 	      location_chain nnode;
 
-	      if (dst->refcount != 1)
+	      if (dst->refcount != 1 || shared_hash_shared (set->vars))
 		{
-		  dst = unshare_variable (dstp, dst,
+		  dst = unshare_variable (set, dstp, dst,
 					  VAR_INIT_STATUS_INITIALIZED);
 		  goto restart_onepart_unshared;
 		}
@@ -1678,13 +1812,14 @@ variable_union (void **slot, void *data)
      thus there are at most MAX_VAR_PARTS different offsets.  */
   gcc_assert (dv_onepart_p (dst->dv) ? k == 1 : 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;
       
       if (! flag_var_tracking_uninit)
 	status = VAR_INIT_STATUS_INITIALIZED;
-      dst = unshare_variable (dstp, dst, status);
+      dst = unshare_variable (set, dstp, dst, status);
     }
 
   i = src->n_var_parts - 1;
@@ -1708,7 +1843,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;
@@ -1725,7 +1860,8 @@ variable_union (void **slot, void *data)
 		    }
 		}
 	      if (node || node2)
-		dst = unshare_variable (dstp, dst, VAR_INIT_STATUS_UNKNOWN);
+		dst = unshare_variable (set, dstp, dst,
+					VAR_INIT_STATUS_UNKNOWN);
 	    }
 
 	  src_l = 0;
@@ -1861,6 +1997,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, slot, src, status);
+    }
+  return 1;
+}
+
 /* Compute union of dataflow sets SRC and DST and store it to DST.  */
 
 static void
@@ -1871,7 +2047,16 @@ 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);
+      dst->traversed_vars = dst->vars;
+      htab_traverse (shared_hash_htab (dst->vars), variable_canonicalize, dst);
+      dst->traversed_vars = NULL;
+    }
+  else
+    htab_traverse (shared_hash_htab (src->vars), variable_union, dst);
 }
 
 /* Whether the value is currently being expanded.  */
@@ -1931,14 +2116,14 @@ find_loc_in_1pdv (rtx loc, variable var,
 	     && !VALUE_RECURSED_INTO (node->loc))
       {
 	decl_or_value dv = dv_from_value (node->loc);
-	void **slot = htab_find_slot_with_hash (vars, &dv, dv_htab_hash (dv),
-						NO_INSERT);
+	variable var = (variable)
+		       htab_find_with_hash (vars, dv, dv_htab_hash (dv));
 
-	if (slot)
+	if (var)
 	  {
 	    location_chain where;
 	    VALUE_RECURSED_INTO (node->loc) = true;
-	    if ((where = find_loc_in_1pdv (loc, (variable)*slot, vars)))
+	    if ((where = find_loc_in_1pdv (loc, var, vars)))
 	      {
 		VALUE_RECURSED_INTO (node->loc) = false;
 		return where;
@@ -1959,6 +2144,8 @@ struct dfset_merge
   dataflow_set *cur;
   /* The set that may contain the other dv we are to merge with.  */
   dataflow_set *src;
+  /* Number of onepart dvs in src.  */
+  int src_onepart_cnt;
 };
 
 /* Insert LOC in *DNODE, if it's not there yet.  The list must be in
@@ -2007,7 +2194,8 @@ intersect_loc_chains (rtx val, location_
       if (s1node->loc == val)
 	continue;
 
-      if ((found = find_loc_in_1pdv (s1node->loc, s2var, s2set->vars)))
+      if ((found = find_loc_in_1pdv (s1node->loc, s2var,
+				     shared_hash_htab (s2set->vars))))
 	{
 	  insert_into_intersection (dest, s1node->loc,
 				    MIN (s1node->init, found->init));
@@ -2018,14 +2206,9 @@ intersect_loc_chains (rtx val, location_
 	  && !VALUE_RECURSED_INTO (s1node->loc))
 	{
 	  decl_or_value dv = dv_from_value (s1node->loc);
-	  void **slot = htab_find_slot_with_hash (s1set->vars,
-						  &dv, dv_htab_hash (dv),
-						  NO_INSERT);
-
-	  if (slot)
+	  variable svar = shared_hash_find (s1set->vars, dv);
+	  if (svar)
 	    {
-	      variable svar = (variable)*slot;
-
 	      if (svar->n_var_parts == 1)
 		{
 		  VALUE_RECURSED_INTO (s1node->loc) = true;
@@ -2298,9 +2481,8 @@ canonicalize_values_mark (void **slot, v
 	else
 	  {
 	    decl_or_value odv = dv_from_value (node->loc);
-	    void **oslot = htab_find_slot_with_hash (set->vars, &odv,
-						     dv_htab_hash (odv),
-						     NO_INSERT);
+	    void **oslot = shared_hash_find_slot_noinsert (set->vars, odv);
+
 #if 0 && ENABLE_CHECKING
 	    variable ovar;
 	    location_chain onode;
@@ -2396,8 +2578,7 @@ canonicalize_values_star (void **slot, v
 	  restart_with_cval:
 	    VALUE_RECURSED_INTO (cval) = false;
 	    dv = dv_from_value (cval);
-	    slot = htab_find_slot_with_hash (set->vars, &dv, dv_htab_hash (dv),
-					     NO_INSERT);
+	    slot = shared_hash_find_slot_noinsert (set->vars, dv);
 	    if (!slot)
 	      {
 		gcc_assert (dv_is_decl_p (var->dv));
@@ -2421,8 +2602,7 @@ canonicalize_values_star (void **slot, v
 
   /* Push values to the canonical one.  */
   cdv = dv_from_value (cval);
-  cslot = htab_find_slot_with_hash (set->vars, &cdv, dv_htab_hash (cdv),
-				    NO_INSERT);
+  cslot = shared_hash_find_slot_noinsert (set->vars, cdv);
 
   for (node = var->var_part[0].loc_chain; node; node = node->next)
     if (node->loc != cval)
@@ -2572,7 +2752,7 @@ variable_merge_over_cur (void **s1slot, 
 {
   struct dfset_merge *dsm = (struct dfset_merge *)data;
   dataflow_set *dst = dsm->dst;
-  void **s2slot, **dstslot;
+  void **dstslot;
   variable s1var = (variable) *s1slot;
   variable s2var, dvar = NULL;
   decl_or_value dv = s1var->dv;
@@ -2599,18 +2779,19 @@ variable_merge_over_cur (void **s1slot, 
   else
     val = NULL;
 
-  s2slot = htab_find_slot_with_hash (dsm->src->vars, &dv, dvhash, NO_INSERT);
-  if (!s2slot)
-    return 1;
-
-  s2var = (variable) *s2slot;
+  s2var = shared_hash_find_1 (dsm->src->vars, dv, dvhash);
+  if (!s2var)
+    {
+      dst_can_be_shared = false;
+      return 1;
+    }
 
+  dsm->src_onepart_cnt--;
   gcc_assert (s2var->var_part[0].loc_chain);
   gcc_assert (s2var->n_var_parts == 1);
   gcc_assert (s2var->var_part[0].offset == 0);
 
-  dstslot = htab_find_slot_with_hash (dst->vars, &dv, dvhash, NO_INSERT);
-
+  dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
   if (dstslot)
     {
       dvar = (variable)*dstslot;
@@ -2627,13 +2808,15 @@ variable_merge_over_cur (void **s1slot, 
 
   if (!dstslot && !onepart_variable_different_p (s1var, s2var))
     {
-      dstslot = htab_find_slot_with_hash (dst->vars, &dv, dvhash,
-					  INSERT);
-      *dstslot = dvar = s1var;
+      dstslot = shared_hash_find_slot_unshare_1 (&dst->vars, dv,
+						 dvhash, INSERT);
+      *dstslot = dvar = s2var;
       dvar->refcount++;
     }
   else
     {
+      dst_can_be_shared = false;
+
       intersect_loc_chains (val, nodep, dsm,
 			    s1var->var_part[0].loc_chain, s2var);
 
@@ -2649,8 +2832,9 @@ variable_merge_over_cur (void **s1slot, 
 	      dvar->var_part[0].loc_chain = node;
 	      dvar->var_part[0].cur_loc = node->loc;
 
-	      dstslot = htab_find_slot_with_hash (dst->vars, &dv, dvhash,
-						  INSERT);
+	      dstslot
+		= shared_hash_find_slot_unshare_1 (&dst->vars, dv, dvhash,
+						   INSERT);
 	      gcc_assert (!*dstslot);
 	      *dstslot = dvar;
 	    }
@@ -2719,12 +2903,13 @@ variable_merge_over_cur (void **s1slot, 
 			       node->init, NULL, INSERT);
 	  }
 
-      dstslot = htab_find_slot_with_hash (dst->vars, &dv, dvhash,
-					  NO_INSERT);
+      dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
       gcc_assert (*dstslot == dvar);
       canonicalize_values_star (dstslot, dst);
-      gcc_assert (dstslot == htab_find_slot_with_hash (dst->vars, &dv,
-						       dvhash, NO_INSERT));
+#ifdef ENABLE_CHECKING
+      gcc_assert (dstslot
+		  == shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash));
+#endif
       dvar = (variable)*dstslot;
     }
   else
@@ -2761,8 +2946,12 @@ variable_merge_over_cur (void **s1slot, 
 	      if (GET_CODE (node->loc) == VALUE)
 		{
 		  decl_or_value dv = dv_from_value (node->loc);
-		  void **slot = htab_find_slot_with_hash (dst->vars, &dv,
-							  dv_htab_hash (dv),
+		  void **slot = NULL;
+
+		  if (shared_hash_shared (dst->vars))
+		    slot = shared_hash_find_slot_noinsert (dst->vars, dv);
+		  if (!slot)
+		    slot = shared_hash_find_slot_unshare (&dst->vars, dv,
 							  INSERT);
 		  if (!*slot)
 		    {
@@ -2780,31 +2969,37 @@ variable_merge_over_cur (void **s1slot, 
 		}
 	    }
 
-	  dstslot = htab_find_slot_with_hash (dst->vars, &dv, dvhash,
-					      NO_INSERT);
+	  dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
 	  gcc_assert (*dstslot == dvar);
 	  canonicalize_values_star (dstslot, dst);
-	  gcc_assert (dstslot == htab_find_slot_with_hash (dst->vars, &dv,
-							   dvhash,
-							   NO_INSERT));
+#ifdef ENABLE_CHECKING
+	  gcc_assert (dstslot
+		      == shared_hash_find_slot_noinsert_1 (dst->vars,
+							   dv, dvhash));
+#endif
 	  dvar = (variable)*dstslot;
 	}
     }
 
-  if (!onepart_variable_different_p (dvar, s1var))
+  if (!onepart_variable_different_p (dvar, s2var))
     {
       variable_htab_free (dvar);
-      *dstslot = dvar = s1var;
+      *dstslot = dvar = s2var;
       dvar->refcount++;
     }
-  else if (s2var != s1var && !onepart_variable_different_p (dvar, s2var))
+  else if (s2var != s1var && !onepart_variable_different_p (dvar, s1var))
     {
       variable_htab_free (dvar);
-      *dstslot = dvar = s2var;
+      *dstslot = dvar = s1var;
       dvar->refcount++;
+      dst_can_be_shared = false;
+    }
+  else
+    {
+      if (dvar->refcount == 1)
+        dvar->var_part[0].cur_loc = dvar->var_part[0].loc_chain->loc;
+      dst_can_be_shared = false;
     }
-  else if (dvar->refcount == 1)
-    dvar->var_part[0].cur_loc = dvar->var_part[0].loc_chain->loc;
 
   return 1;
 }
@@ -2824,8 +3019,14 @@ variable_merge_over_src (void **s2slot, 
   bool onepart = dv_onepart_p (dv);
 
   if (!onepart)
-    return variable_union (s2slot, dst);
+    {
+      void **dstp = shared_hash_find_slot (dst->vars, dv);
+      *dstp = s2var;
+      s2var->refcount++;
+      return variable_canonicalize (dstp, dst);
+    }
 
+  dsm->src_onepart_cnt++;
   return 1;
 }
 
@@ -2838,9 +3039,18 @@ dataflow_set_merge (dataflow_set *dst, d
   dataflow_set src2 = *dst;
   struct dfset_merge dsm;
   int i;
+  size_t src_elems, dst_elems;
 
-  dataflow_set_init (dst, MAX (htab_elements (src->vars),
-			       htab_elements (src2.vars)));
+  src_elems = htab_elements (shared_hash_htab (src->vars));
+  dst_elems = htab_elements (shared_hash_htab (src2.vars));
+  dataflow_set_init (dst);
+  dst->stack_adjust = src2.stack_adjust;
+  shared_hash_destroy (dst->vars);
+  dst->vars = (shared_hash) pool_alloc (shared_hash_pool);
+  dst->vars->refcount = 1;
+  dst->vars->htab
+    = htab_create (MAX (src_elems, dst_elems), variable_htab_hash,
+		   variable_htab_eq, variable_htab_free);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     attrs_list_mpdv_union (&dst->regs[i], src->regs[i], src2.regs[i]);
@@ -2848,9 +3058,15 @@ dataflow_set_merge (dataflow_set *dst, d
   dsm.dst = dst;
   dsm.src = &src2;
   dsm.cur = src;
+  dsm.src_onepart_cnt = 0;
 
-  htab_traverse (dsm.cur->vars, variable_merge_over_cur, &dsm);
-  htab_traverse (dsm.src->vars, variable_merge_over_src, &dsm);
+  htab_traverse (shared_hash_htab (dsm.src->vars), variable_merge_over_src,
+		 &dsm);
+  htab_traverse (shared_hash_htab (dsm.cur->vars), variable_merge_over_cur,
+		 &dsm);
+
+  if (dsm.src_onepart_cnt)
+    dst_can_be_shared = false;
 
   dataflow_set_destroy (&src2);
 }
@@ -2923,9 +3139,7 @@ dataflow_set_equiv_regs (dataflow_set *s
 		  continue;
 	      }
 
-	    slot = htab_find_slot_with_hash (set->vars, &list->dv,
-					     dv_htab_hash (list->dv),
-					     NO_INSERT);
+	    slot = shared_hash_find_slot_noinsert (set->vars, list->dv);
 	    canonicalize_values_star (slot, set);
 	    if (*listp != list)
 	      list = NULL;
@@ -3012,7 +3226,7 @@ variable_post_merge_new_vals (void **slo
 
 	      if (var->refcount != 1)
 		{
-		  var = unshare_variable (slot, var,
+		  var = unshare_variable (set, slot, var,
 					  VAR_INIT_STATUS_INITIALIZED);
 		  goto restart;
 		}
@@ -3054,7 +3268,7 @@ variable_post_merge_new_vals (void **slo
 		  if (!*dfpm->permp)
 		    {
 		      *dfpm->permp = XNEW (dataflow_set);
-		      dataflow_set_init (*dfpm->permp, 7);
+		      dataflow_set_init (*dfpm->permp);
 		    }
 
 		  for (att = (*dfpm->permp)->regs[REGNO (node->loc)];
@@ -3121,7 +3335,7 @@ variable_post_merge_new_vals (void **slo
 
 	      if (var->refcount != 1)
 		{
-		  var = unshare_variable (slot, var,
+		  var = unshare_variable (set, slot, var,
 					  VAR_INIT_STATUS_INITIALIZED);
 		  goto restart;
 		}
@@ -3143,9 +3357,7 @@ variable_post_merge_new_vals (void **slo
 	      cval = v->val_rtx;
 	      cdv = dv_from_value (cval);
 
-	      oslot = htab_find_slot_with_hash
-		(set->vars, &cdv, dv_htab_hash (cdv), NO_INSERT);
-
+	      oslot = shared_hash_find_slot_noinsert (set->vars, cdv);
 	      if (oslot)
 		set_slot_part (set, node->loc, oslot, cdv, 0,
 			       VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
@@ -3154,7 +3366,7 @@ variable_post_merge_new_vals (void **slo
 		  if (!*dfpm->permp)
 		    {
 		      *dfpm->permp = XNEW (dataflow_set);
-		      dataflow_set_init (*dfpm->permp, 7);
+		      dataflow_set_init (*dfpm->permp);
 		    }
 
 		  set_variable_part (*dfpm->permp, node->loc, cdv, 0,
@@ -3182,9 +3394,8 @@ variable_post_merge_perm_vals (void **ps
 {
   struct dfset_post_merge *dfpm = (struct dfset_post_merge *)info;
   dataflow_set *set = dfpm->set;
-  variable pvar = (variable)*pslot;
+  variable pvar = (variable)*pslot, var;
   location_chain pnode;
-  void **slot;
   decl_or_value dv;
   attrs att;
 
@@ -3197,12 +3408,10 @@ variable_post_merge_perm_vals (void **ps
 
   dv = pvar->dv;
 
-  slot = htab_find_slot_with_hash (set->vars, &dv, dv_htab_hash (dv),
-				   NO_INSERT);
-
-  if (slot)
+  var = shared_hash_find (set->vars, dv);
+  if (var)
     {
-      if (find_loc_in_1pdv (pnode->loc, (variable)*slot, set->vars))
+      if (find_loc_in_1pdv (pnode->loc, var, shared_hash_htab (set->vars)))
 	return 1;
       val_reset (set, dv);
     }
@@ -3243,10 +3452,12 @@ dataflow_post_merge_adjust (dataflow_set
   dfpm.set = set;
   dfpm.permp = permp;
 
-  htab_traverse (set->vars, variable_post_merge_new_vals, &dfpm);
+  htab_traverse (shared_hash_htab (set->vars), variable_post_merge_new_vals,
+		 &dfpm);
   if (*permp)
-    htab_traverse ((*permp)->vars, variable_post_merge_perm_vals, &dfpm);
-  htab_traverse (set->vars, canonicalize_values_star, set);
+    htab_traverse (shared_hash_htab ((*permp)->vars),
+		   variable_post_merge_perm_vals, &dfpm);
+  htab_traverse (shared_hash_htab (set->vars), canonicalize_values_star, set);
 }
 
 /* Return a node whose loc is a MEM that refers to EXPR in the
@@ -3258,7 +3469,6 @@ find_mem_expr_in_1pdv (tree expr, rtx va
 {
   location_chain node;
   decl_or_value dv;
-  void **slot;
   variable var;
   location_chain where = NULL;
 
@@ -3270,14 +3480,11 @@ find_mem_expr_in_1pdv (tree expr, rtx va
   gcc_assert (!VALUE_RECURSED_INTO (val));
 
   dv = dv_from_value (val);
-  slot = htab_find_slot_with_hash (vars, &dv, dv_htab_hash (dv), NO_INSERT);
+  var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
 
-  if (!slot)
+  if (!var)
     return NULL;
 
-  var = (variable)*slot;
-
-  gcc_assert (var);
   gcc_assert (dv_onepart_p (var->dv));
 
   if (!var->n_var_parts)
@@ -3315,7 +3522,7 @@ find_mem_expr_in_1pdv (tree expr, rtx va
 static int
 dataflow_set_preserve_mem_locs (void **slot, void *data)
 {
-  htab_t vars = (htab_t) data;
+  dataflow_set *set = (dataflow_set *) data;
   variable var = (variable) *slot;
 
   if (dv_is_decl_p (var->dv) && dv_onepart_p (var->dv))
@@ -3328,7 +3535,7 @@ dataflow_set_preserve_mem_locs (void **s
 
       gcc_assert (var->n_var_parts == 1);
 
-      if (var->refcount > 1)
+      if (var->refcount > 1 || shared_hash_shared (set->vars))
 	{
 	  for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
 	    {
@@ -3339,14 +3546,15 @@ dataflow_set_preserve_mem_locs (void **s
 		break;
 	      /* We want to move here a MEM that does refer to DECL.  */
 	      else if (GET_CODE (loc->loc) == VALUE
-		       && find_mem_expr_in_1pdv (decl, loc->loc, vars))
+		       && find_mem_expr_in_1pdv (decl, loc->loc,
+						 shared_hash_htab (set->vars)))
 	      break;
 	    }
 
 	  if (!loc)
 	    return 1;
 
-	  var = unshare_variable (slot, var, VAR_INIT_STATUS_UNKNOWN);
+	  var = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN);
 	  gcc_assert (var->n_var_parts == 1);
 	}
 
@@ -3355,8 +3563,9 @@ dataflow_set_preserve_mem_locs (void **s
 	{
 	  if (GET_CODE (loc->loc) == VALUE)
 	    {
-	      location_chain mem_node = find_mem_expr_in_1pdv (decl, loc->loc,
-							       vars);
+	      location_chain mem_node
+		= find_mem_expr_in_1pdv (decl, loc->loc,
+					 shared_hash_htab (set->vars));
 
 	      /* ??? This picks up only one out of multiple MEMs that
 		 refer to the same variable.  Do we ever need to be
@@ -3387,7 +3596,7 @@ dataflow_set_preserve_mem_locs (void **s
       if (!var->var_part[0].loc_chain)
 	{
 	  var->n_var_parts--;
-	  variable_was_changed (var, vars);
+	  variable_was_changed (var, set);
 	}
     }
 
@@ -3400,7 +3609,7 @@ dataflow_set_preserve_mem_locs (void **s
 static int
 dataflow_set_remove_mem_locs (void **slot, void *data)
 {
-  htab_t vars = (htab_t) data;
+  dataflow_set *set = (dataflow_set *) data;
   variable var = (variable) *slot;
 
   if (dv_is_value_p (var->dv))
@@ -3410,7 +3619,7 @@ dataflow_set_remove_mem_locs (void **slo
 
       gcc_assert (var->n_var_parts == 1);
 
-      if (var->refcount > 1)
+      if (var->refcount > 1 || shared_hash_shared (set->vars))
 	{
 	  for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
 	    if (GET_CODE (loc->loc) == MEM)
@@ -3419,7 +3628,7 @@ dataflow_set_remove_mem_locs (void **slo
 	  if (!loc)
 	    return 1;
 
-	  var = unshare_variable (slot, var, VAR_INIT_STATUS_UNKNOWN);
+	  var = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN);
 	  gcc_assert (var->n_var_parts == 1);
 	}
 
@@ -3451,7 +3660,7 @@ dataflow_set_remove_mem_locs (void **slo
 	{
 	  if (var->n_var_parts && var->var_part[0].loc_chain)
 	    var->var_part[0].cur_loc = var->var_part[0].loc_chain->loc;
-	  variable_was_changed (var, vars);
+	  variable_was_changed (var, set);
 	}
     }
 
@@ -3472,8 +3681,13 @@ dataflow_set_clear_at_call (dataflow_set
 
   if (MAY_HAVE_DEBUG_INSNS)
     {
-      htab_traverse (set->vars, dataflow_set_preserve_mem_locs, set->vars);
-      htab_traverse (set->vars, dataflow_set_remove_mem_locs, set->vars);
+      set->traversed_vars = set->vars;
+      htab_traverse (shared_hash_htab (set->vars),
+		     dataflow_set_preserve_mem_locs, set);
+      set->traversed_vars = set->vars;
+      htab_traverse (shared_hash_htab (set->vars), dataflow_set_remove_mem_locs,
+		     set);
+      set->traversed_vars = NULL;
     }
 }
 
@@ -3590,7 +3804,7 @@ dataflow_set_different_1 (void **slot, v
   variable var1, var2;
 
   var1 = (variable) *slot;
-  var2 = (variable) htab_find_with_hash (htab, &var1->dv,
+  var2 = (variable) htab_find_with_hash (htab, var1->dv,
 					 dv_htab_hash (var1->dv));
   if (!var2)
     {
@@ -3635,7 +3849,7 @@ dataflow_set_different_2 (void **slot, v
   variable var1, var2;
 
   var1 = (variable) *slot;
-  var2 = (variable) htab_find_with_hash (htab, &var1->dv,
+  var2 = (variable) htab_find_with_hash (htab, var1->dv,
 					 dv_htab_hash (var1->dv));
   if (!var2)
     {
@@ -3664,15 +3878,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;
 }
@@ -3687,7 +3910,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;
 }
 
@@ -4684,7 +4907,6 @@ find_src_set_src (dataflow_set *set, rtx
 {
   tree decl = NULL_TREE;   /* The variable being copied around.          */
   rtx set_src = NULL_RTX;  /* The value for "decl" stored in "src".      */
-  void **slot;
   variable var;
   location_chain nextp;
   int i;
@@ -4699,12 +4921,9 @@ find_src_set_src (dataflow_set *set, rtx
     {
       decl_or_value dv = dv_from_decl (decl);
 
-      slot = htab_find_slot_with_hash (set->vars, &dv,
-				       VARIABLE_HASH_VAL (decl), NO_INSERT);
-
-      if (slot)
+      var = shared_hash_find (set->vars, dv);
+      if (var)
 	{
-	  var = (variable) *slot;
 	  found = false;
 	  for (i = 0; i < var->n_var_parts && !found; i++)
 	    for (nextp = var->var_part[i].loc_chain; nextp && !found; 
@@ -4732,7 +4951,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);
 
@@ -4986,10 +5205,13 @@ compute_bb_dataflow (basic_block bb)
   if (MAY_HAVE_DEBUG_INSNS)
     {
       dataflow_set_equiv_regs (out);
-      htab_traverse (out->vars, canonicalize_values_mark, out);
-      htab_traverse (out->vars, canonicalize_values_star, out);
+      htab_traverse (shared_hash_htab (out->vars), canonicalize_values_mark,
+		     out);
+      htab_traverse (shared_hash_htab (out->vars), canonicalize_values_star,
+		     out);
 #if ENABLE_CHECKING
-      htab_traverse (out->vars, canonicalize_loc_order_check, out);
+      htab_traverse (shared_hash_htab (out->vars),
+		     canonicalize_loc_order_check, out);
 #endif
     }
   changed = dataflow_set_different (&old_out, out);
@@ -5054,35 +5276,29 @@ vt_find_locations (void)
 
 	      SET_BIT (visited, bb->index);
 
-	      if (VTI (bb)->in.vars)
+	      if (dump_file && VTI (bb)->in.vars)
 		{
-		  htabsz -= VTI (bb)->in.vars->size + VTI (bb)->out.vars->size;
-		  oldinsz = VTI (bb)->in.vars->n_elements;
-		  oldoutsz = VTI (bb)->out.vars->n_elements;
+		  htabsz
+		    -= htab_size (shared_hash_htab (VTI (bb)->in.vars))
+		       + htab_size (shared_hash_htab (VTI (bb)->out.vars));
+		  oldinsz
+		    = htab_elements (shared_hash_htab (VTI (bb)->in.vars));
+		  oldoutsz
+		    = htab_elements (shared_hash_htab (VTI (bb)->out.vars));
 		}
 	      else
 		oldinsz = oldoutsz = 0;
 
 	      if (MAY_HAVE_DEBUG_INSNS)
 		{
-		  dataflow_set *in = &VTI (bb)->in;
-		  dataflow_set oin, *oldinp = NULL;
+		  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
 		  bool first = true, adjust = false;
 
 		  /* Calculate the IN set as the intersection of
 		     predecessor OUT sets.  */
 
-		  if ((dump_flags & TDF_DETAILS))
-		    {
-		      oldinp = &oin;
-		      *oldinp = *in;
-		      dataflow_set_init (in,
-					 in->vars ?
-					 htab_elements (in->vars)
-					 : 3);
-		    }
-		  else
-		    dataflow_set_clear (in);
+		  dataflow_set_clear (in);
+		  dst_can_be_shared = true;
 
 		  FOR_EACH_EDGE (e, ei, bb->preds)
 		    if (!VTI (e->src)->flooded)
@@ -5091,6 +5307,7 @@ vt_find_locations (void)
 		    else if (first)
 		      {
 			dataflow_set_copy (in, &VTI (e->src)->out);
+			first_out = &VTI (e->src)->out;
 			first = false;
 		      }
 		    else
@@ -5105,35 +5322,18 @@ vt_find_locations (void)
 #if ENABLE_CHECKING
 		      /* Merge and merge_adjust should keep entries in
 			 canonical order.  */
-		      htab_traverse (in->vars,
+		      htab_traverse (shared_hash_htab (in->vars),
 				     canonicalize_loc_order_check,
 				     in);
 #endif
-		    }
-
-		  VTI (bb)->flooded = true;
-
-		  if (oldinp && dump_file && (dump_flags & TDF_DETAILS)
-		      && dataflow_set_different (oldinp, in))
-		    {
-		      fprintf (dump_file,
-			       "BB %i IN differences above, from", bb->index);
-		      FOR_EACH_EDGE (e, ei, bb->preds)
-			fprintf (dump_file, " %i", e->src->index);
-		      fputc ('\n', dump_file);
-
-#if 0
-		      FOR_EACH_EDGE (e, ei, bb->preds)
+		      if (dst_can_be_shared)
 			{
-			  fprintf (dump_file, "\nBB %i OUT -> %i:\n",
-				   e->src->index, bb->index);
-			  dump_dataflow_set (&VTI (e->src)->out);
+			  shared_hash_destroy (in->vars);
+			  in->vars = shared_hash_copy (first_out->vars);
 			}
-#endif
 		    }
 
-		  if (oldinp)
-		    dataflow_set_destroy (oldinp);
+		  VTI (bb)->flooded = true;
 		}
 	      else
 		{
@@ -5144,7 +5344,9 @@ vt_find_locations (void)
 		}
 
 	      changed = compute_bb_dataflow (bb);
-	      htabsz += VTI (bb)->in.vars->size + VTI (bb)->out.vars->size;
+	      if (dump_file)
+		htabsz += htab_size (shared_hash_htab (VTI (bb)->in.vars))
+			  + htab_size (shared_hash_htab (VTI (bb)->out.vars));
 
 	      if (changed)
 		{
@@ -5178,8 +5380,10 @@ vt_find_locations (void)
 		fprintf (dump_file,
 			 "BB %i: in %i (was %i), out %i (was %i), rem %i + %i, tsz %i\n",
 			 bb->index,
-			 (int)VTI (bb)->in.vars->n_elements, oldinsz,
-			 (int)VTI (bb)->out.vars->n_elements, oldoutsz,
+			 (int)htab_elements (shared_hash_htab (VTI (bb)->in.vars)),
+			 oldinsz,
+			 (int)htab_elements (shared_hash_htab (VTI (bb)->out.vars)),
+			 oldoutsz,
 			 (int)worklist->nodes, (int)pending->nodes, htabsz);
 
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5305,7 +5509,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");
 }
 
@@ -5327,10 +5531,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 = dv_htab_hash (var->dv);
 
@@ -5342,39 +5546,42 @@ variable_was_changed (variable var, htab
       set_dv_changed (var->dv, true);
 
       slot = htab_find_slot_with_hash (changed_variables,
-				       &var->dv,
+				       var->dv,
 				       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 (dv_pool (var->dv));
 	  empty_var->dv = var->dv;
-	  empty_var->refcount = 0;
+	  empty_var->refcount = 1;
 	  empty_var->n_var_parts = 0;
 	  *slot = empty_var;
-
-	  old = htab_find_slot_with_hash (htab, &var->dv, 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->dv,
-						  hash, NO_INSERT);
+	  void **slot;
+
+	drop_var:
+	  slot = shared_hash_find_slot_noinsert (set->vars, var->dv);
 	  if (slot)
-	    htab_clear_slot (htab, slot);
+	    {
+	      if (shared_hash_shared (set->vars))
+		slot = shared_hash_find_slot_unshare (&set->vars, var->dv,
+						      NO_INSERT);
+	      htab_clear_slot (shared_hash_htab (set->vars), slot);
+	    }
 	}
     }
 }
@@ -5422,7 +5629,7 @@ set_slot_part (dataflow_set *set, rtx lo
   location_chain *nextp;
   variable var;
   bool onepart = dv_onepart_p (dv);
-  
+
   gcc_assert (offset == 0 || !onepart);
   gcc_assert (loc != dv_as_opaque (dv));
 
@@ -5460,9 +5667,9 @@ set_slot_part (dataflow_set *set, rtx lo
       if (r == 0)
 	return;
 
-      if (var->refcount > 1)
+      if (var->refcount > 1 || shared_hash_shared (set->vars))
 	{
-	  var = unshare_variable (slot, var, initialized);
+	  var = unshare_variable (set, slot, var, initialized);
 	  for (nextp = &var->var_part[0].loc_chain; c;
 	       nextp = &(*nextp)->next)
 	    c--;
@@ -5493,14 +5700,13 @@ set_slot_part (dataflow_set *set, rtx lo
 	      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)
-		var = unshare_variable (slot, var, initialized);
+	      if (var->refcount > 1 || shared_hash_shared (set->vars))
+		var = unshare_variable (set, slot, var, initialized);
 	    }
 	}
       else
@@ -5508,8 +5714,8 @@ set_slot_part (dataflow_set *set, rtx lo
 	  /* 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 (slot, var, initialized);
+	  if (var->refcount > 1 || shared_hash_shared (set->vars))
+	    var = unshare_variable (set, slot, var, initialized);
 
 	  /* We track only variables whose size is <= MAX_VAR_PARTS bytes
 	     thus there are at most MAX_VAR_PARTS different offsets.  */
@@ -5565,7 +5771,7 @@ set_slot_part (dataflow_set *set, rtx lo
   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);
     }
 }
 
@@ -5581,8 +5787,16 @@ set_variable_part (dataflow_set *set, rt
 		   enum var_init_status initialized, rtx set_src,
 		   enum insert_option iopt)
 {
-  void **slot = htab_find_slot_with_hash (set->vars, &dv,
-					  dv_htab_hash (dv), iopt);
+  void **slot;
+
+  if (iopt == NO_INSERT)
+    slot = shared_hash_find_slot_noinsert (set->vars, dv);
+  else
+    {
+      slot = shared_hash_find_slot (set->vars, dv);
+      if (!slot)
+	slot = shared_hash_find_slot_unshare (&set->vars, dv, iopt);
+    }
   set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
 }
 
@@ -5658,8 +5872,7 @@ clobber_variable_part (dataflow_set *set
       || (!dv_is_value_p (dv) && ! DECL_P (dv_as_decl (dv))))
     return;
 
-  slot = htab_find_slot_with_hash (set->vars, &dv,
-				   dv_htab_hash (dv), NO_INSERT);
+  slot = shared_hash_find_slot_noinsert (set->vars, dv);
   if (!slot)
     return;
 
@@ -5682,7 +5895,7 @@ delete_slot_part (dataflow_set *set, rtx
       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.  */
@@ -5696,7 +5909,7 @@ delete_slot_part (dataflow_set *set, rtx
 		  enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
 		  if (! flag_var_tracking_uninit)
 		    status = VAR_INIT_STATUS_INITIALIZED;
-		  var = unshare_variable (slot, var, status);
+		  var = unshare_variable (set, slot, var, status);
 		  break;
 		}
 	    }
@@ -5746,7 +5959,7 @@ delete_slot_part (dataflow_set *set, rtx
 	    }
 	}
       if (changed)
-	variable_was_changed (var, set->vars);
+	variable_was_changed (var, set);
     }
 }
 
@@ -5758,10 +5971,7 @@ static void
 delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
 		      HOST_WIDE_INT offset)
 {
-  void **slot;
-
-  slot = htab_find_slot_with_hash (set->vars, &dv,
-				   dv_htab_hash (dv), NO_INSERT);
+  void **slot = shared_hash_find_slot_noinsert (set->vars, dv);
   if (!slot)
     return;
 
@@ -5776,7 +5986,6 @@ vt_expand_loc_callback (rtx x, bitmap re
 {
   htab_t vars = (htab_t)data;
   decl_or_value dv;
-  void **slot;
   variable var;
   location_chain loc;
   rtx result;
@@ -5787,13 +5996,11 @@ vt_expand_loc_callback (rtx x, bitmap re
     return NULL;
 
   dv = dv_from_value (x);
-  slot = htab_find_slot_with_hash (vars, &dv, dv_htab_hash (dv), NO_INSERT);
+  var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
 
-  if (!slot)
+  if (!var)
     return NULL;
 
-  var = (variable)*slot;
-
   if (var->n_var_parts == 0)
     return NULL;
 
@@ -6005,14 +6212,6 @@ emit_note_insn_var_location (void **varp
   set_dv_changed (var->dv, false);
   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 && var->refcount == 0)
-    {
-      pool_free (dv_pool (var->dv), var);
-    }
-
   /* Continue traversing the hash table.  */
   return 1;
 }
@@ -6085,9 +6284,11 @@ check_changed_var (void **slot, void *da
    shall be emitted before of after instruction INSN.  */
 
 static void
-emit_notes_for_changes (rtx insn, enum emit_note_where where, htab_t vars)
+emit_notes_for_changes (rtx insn, enum emit_note_where where,
+			shared_hash vars)
 {
   emit_note_data data;
+  htab_t htab = shared_hash_htab (vars);
 
   if (MAY_HAVE_DEBUG_INSNS)
     {
@@ -6100,14 +6301,14 @@ emit_notes_for_changes (rtx insn, enum e
       do
 	{
 	  more_changed = false;
-	  htab_traverse (vars, check_changed_var, &more_changed);
+	  htab_traverse (htab, check_changed_var, &more_changed);
 	}
       while (more_changed);
     }
 
   data.insn = insn;
   data.where = where;
-  data.vars = vars;
+  data.vars = htab;
   htab_traverse (changed_variables, emit_note_insn_var_location, &data);
 }
 
@@ -6121,7 +6322,7 @@ emit_notes_for_differences_1 (void **slo
   variable old_var, new_var;
 
   old_var = (variable) *slot;
-  new_var = (variable) htab_find_with_hash (new_vars, &old_var->dv,
+  new_var = (variable) htab_find_with_hash (new_vars, old_var->dv,
 					    dv_htab_hash (old_var->dv));
 
   if (!new_var)
@@ -6131,7 +6332,7 @@ emit_notes_for_differences_1 (void **slo
 
       empty_var = (variable) pool_alloc (dv_pool (old_var->dv));
       empty_var->dv = old_var->dv;
-      empty_var->refcount = 1;
+      empty_var->refcount = 0;
       empty_var->n_var_parts = 0;
       variable_was_changed (empty_var, NULL);
     }
@@ -6154,7 +6355,7 @@ emit_notes_for_differences_2 (void **slo
   variable old_var, new_var;
 
   new_var = (variable) *slot;
-  old_var = (variable) htab_find_with_hash (old_vars, &new_var->dv,
+  old_var = (variable) htab_find_with_hash (old_vars, new_var->dv,
 					    dv_htab_hash (new_var->dv));
   if (!old_var)
     {
@@ -6173,8 +6374,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, new_set->vars);
 }
 
@@ -6186,7 +6391,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++)
@@ -6461,7 +6666,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)
@@ -6772,18 +6977,6 @@ vt_initialize (void)
 	}
     }
 
-  /* Init the IN and OUT sets.  */
-  FOR_ALL_BB (bb)
-    {
-      VTI (bb)->visited = false;
-      VTI (bb)->flooded = false;
-      dataflow_set_init (&VTI (bb)->in, 7);
-      dataflow_set_init (&VTI (bb)->out, 7);
-      VTI (bb)->permp = NULL;
-    }
-
-  VTI (ENTRY_BLOCK_PTR)->flooded = true;
-
   attrs_pool = create_alloc_pool ("attrs_def pool",
 				  sizeof (struct attrs_def), 1024);
   var_pool = create_alloc_pool ("variable_def pool",
@@ -6793,8 +6986,27 @@ 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;
+      VTI (bb)->flooded = false;
+      dataflow_set_init (&VTI (bb)->in);
+      dataflow_set_init (&VTI (bb)->out);
+      VTI (bb)->permp = NULL;
+    }
+
+  VTI (ENTRY_BLOCK_PTR)->flooded = true;
   vt_add_function_parameters ();
 }
 
@@ -6853,10 +7065,12 @@ vt_finalize (void)
 	}
     }
   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);
 
   if (MAY_HAVE_DEBUG_INSNS)
     {

	Jakub

Attachment: P2-checking
Description: Text document

Attachment: XX
Description: Text document


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