public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Merge C++ conversion into trunk (4/6 - hash table rewrite)
@ 2012-08-12 20:14 Diego Novillo
  2012-08-15 10:59 ` Richard Guenther
  2012-08-15 13:00 ` Richard Guenther
  0 siblings, 2 replies; 29+ messages in thread
From: Diego Novillo @ 2012-08-12 20:14 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Guenther, Richard Henderson

This implements a new C++ hash table.

See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for
details.

Diego.


2012-08-12   Lawrence Crowl  <crowl@google.com>

	* hash-table.h: New. Implementation borrowed from libiberty/hashtab.c.
	* hash-table.c: Likewise.
	* tree-ssa-tail-merge.c: Include hash-table.h instead of hashtab.h.
	(static htab_t same_succ_htab): Change type to hash_table;
	move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(same_succ_print_traverse): Make extern ssa_.... Change callers.
	Remove void* casting.
	(same_succ_hash): Likewise.
	(same_succ_equal): Likewise.
	(same_succ_delete): Likewise.
	* tree-ssa-threadupdate.c: Include hash-table.h.
	(struct local_info): Rename to ssa_local_info_t to avoid overloading
	the type name local_info with the variable name local_info.
	(static htab_t redirection_data): Change type to hash_table.
	Move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(redirection_data_hash): Make extern ssa_.... Change callers.
	Remove void* casting.
	(redirection_data_eq): Likewise.
	(fix_duplicate_block_edges): Likewise.
	(create_duplicates): Likewise.
	(fixup_template_block): Likewise.
	(redirect_edges): Likewise.
	(lookup_redirection_data): Change types associated with the hash table
	from void* to their actual type. Remove unnecessary casts.
	* tree-ssa-ccp.c: Include hash-table.h.
	(typedef gimple_htab): New.  Uses hash_table.  Replace specific uses
	of htab_t with gimple_htab.  Change users to invoke member functions.
	Move specification of helper functions from create call to declaration.
	* tree-ssa-coalesce.c: Include hash-table.h instead of hashtab.h.
	(hash_ssa_name_by_var): Make extern. Remove void* casting.
	(eq_ssa_name_by_var): Likewise.
	(coalesce_ssa_name): Change type of local static htab_t ssa_name_hash
	to hash_table. Change users to invoke member functions.
	Move specification of helper functions from create call to declaration.
	* coverage.c: Include hash-table.h instead of hashtab.h.
	(static htab_t counts_hash): Change type to hash_table;
	move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(htab_counts_entry_hash): Make extern. Rename with coverage_... instead
	of htab_... Remove void* casting.
	(htab_counts_entry_eq): Likewise.
	(htab_counts_entry_del): Likewise.
	* tree-ssa-pre.c: Include hash-table.h instead of hashtab.h.
	(static htab_t expression_to_id): Change type to hash_table.
	Move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(static htab_t phi_translate_table): Likewise.
	(pre_expr_eq): Make extern ssa_.... Change callers.
	Remove void* casting.
	(pre_expr_hash): Likewise.
	(expr_pred_trans_hash): Likewise.
	(expr_pred_trans_eq): Likewise.
	(alloc_expression_id): Change types associated with the hash table
	from void* to their actual type. Remove unnecessary casts.
	(lookup_expression_id): Likewise.
	(phi_trans_lookup): Likewise.
	(phi_trans_add): Likewise.
	* stringpool.c: Rename uses of libcpp typedef hash_table to
	cpp_hash_table.
	* Makefile.in: Add hash-table.o to OBJS-libcommon-target.
	Add $(HASH_TABLE_H). Add new dependences on $(HASH_TABLE_H).

diff --git a/gcc/coverage.c b/gcc/coverage.c
index af52289..3fea525 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "coverage.h"
 #include "langhooks.h"
-#include "hashtab.h"
+#include "hash-table.h"
 #include "tree-iterator.h"
 #include "cgraph.h"
 #include "dumpfile.h"
@@ -109,17 +109,11 @@ static unsigned bbg_file_stamp;
 /* Name of the count data (gcda) file.  */
 static char *da_file_name;
 
-/* Hash table of count data.  */
-static htab_t counts_hash = NULL;
-
 /* The names of merge functions for counters.  */
 static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
 static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
 
 /* Forward declarations.  */
-static hashval_t htab_counts_entry_hash (const void *);
-static int htab_counts_entry_eq (const void *, const void *);
-static void htab_counts_entry_del (void *);
 static void read_counts_file (void);
 static tree build_var (tree, tree, int);
 static void build_fn_info_type (tree, unsigned, tree);
@@ -149,32 +143,31 @@ get_gcov_unsigned_t (void)
   return lang_hooks.types.type_for_mode (mode, true);
 }
 \f
-static hashval_t
-htab_counts_entry_hash (const void *of)
+inline hashval_t
+coverage_counts_entry_hash (const counts_entry_t *entry)
 {
-  const counts_entry_t *const entry = (const counts_entry_t *) of;
-
   return entry->ident * GCOV_COUNTERS + entry->ctr;
 }
 
-static int
-htab_counts_entry_eq (const void *of1, const void *of2)
+inline int
+coverage_counts_entry_eq (const counts_entry_t *entry1,
+                          const counts_entry_t *entry2)
 {
-  const counts_entry_t *const entry1 = (const counts_entry_t *) of1;
-  const counts_entry_t *const entry2 = (const counts_entry_t *) of2;
-
   return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
 }
 
-static void
-htab_counts_entry_del (void *of)
+inline void
+coverage_counts_entry_del (counts_entry_t *entry)
 {
-  counts_entry_t *const entry = (counts_entry_t *) of;
-
   free (entry->counts);
   free (entry);
 }
 
+/* Hash table of count data.  */
+static hash_table <counts_entry_t, coverage_counts_entry_hash,
+		   coverage_counts_entry_eq, coverage_counts_entry_del>
+		  counts_hash;
+
 /* Read in the counts file, if available.  */
 
 static void
@@ -214,9 +207,7 @@ read_counts_file (void)
   tag = gcov_read_unsigned ();
   bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
 
-  counts_hash = htab_create (10,
-			     htab_counts_entry_hash, htab_counts_entry_eq,
-			     htab_counts_entry_del);
+  counts_hash.create (10);
   while ((tag = gcov_read_unsigned ()))
     {
       gcov_unsigned_t length;
@@ -264,8 +255,7 @@ read_counts_file (void)
 	  elt.ident = fn_ident;
 	  elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
 
-	  slot = (counts_entry_t **) htab_find_slot
-	    (counts_hash, &elt, INSERT);
+	  slot = counts_hash.find_slot (&elt, INSERT);
 	  entry = *slot;
 	  if (!entry)
 	    {
@@ -285,14 +275,14 @@ read_counts_file (void)
 	      error ("checksum is (%x,%x) instead of (%x,%x)",
 		     entry->lineno_checksum, entry->cfg_checksum,
 		     lineno_checksum, cfg_checksum);
-	      htab_delete (counts_hash);
+	      counts_hash.dispose ();
 	      break;
 	    }
 	  else if (entry->summary.num != n_counts)
 	    {
 	      error ("Profile data for function %u is corrupted", fn_ident);
 	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
-	      htab_delete (counts_hash);
+	      counts_hash.dispose ();
 	      break;
 	    }
 	  else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
@@ -318,7 +308,7 @@ read_counts_file (void)
 	{
 	  error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted",
 		 da_file_name);
-	  htab_delete (counts_hash);
+	  counts_hash.dispose ();
 	  break;
 	}
     }
@@ -336,7 +326,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
   counts_entry_t *entry, elt;
 
   /* No hash table, no counts.  */
-  if (!counts_hash)
+  if (!counts_hash.is_created ())
     {
       static int warned = 0;
 
@@ -350,7 +340,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
 
   elt.ident = current_function_funcdef_no + 1;
   elt.ctr = counter;
-  entry = (counts_entry_t *) htab_find (counts_hash, &elt);
+  entry = counts_hash.find (&elt);
   if (!entry || !entry->summary.num)
     /* The function was not emitted, or is weak and not chosen in the
        final executable.  Silently fail, because there's nothing we
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 9b186dd..9f602e9 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -30,7 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-inline.h"
 #include "tree-flow.h"
 #include "gimple.h"
-#include "hashtab.h"
+#include "hash-table.h"
 #include "tree-iterator.h"
 #include "alloc-pool.h"
 #include "obstack.h"
@@ -177,12 +177,11 @@ typedef struct pre_expr_d
 #define PRE_EXPR_REFERENCE(e) (e)->u.reference
 #define PRE_EXPR_CONSTANT(e) (e)->u.constant
 
-static int
-pre_expr_eq (const void *p1, const void *p2)
-{
-  const struct pre_expr_d *e1 = (const struct pre_expr_d *) p1;
-  const struct pre_expr_d *e2 = (const struct pre_expr_d *) p2;
+/* Compare E1 and E1 for equality.  */
 
+inline int
+ssa_pre_expr_eq (const struct pre_expr_d *e1, const struct pre_expr_d *e2)
+{
   if (e1->kind != e2->kind)
     return false;
 
@@ -203,10 +202,11 @@ pre_expr_eq (const void *p1, const void *p2)
     }
 }
 
-static hashval_t
-pre_expr_hash (const void *p1)
+/* Hash E.  */
+
+inline hashval_t
+ssa_pre_expr_hash (const struct pre_expr_d *e)
 {
-  const struct pre_expr_d *e = (const struct pre_expr_d *) p1;
   switch (e->kind)
     {
     case CONSTANT:
@@ -222,7 +222,6 @@ pre_expr_hash (const void *p1)
     }
 }
 
-
 /* Next global expression id number.  */
 static unsigned int next_expression_id;
 
@@ -230,7 +229,9 @@ static unsigned int next_expression_id;
 DEF_VEC_P (pre_expr);
 DEF_VEC_ALLOC_P (pre_expr, heap);
 static VEC(pre_expr, heap) *expressions;
-static htab_t expression_to_id;
+static hash_table <pre_expr_d, ssa_pre_expr_hash, ssa_pre_expr_eq,
+		   typed_null_remove <pre_expr_d> >
+		  expression_to_id;
 static VEC(unsigned, heap) *name_to_id;
 
 /* Allocate an expression id for EXPR.  */
@@ -238,7 +239,7 @@ static VEC(unsigned, heap) *name_to_id;
 static inline unsigned int
 alloc_expression_id (pre_expr expr)
 {
-  void **slot;
+  struct pre_expr_d **slot;
   /* Make sure we won't overflow. */
   gcc_assert (next_expression_id + 1 > next_expression_id);
   expr->id = next_expression_id++;
@@ -257,7 +258,7 @@ alloc_expression_id (pre_expr expr)
     }
   else
     {
-      slot = htab_find_slot (expression_to_id, expr, INSERT);
+      slot = expression_to_id.find_slot (expr, INSERT);
       gcc_assert (!*slot);
       *slot = expr;
     }
@@ -275,7 +276,7 @@ get_expression_id (const pre_expr expr)
 static inline unsigned int
 lookup_expression_id (const pre_expr expr)
 {
-  void **slot;
+  struct pre_expr_d **slot;
 
   if (expr->kind == NAME)
     {
@@ -286,7 +287,7 @@ lookup_expression_id (const pre_expr expr)
     }
   else
     {
-      slot = htab_find_slot (expression_to_id, expr, NO_INSERT);
+      slot = expression_to_id.find_slot (expr, NO_INSERT);
       if (!slot)
 	return 0;
       return ((pre_expr)*slot)->id;
@@ -479,11 +480,6 @@ static bitmap need_eh_cleanup;
 /* Set of blocks with statements that have had their AB properties changed.  */
 static bitmap need_ab_cleanup;
 
-/* The phi_translate_table caches phi translations for a given
-   expression and predecessor.  */
-
-static htab_t phi_translate_table;
-
 /* A three tuple {e, pred, v} used to cache phi translations in the
    phi_translate_table.  */
 
@@ -506,21 +502,19 @@ typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
 
 /* Return the hash value for a phi translation table entry.  */
 
-static hashval_t
-expr_pred_trans_hash (const void *p)
+inline hashval_t
+ssa_expr_pred_trans_hash (const expr_pred_trans_d *ve)
 {
-  const_expr_pred_trans_t const ve = (const_expr_pred_trans_t) p;
   return ve->hashcode;
 }
 
 /* Return true if two phi translation table entries are the same.
    P1 and P2 should point to the expr_pred_trans_t's to be compared.*/
 
-static int
-expr_pred_trans_eq (const void *p1, const void *p2)
+inline int
+ssa_expr_pred_trans_eq (const expr_pred_trans_d *ve1,
+			const expr_pred_trans_d *ve2)
 {
-  const_expr_pred_trans_t const ve1 = (const_expr_pred_trans_t) p1;
-  const_expr_pred_trans_t const ve2 = (const_expr_pred_trans_t) p2;
   basic_block b1 = ve1->pred;
   basic_block b2 = ve2->pred;
 
@@ -528,9 +522,17 @@ expr_pred_trans_eq (const void *p1, const void *p2)
      be equal.  */
   if (b1 != b2)
     return false;
-  return pre_expr_eq (ve1->e, ve2->e);
+  return ssa_pre_expr_eq (ve1->e, ve2->e);
 }
 
+/* The phi_translate_table caches phi translations for a given
+   expression and predecessor.  */
+
+static hash_table <expr_pred_trans_d, ssa_expr_pred_trans_hash,
+		   ssa_expr_pred_trans_eq,
+		   typed_free_remove <expr_pred_trans_d> >
+		  phi_translate_table;
+
 /* Search in the phi translation table for the translation of
    expression E in basic block PRED.
    Return the translated value, if found, NULL otherwise.  */
@@ -538,18 +540,18 @@ expr_pred_trans_eq (const void *p1, const void *p2)
 static inline pre_expr
 phi_trans_lookup (pre_expr e, basic_block pred)
 {
-  void **slot;
+  expr_pred_trans_t *slot;
   struct expr_pred_trans_d ept;
 
   ept.e = e;
   ept.pred = pred;
-  ept.hashcode = iterative_hash_hashval_t (pre_expr_hash (e), pred->index);
-  slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode,
+  ept.hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e), pred->index);
+  slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode,
 				   NO_INSERT);
   if (!slot)
     return NULL;
   else
-    return ((expr_pred_trans_t) *slot)->v;
+    return (*slot)->v;
 }
 
 
@@ -559,18 +561,18 @@ phi_trans_lookup (pre_expr e, basic_block pred)
 static inline void
 phi_trans_add (pre_expr e, pre_expr v, basic_block pred)
 {
-  void **slot;
+  expr_pred_trans_t *slot;
   expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d);
   new_pair->e = e;
   new_pair->pred = pred;
   new_pair->v = v;
-  new_pair->hashcode = iterative_hash_hashval_t (pre_expr_hash (e),
+  new_pair->hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e),
 						 pred->index);
 
-  slot = htab_find_slot_with_hash (phi_translate_table, new_pair,
+  slot = phi_translate_table.find_slot_with_hash (new_pair,
 				   new_pair->hashcode, INSERT);
   free (*slot);
-  *slot = (void *) new_pair;
+  *slot = new_pair;
 }
 
 
@@ -1607,12 +1609,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
 		if (double_int_fits_in_shwi_p (off))
 		  newop.off = off.low;
 	      }
-	    VEC_replace (vn_reference_op_s, newoperands, j, &newop);
+	    VEC_replace (vn_reference_op_s, newoperands, j, newop);
 	    /* If it transforms from an SSA_NAME to an address, fold with
 	       a preceding indirect reference.  */
 	    if (j > 0 && op[0] && TREE_CODE (op[0]) == ADDR_EXPR
 		&& VEC_index (vn_reference_op_s,
-			      newoperands, j - 1)->opcode == MEM_REF)
+			      newoperands, j - 1).opcode == MEM_REF)
 	      vn_reference_fold_indirect (&newoperands, &j);
 	  }
 	if (i != VEC_length (vn_reference_op_s, operands))
@@ -2596,8 +2598,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
 				  unsigned int *operand, gimple_seq *stmts,
 				  gimple domstmt)
 {
-  vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
-					*operand);
+  vn_reference_op_t currop = &VEC_index (vn_reference_op_s, ref->operands,
+					 *operand);
   tree genop;
   ++*operand;
   switch (currop->opcode)
@@ -2674,8 +2676,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
       {
 	pre_expr op0expr, op1expr;
 	tree genop0 = NULL_TREE, genop1 = NULL_TREE;
-	vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands,
-					      ++*operand);
+	vn_reference_op_t nextop = &VEC_index (vn_reference_op_s, ref->operands,
+					       ++*operand);
 	tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
 							stmts, domstmt);
 	if (!baseop)
@@ -3488,7 +3490,7 @@ do_regular_insertion (basic_block block, basic_block dom)
 		    do_insertion = true;
 		  if (first_s == NULL)
 		    first_s = edoubleprime;
-		  else if (!pre_expr_eq (first_s, edoubleprime))
+		  else if (!ssa_pre_expr_eq (first_s, edoubleprime))
 		    all_same = false;
 		}
 	    }
@@ -4767,7 +4769,7 @@ init_pre (bool do_fre)
 
   next_expression_id = 1;
   expressions = NULL;
-  VEC_safe_push (pre_expr, heap, expressions, NULL);
+  VEC_safe_push (pre_expr, heap, expressions, (pre_expr)NULL);
   value_expressions = VEC_alloc (bitmap_set_t, heap, get_max_value_id () + 1);
   VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
 			 get_max_value_id() + 1);
@@ -4790,11 +4792,8 @@ init_pre (bool do_fre)
   calculate_dominance_info (CDI_DOMINATORS);
 
   bitmap_obstack_initialize (&grand_bitmap_obstack);
-  phi_translate_table = htab_create (5110, expr_pred_trans_hash,
-				     expr_pred_trans_eq, free);
-  expression_to_id = htab_create (num_ssa_names * 3,
-				  pre_expr_hash,
-				  pre_expr_eq, NULL);
+  phi_translate_table.create (5110);
+  expression_to_id.create (num_ssa_names * 3);
   bitmap_set_pool = create_alloc_pool ("Bitmap sets",
 				       sizeof (struct bitmap_set), 30);
   pre_expr_pool = create_alloc_pool ("pre_expr nodes",
@@ -4826,8 +4825,8 @@ fini_pre (bool do_fre)
   bitmap_obstack_release (&grand_bitmap_obstack);
   free_alloc_pool (bitmap_set_pool);
   free_alloc_pool (pre_expr_pool);
-  htab_delete (phi_translate_table);
-  htab_delete (expression_to_id);
+  phi_translate_table.dispose ();
+  expression_to_id.dispose ();
   VEC_free (unsigned, heap, name_to_id);
 
   free_aux_for_blocks ();
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a2d4633..57d9f99 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -193,7 +193,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "bitmap.h"
 #include "tree-ssa-alias.h"
 #include "params.h"
-#include "hashtab.h"
+#include "hash-table.h"
 #include "gimple-pretty-print.h"
 #include "tree-ssa-sccvn.h"
 #include "tree-dump.h"
@@ -368,11 +368,10 @@ same_succ_print (FILE *file, const same_succ e)
 
 /* Prints same_succ VE to VFILE.  */
 
-static int
-same_succ_print_traverse (void **ve, void *vfile)
+inline int
+ssa_same_succ_print_traverse (same_succ *pe, FILE *file)
 {
-  const same_succ e = *((const same_succ *)ve);
-  FILE *file = ((FILE*)vfile);
+  const same_succ e = *pe;
   same_succ_print (file, e);
   return 1;
 }
@@ -416,10 +415,9 @@ stmt_update_dep_bb (gimple stmt)
 
 /* Calculates hash value for same_succ VE.  */
 
-static hashval_t
-same_succ_hash (const void *ve)
+hashval_t
+ssa_same_succ_hash (const_same_succ e)
 {
-  const_same_succ e = (const_same_succ)ve;
   hashval_t hashval = bitmap_hash (e->succs);
   int flags;
   unsigned int i;
@@ -515,11 +513,9 @@ inverse_flags (const_same_succ e1, const_same_succ e2)
 
 /* Compares SAME_SUCCs VE1 and VE2.  */
 
-static int
-same_succ_equal (const void *ve1, const void *ve2)
+int
+ssa_same_succ_equal (const_same_succ e1, const_same_succ e2)
 {
-  const_same_succ e1 = (const_same_succ)ve1;
-  const_same_succ e2 = (const_same_succ)ve2;
   unsigned int i, first1, first2;
   gimple_stmt_iterator gsi1, gsi2;
   gimple s1, s2;
@@ -590,17 +586,15 @@ same_succ_alloc (void)
 
 /* Delete same_succ VE.  */
 
-static void
-same_succ_delete (void *ve)
+inline void
+ssa_same_succ_delete (same_succ e)
 {
-  same_succ e = (same_succ)ve;
-
   BITMAP_FREE (e->bbs);
   BITMAP_FREE (e->succs);
   BITMAP_FREE (e->inverse);
   VEC_free (int, heap, e->succ_flags);
 
-  XDELETE (ve);
+  XDELETE (e);
 }
 
 /* Reset same_succ SAME.  */
@@ -616,7 +610,9 @@ same_succ_reset (same_succ same)
 
 /* Hash table with all same_succ entries.  */
 
-static htab_t same_succ_htab;
+static hash_table <struct same_succ_def, ssa_same_succ_hash,
+		   ssa_same_succ_equal, ssa_same_succ_delete>
+		  same_succ_htab;
 
 /* Array that is used to store the edge flags for a successor.  */
 
@@ -637,7 +633,7 @@ extern void debug_same_succ (void);
 DEBUG_FUNCTION void
 debug_same_succ ( void)
 {
-  htab_traverse (same_succ_htab, same_succ_print_traverse, stderr);
+  same_succ_htab.traverse <FILE *, ssa_same_succ_print_traverse> (stderr);
 }
 
 DEF_VEC_P (same_succ);
@@ -696,10 +692,9 @@ find_same_succ_bb (basic_block bb, same_succ *same_p)
   EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
     VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
 
-  same->hashval = same_succ_hash (same);
+  same->hashval = ssa_same_succ_hash (same);
 
-  slot = (same_succ *) htab_find_slot_with_hash (same_succ_htab, same,
-						   same->hashval, INSERT);
+  slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
   if (*slot == NULL)
     {
       *slot = same;
@@ -733,7 +728,7 @@ find_same_succ (void)
 	same = same_succ_alloc ();
     }
 
-  same_succ_delete (same);
+  ssa_same_succ_delete (same);
 }
 
 /* Initializes worklist administration.  */
@@ -742,9 +737,7 @@ static void
 init_worklist (void)
 {
   alloc_aux_for_blocks (sizeof (struct aux_bb_info));
-  same_succ_htab
-    = htab_create (n_basic_blocks, same_succ_hash, same_succ_equal,
-		   same_succ_delete);
+  same_succ_htab.create (n_basic_blocks);
   same_succ_edge_flags = XCNEWVEC (int, last_basic_block);
   deleted_bbs = BITMAP_ALLOC (NULL);
   deleted_bb_preds = BITMAP_ALLOC (NULL);
@@ -764,8 +757,7 @@ static void
 delete_worklist (void)
 {
   free_aux_for_blocks ();
-  htab_delete (same_succ_htab);
-  same_succ_htab = NULL;
+  same_succ_htab.dispose ();
   XDELETEVEC (same_succ_edge_flags);
   same_succ_edge_flags = NULL;
   BITMAP_FREE (deleted_bbs);
@@ -795,7 +787,7 @@ same_succ_flush_bb (basic_block bb)
   same_succ same = BB_SAME_SUCC (bb);
   BB_SAME_SUCC (bb) = NULL;
   if (bitmap_single_bit_set_p (same->bbs))
-    htab_remove_elt_with_hash (same_succ_htab, same, same->hashval);
+    same_succ_htab.remove_elt_with_hash (same, same->hashval);
   else
     bitmap_clear_bit (same->bbs, bb->index);
 }
@@ -868,7 +860,7 @@ update_worklist (void)
       if (same == NULL)
 	same = same_succ_alloc ();
     }
-  same_succ_delete (same);
+  ssa_same_succ_delete (same);
   bitmap_clear (deleted_bb_preds);
 }
 
@@ -1637,7 +1629,7 @@ tail_merge_optimize (unsigned int todo)
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "htab collision / search: %f\n",
-	     htab_collisions (same_succ_htab));
+	     same_succ_htab.collisions ());
 
   if (nr_bbs_removed_total > 0)
     {
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index a0536db..3ecb303 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-flow.h"
 #include "dumpfile.h"
 #include "cfgloop.h"
+#include "hash-table.h"
 
 /* Given a block B, update the CFG and SSA graph to reflect redirecting
    one or more in-edges to B to instead reach the destination of an
@@ -126,11 +127,8 @@ struct redirection_data
   struct el *incoming_edges;
 };
 
-/* Main data structure to hold information for duplicates of BB.  */
-static htab_t redirection_data;
-
 /* Data structure of information to pass to hash table traversal routines.  */
-struct local_info
+struct ssa_local_info_t
 {
   /* The current block we are working on.  */
   basic_block bb;
@@ -220,24 +218,32 @@ create_block_for_threading (basic_block bb, struct redirection_data *rd)
 }
 
 /* Hashing and equality routines for our hash table.  */
-static hashval_t
-redirection_data_hash (const void *p)
+inline hashval_t
+ssa_redirection_data_hash (const struct redirection_data *p)
 {
-  edge e = ((const struct redirection_data *)p)->outgoing_edge;
+  edge e = p->outgoing_edge;
   return e->dest->index;
 }
 
-static int
-redirection_data_eq (const void *p1, const void *p2)
+inline int
+ssa_redirection_data_eq (const struct redirection_data *p1,
+			 const struct redirection_data *p2)
 {
-  edge e1 = ((const struct redirection_data *)p1)->outgoing_edge;
-  edge e2 = ((const struct redirection_data *)p2)->outgoing_edge;
-  edge e3 = ((const struct redirection_data *)p1)->intermediate_edge;
-  edge e4 = ((const struct redirection_data *)p2)->intermediate_edge;
+  edge e1 = p1->outgoing_edge;
+  edge e2 = p2->outgoing_edge;
+  edge e3 = p1->intermediate_edge;
+  edge e4 = p2->intermediate_edge;
 
   return e1 == e2 && e3 == e4;
 }
 
+/* Main data structure to hold information for duplicates of BB.  */
+
+static hash_table <struct redirection_data, ssa_redirection_data_hash,
+		   ssa_redirection_data_eq,
+		   typed_free_remove<struct redirection_data> >
+		  redirection_data;
+
 /* Given an outgoing edge E lookup and return its entry in our hash table.
 
    If INSERT is true, then we insert the entry into the hash table if
@@ -247,7 +253,7 @@ redirection_data_eq (const void *p1, const void *p2)
 static struct redirection_data *
 lookup_redirection_data (edge e, enum insert_option insert)
 {
-  void **slot;
+  struct redirection_data **slot;
   struct redirection_data *elt;
 
  /* Build a hash table element so we can see if E is already
@@ -259,7 +265,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
   elt->dup_block = NULL;
   elt->incoming_edges = NULL;
 
-  slot = htab_find_slot (redirection_data, elt, insert);
+  slot = redirection_data.find_slot (elt, insert);
 
   /* This will only happen if INSERT is false and the entry is not
      in the hash table.  */
@@ -273,7 +279,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
      INSERT is true.  */
   if (*slot == NULL)
     {
-      *slot = (void *)elt;
+      *slot = elt;
       elt->incoming_edges = XNEW (struct el);
       elt->incoming_edges->e = e;
       elt->incoming_edges->next = NULL;
@@ -287,7 +293,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
       free (elt);
 
       /* Get the entry stored in the hash table.  */
-      elt = (struct redirection_data *) *slot;
+      elt = *slot;
 
       /* If insertion was requested, then we need to add INCOMING_EDGE
 	 to the list of incoming edges associated with E.  */
@@ -375,9 +381,9 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
 
 /* Wire up the outgoing edges from the duplicate block and
    update any PHIs as needed.  */
-static void
-fix_duplicate_block_edges (struct redirection_data *rd,
-			   struct local_info *local_info)
+void
+ssa_fix_duplicate_block_edges (struct redirection_data *rd,
+			       ssa_local_info_t *local_info)
 {
   /* If we were threading through an joiner block, then we want
      to keep its control statement and redirect an outgoing edge.
@@ -412,11 +418,11 @@ fix_duplicate_block_edges (struct redirection_data *rd,
 }
 /* Hash table traversal callback routine to create duplicate blocks.  */
 
-static int
-create_duplicates (void **slot, void *data)
+int
+ssa_create_duplicates (struct redirection_data **slot,
+		       ssa_local_info_t *local_info)
 {
-  struct redirection_data *rd = (struct redirection_data *) *slot;
-  struct local_info *local_info = (struct local_info *)data;
+  struct redirection_data *rd = *slot;
 
   /* Create a template block if we have not done so already.  Otherwise
      use the template to create a new block.  */
@@ -435,7 +441,7 @@ create_duplicates (void **slot, void *data)
 
       /* Go ahead and wire up outgoing edges and update PHIs for the duplicate
 	 block.   */
-      fix_duplicate_block_edges (rd, local_info);
+      ssa_fix_duplicate_block_edges (rd, local_info);
     }
 
   /* Keep walking the hash table.  */
@@ -446,11 +452,11 @@ create_duplicates (void **slot, void *data)
    block creation.  This hash table traversal callback creates the
    outgoing edge for the template block.  */
 
-static int
-fixup_template_block (void **slot, void *data)
+inline int
+ssa_fixup_template_block (struct redirection_data **slot,
+			  ssa_local_info_t *local_info)
 {
-  struct redirection_data *rd = (struct redirection_data *) *slot;
-  struct local_info *local_info = (struct local_info *)data;
+  struct redirection_data *rd = *slot;
 
   /* If this is the template block halt the traversal after updating
      it appropriately.
@@ -461,7 +467,7 @@ fixup_template_block (void **slot, void *data)
      a new outgoing edge.  In both cases we may need to update PHIs.  */
   if (rd->dup_block && rd->dup_block == local_info->template_block)
     {
-      fix_duplicate_block_edges (rd, local_info);
+      ssa_fix_duplicate_block_edges (rd, local_info);
       return 0;
     }
 
@@ -471,11 +477,11 @@ fixup_template_block (void **slot, void *data)
 /* Hash table traversal callback to redirect each incoming edge
    associated with this hash table element to its new destination.  */
 
-static int
-redirect_edges (void **slot, void *data)
+int
+ssa_redirect_edges (struct redirection_data **slot,
+		    ssa_local_info_t *local_info)
 {
-  struct redirection_data *rd = (struct redirection_data *) *slot;
-  struct local_info *local_info = (struct local_info *)data;
+  struct redirection_data *rd = *slot;
   struct el *next, *el;
 
   /* Walk over all the incoming edges associated associated with this
@@ -594,17 +600,14 @@ thread_block (basic_block bb, bool noloop_only)
      redirect to a duplicate of BB.  */
   edge e, e2;
   edge_iterator ei;
-  struct local_info local_info;
+  ssa_local_info_t local_info;
   struct loop *loop = bb->loop_father;
 
   /* To avoid scanning a linear array for the element we need we instead
      use a hash table.  For normal code there should be no noticeable
      difference.  However, if we have a block with a large number of
      incoming and outgoing edges such linear searches can get expensive.  */
-  redirection_data = htab_create (EDGE_COUNT (bb->succs),
-				  redirection_data_hash,
-				  redirection_data_eq,
-				  free);
+  redirection_data.create (EDGE_COUNT (bb->succs));
 
   /* If we thread the latch of the loop to its exit, the loop ceases to
      exist.  Make sure we do not restrict ourselves in order to preserve
@@ -678,24 +681,26 @@ thread_block (basic_block bb, bool noloop_only)
   local_info.template_block = NULL;
   local_info.bb = bb;
   local_info.jumps_threaded = false;
-  htab_traverse (redirection_data, create_duplicates, &local_info);
+  redirection_data.traverse <ssa_local_info_t *, ssa_create_duplicates>
+			    (&local_info);
 
   /* The template does not have an outgoing edge.  Create that outgoing
      edge and update PHI nodes as the edge's target as necessary.
 
      We do this after creating all the duplicates to avoid creating
      unnecessary edges.  */
-  htab_traverse (redirection_data, fixup_template_block, &local_info);
+  redirection_data.traverse <ssa_local_info_t *, ssa_fixup_template_block>
+			    (&local_info);
 
   /* The hash table traversals above created the duplicate blocks (and the
      statements within the duplicate blocks).  This loop creates PHI nodes for
      the duplicated blocks and redirects the incoming edges into BB to reach
      the duplicates of BB.  */
-  htab_traverse (redirection_data, redirect_edges, &local_info);
+  redirection_data.traverse <ssa_local_info_t *, ssa_redirect_edges>
+			    (&local_info);
 
   /* Done with this block.  Clear REDIRECTION_DATA.  */
-  htab_delete (redirection_data);
-  redirection_data = NULL;
+  redirection_data.dispose ();
 
   if (noloop_only
       && bb == bb->loop_father->header)
diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
index 8244f0c..d0973f4 100644
--- a/libcpp/identifiers.c
+++ b/libcpp/identifiers.c
@@ -28,12 +28,12 @@ along with this program; see the file COPYING3.  If not see
 #include "cpplib.h"
 #include "internal.h"
 
-static hashnode alloc_node (hash_table *);
+static hashnode alloc_node (cpp_hash_table *);
 
 /* Return an identifier node for hashtable.c.  Used by cpplib except
    when integrated with the C front ends.  */
 static hashnode
-alloc_node (hash_table *table)
+alloc_node (cpp_hash_table *table)
 {
   cpp_hashnode *node;
 
@@ -45,7 +45,7 @@ alloc_node (hash_table *table)
 /* Set up the identifier hash table.  Use TABLE if non-null, otherwise
    create our own.  */
 void
-_cpp_init_hashtable (cpp_reader *pfile, hash_table *table)
+_cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table)
 {
   struct spec_nodes *s;
 
diff --git a/libcpp/include/symtab.h b/libcpp/include/symtab.h
index 4107a6f..30d7645 100644
--- a/libcpp/include/symtab.h
+++ b/libcpp/include/symtab.h
@@ -38,7 +38,7 @@ struct GTY(()) ht_identifier {
 #define HT_LEN(NODE) ((NODE)->len)
 #define HT_STR(NODE) ((NODE)->str)
 
-typedef struct ht hash_table;
+typedef struct ht cpp_hash_table;
 typedef struct ht_identifier *hashnode;
 
 enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC};
@@ -51,7 +51,7 @@ struct ht
 
   hashnode *entries;
   /* Call back, allocate a node.  */
-  hashnode (*alloc_node) (hash_table *);
+  hashnode (*alloc_node) (cpp_hash_table *);
   /* Call back, allocate something that hangs off a node like a cpp_macro.  
      NULL means use the usual allocator.  */
   void * (*alloc_subobject) (size_t);
@@ -71,14 +71,14 @@ struct ht
 };
 
 /* Initialize the hashtable with 2 ^ order entries.  */
-extern hash_table *ht_create (unsigned int order);
+extern cpp_hash_table *ht_create (unsigned int order);
 
 /* Frees all memory associated with a hash table.  */
-extern void ht_destroy (hash_table *);
+extern void ht_destroy (cpp_hash_table *);
 
-extern hashnode ht_lookup (hash_table *, const unsigned char *,
+extern hashnode ht_lookup (cpp_hash_table *, const unsigned char *,
 			   size_t, enum ht_lookup_option);
-extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
+extern hashnode ht_lookup_with_hash (cpp_hash_table *, const unsigned char *,
                                      size_t, unsigned int,
                                      enum ht_lookup_option);
 #define HT_HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
@@ -88,17 +88,17 @@ extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
    TABLE->PFILE, the node, and a PTR, and the callback sequence stops
    if the callback returns zero.  */
 typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
-extern void ht_forall (hash_table *, ht_cb, const void *);
+extern void ht_forall (cpp_hash_table *, ht_cb, const void *);
 
 /* For all nodes in TABLE, call the callback.  If the callback returns
    a nonzero value, the node is removed from the table.  */
-extern void ht_purge (hash_table *, ht_cb, const void *);
+extern void ht_purge (cpp_hash_table *, ht_cb, const void *);
 
 /* Restore the hash table.  */
-extern void ht_load (hash_table *ht, hashnode *entries,
+extern void ht_load (cpp_hash_table *ht, hashnode *entries,
 		     unsigned int nslots, unsigned int nelements, bool own);
 
 /* Dump allocation statistics to stderr.  */
-extern void ht_dump_statistics (hash_table *);
+extern void ht_dump_statistics (cpp_hash_table *);
 
 #endif /* LIBCPP_SYMTAB_H */
diff --git a/libcpp/init.c b/libcpp/init.c
index 7752fea..040ab34 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -149,7 +149,7 @@ init_library (void)
 
 /* Initialize a cpp_reader structure.  */
 cpp_reader *
-cpp_create_reader (enum c_lang lang, hash_table *table,
+cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
 		   struct line_maps *line_table)
 {
   cpp_reader *pfile;
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 37aac82..79dd54f 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -619,7 +619,7 @@ extern void _cpp_push_token_context (cpp_reader *, cpp_hashnode *,
 extern void _cpp_backup_tokens_direct (cpp_reader *, unsigned int);
 
 /* In identifiers.c */
-extern void _cpp_init_hashtable (cpp_reader *, hash_table *);
+extern void _cpp_init_hashtable (cpp_reader *, cpp_hash_table *);
 extern void _cpp_destroy_hashtable (cpp_reader *);
 
 /* In files.c */
diff --git a/libcpp/symtab.c b/libcpp/symtab.c
index 48a5338..a3537a0 100644
--- a/libcpp/symtab.c
+++ b/libcpp/symtab.c
@@ -31,7 +31,7 @@ along with this program; see the file COPYING3.  If not see
    existing entry with a potential new one.  */
 
 static unsigned int calc_hash (const unsigned char *, size_t);
-static void ht_expand (hash_table *);
+static void ht_expand (cpp_hash_table *);
 static double approx_sqrt (double);
 
 /* A deleted entry.  */
@@ -53,13 +53,13 @@ calc_hash (const unsigned char *str, size_t len)
 
 /* Initialize an identifier hashtable.  */
 
-hash_table *
+cpp_hash_table *
 ht_create (unsigned int order)
 {
   unsigned int nslots = 1 << order;
-  hash_table *table;
+  cpp_hash_table *table;
 
-  table = XCNEW (hash_table);
+  table = XCNEW (cpp_hash_table);
 
   /* Strings need no alignment.  */
   _obstack_begin (&table->stack, 0, 0,
@@ -77,7 +77,7 @@ ht_create (unsigned int order)
 /* Frees all memory associated with a hash table.  */
 
 void
-ht_destroy (hash_table *table)
+ht_destroy (cpp_hash_table *table)
 {
   obstack_free (&table->stack, NULL);
   if (table->entries_owned)
@@ -91,7 +91,7 @@ ht_destroy (hash_table *table)
    returns NULL.  Otherwise insert and returns a new entry.  A new
    string is allocated.  */
 hashnode
-ht_lookup (hash_table *table, const unsigned char *str, size_t len,
+ht_lookup (cpp_hash_table *table, const unsigned char *str, size_t len,
 	   enum ht_lookup_option insert)
 {
   return ht_lookup_with_hash (table, str, len, calc_hash (str, len),
@@ -99,7 +99,7 @@ ht_lookup (hash_table *table, const unsigned char *str, size_t len,
 }
 
 hashnode
-ht_lookup_with_hash (hash_table *table, const unsigned char *str,
+ht_lookup_with_hash (cpp_hash_table *table, const unsigned char *str,
 		     size_t len, unsigned int hash,
 		     enum ht_lookup_option insert)
 {
@@ -182,7 +182,7 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
 /* Double the size of a hash table, re-hashing existing entries.  */
 
 static void
-ht_expand (hash_table *table)
+ht_expand (cpp_hash_table *table)
 {
   hashnode *nentries, *p, *limit;
   unsigned int size, sizemask;
@@ -224,7 +224,7 @@ ht_expand (hash_table *table)
 /* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
    the node, and V.  */
 void
-ht_forall (hash_table *table, ht_cb cb, const void *v)
+ht_forall (cpp_hash_table *table, ht_cb cb, const void *v)
 {
   hashnode *p, *limit;
 
@@ -242,7 +242,7 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
 /* Like ht_forall, but a nonzero return from the callback means that
    the entry should be removed from the table.  */
 void
-ht_purge (hash_table *table, ht_cb cb, const void *v)
+ht_purge (cpp_hash_table *table, ht_cb cb, const void *v)
 {
   hashnode *p, *limit;
 
@@ -259,7 +259,7 @@ ht_purge (hash_table *table, ht_cb cb, const void *v)
 
 /* Restore the hash table.  */
 void
-ht_load (hash_table *ht, hashnode *entries,
+ht_load (cpp_hash_table *ht, hashnode *entries,
 	 unsigned int nslots, unsigned int nelements,
 	 bool own)
 {
@@ -274,7 +274,7 @@ ht_load (hash_table *ht, hashnode *entries,
 /* Dump allocation statistics to stderr.  */
 
 void
-ht_dump_statistics (hash_table *table)
+ht_dump_statistics (cpp_hash_table *table)
 {
   size_t nelts, nids, overhead, headers;
   size_t total_bytes, longest, deleted = 0;
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 83ed653..4332398 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -130,6 +130,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "gimple-fold.h"
 #include "params.h"
+#include "hash-table.h"
 
 
 /* Possible lattice values.  */
@@ -1688,11 +1689,17 @@ evaluate_stmt (gimple stmt)
   return val;
 }
 
+typedef hash_table <gimple_statement_d, typed_pointer_hash<gimple_statement_d>,
+		    typed_pointer_equal<gimple_statement_d>,
+		    typed_null_remove<gimple_statement_d> >
+		   gimple_htab;
+
 /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
    each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
 
 static void
-insert_clobber_before_stack_restore (tree saved_val, tree var, htab_t *visited)
+insert_clobber_before_stack_restore (tree saved_val, tree var,
+				     gimple_htab *visited)
 {
   gimple stmt, clobber_stmt;
   tree clobber;
@@ -1712,10 +1719,10 @@ insert_clobber_before_stack_restore (tree saved_val, tree var, htab_t *visited)
       }
     else if (gimple_code (stmt) == GIMPLE_PHI)
       {
-	if (*visited == NULL)
-	  *visited = htab_create (10, htab_hash_pointer, htab_eq_pointer, NULL);
+	if (!visited->is_created ())
+	  visited->create (10);
 
-	slot = (gimple *)htab_find_slot (*visited, stmt, INSERT);
+	slot = visited->find_slot (stmt, INSERT);
 	if (*slot != NULL)
 	  continue;
 
@@ -1758,7 +1765,7 @@ insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
 {
   gimple stmt;
   tree saved_val;
-  htab_t visited = NULL;
+  gimple_htab visited;
 
   for (; !gsi_end_p (i); gsi_prev_dom_bb_nondebug (&i))
     {
@@ -1775,8 +1782,8 @@ insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
       break;
     }
 
-  if (visited != NULL)
-    htab_delete (visited);
+  if (visited.is_created ())
+    visited.dispose ();
 }
 
 /* Detects a __builtin_alloca_with_align with constant size argument.  Declares
diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c
index b8b1a51..399e7fc 100644
--- a/gcc/tree-ssa-coalesce.c
+++ b/gcc/tree-ssa-coalesce.c
@@ -29,7 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "bitmap.h"
 #include "dumpfile.h"
 #include "tree-flow.h"
-#include "hashtab.h"
+#include "hash-table.h"
 #include "tree-ssa-live.h"
 #include "diagnostic-core.h"
 
@@ -1258,22 +1258,19 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
     }
 }
 
-/* Returns a hash code for P.  */
+/* Returns a hash code for N.  */
 
-static hashval_t
-hash_ssa_name_by_var (const void *p)
+inline hashval_t
+hash_ssa_name_by_var (const_tree n)
 {
-  const_tree n = (const_tree) p;
   return (hashval_t) htab_hash_pointer (SSA_NAME_VAR (n));
 }
 
-/* Returns nonzero if P1 and P2 are equal.  */
+/* Returns nonzero if N1 and N2 are equal.  */
 
-static int
-eq_ssa_name_by_var (const void *p1, const void *p2)
+inline int
+eq_ssa_name_by_var (const_tree n1, const_tree n2)
 {
-  const_tree n1 = (const_tree) p1;
-  const_tree n2 = (const_tree) p2;
   return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
 }
 
@@ -1289,7 +1286,9 @@ coalesce_ssa_name (void)
   bitmap used_in_copies = BITMAP_ALLOC (NULL);
   var_map map;
   unsigned int i;
-  static htab_t ssa_name_hash;
+  static hash_table <tree_node, hash_ssa_name_by_var, eq_ssa_name_by_var,
+		     typed_null_remove<tree_node> >
+		    ssa_name_hash;
 
   cl = create_coalesce_list ();
   map = create_outofssa_var_map (cl, used_in_copies);
@@ -1298,8 +1297,7 @@ coalesce_ssa_name (void)
      so debug info remains undisturbed.  */
   if (!optimize)
     {
-      ssa_name_hash = htab_create (10, hash_ssa_name_by_var,
-      				   eq_ssa_name_by_var, NULL);
+      ssa_name_hash.create (10);
       for (i = 1; i < num_ssa_names; i++)
 	{
 	  tree a = ssa_name (i);
@@ -1309,7 +1307,7 @@ coalesce_ssa_name (void)
 	      && !DECL_IGNORED_P (SSA_NAME_VAR (a))
 	      && (!has_zero_uses (a) || !SSA_NAME_IS_DEFAULT_DEF (a)))
 	    {
-	      tree *slot = (tree *) htab_find_slot (ssa_name_hash, a, INSERT);
+	      tree *slot = ssa_name_hash.find_slot (a, INSERT);
 
 	      if (!*slot)
 		*slot = a;
@@ -1322,7 +1320,7 @@ coalesce_ssa_name (void)
 		}
 	    }
 	}
-      htab_delete (ssa_name_hash);
+      ssa_name_hash.dispose ();
     }
   if (dump_file && (dump_flags & TDF_DETAILS))
     dump_var_map (dump_file, map);
diff --git a/gcc/hash-table.c
===================================================================
--- gcc/hash-table.c	(revision 0)
+++ gcc/hash-table.c	(revision 0)
@@ -0,0 +1,190 @@
+/* A type-safe hash table template.
+   Copyright (C) 2012
+   Free Software Foundation, Inc.
+   Contributed by Lawrence Crowl <crowl@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* This file implements a typed hash table.
+   The implementation borrows from libiberty's hashtab.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "hash-table.h"
+
+
+/* Table of primes and multiplicative inverses.
+
+   Note that these are not minimally reduced inverses.  Unlike when generating
+   code to divide by a constant, we want to be able to use the same algorithm
+   all the time.  All of these inverses (are implied to) have bit 32 set.
+
+   For the record, here's the function that computed the table; it's a 
+   vastly simplified version of the function of the same name from gcc.  */
+
+#if 0
+unsigned int
+ceil_log2 (unsigned int x)
+{
+  int i;
+  for (i = 31; i >= 0 ; --i)
+    if (x > (1u << i))
+      return i+1;
+  abort ();
+}
+
+unsigned int
+choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp)
+{
+  unsigned long long mhigh;
+  double nx;
+  int lgup, post_shift;
+  int pow, pow2;
+  int n = 32, precision = 32;
+
+  lgup = ceil_log2 (d);
+  pow = n + lgup;
+  pow2 = n + lgup - precision;
+
+  nx = ldexp (1.0, pow) + ldexp (1.0, pow2);
+  mhigh = nx / d;
+
+  *shiftp = lgup - 1;
+  *mlp = mhigh;
+  return mhigh >> 32;
+}
+#endif
+
+struct prime_ent const prime_tab[] = {
+  {          7, 0x24924925, 0x9999999b, 2 },
+  {         13, 0x3b13b13c, 0x745d1747, 3 },
+  {         31, 0x08421085, 0x1a7b9612, 4 },
+  {         61, 0x0c9714fc, 0x15b1e5f8, 5 },
+  {        127, 0x02040811, 0x0624dd30, 6 },
+  {        251, 0x05197f7e, 0x073260a5, 7 },
+  {        509, 0x01824366, 0x02864fc8, 8 },
+  {       1021, 0x00c0906d, 0x014191f7, 9 },
+  {       2039, 0x0121456f, 0x0161e69e, 10 },
+  {       4093, 0x00300902, 0x00501908, 11 },
+  {       8191, 0x00080041, 0x00180241, 12 },
+  {      16381, 0x000c0091, 0x00140191, 13 },
+  {      32749, 0x002605a5, 0x002a06e6, 14 },
+  {      65521, 0x000f00e2, 0x00110122, 15 },
+  {     131071, 0x00008001, 0x00018003, 16 },
+  {     262139, 0x00014002, 0x0001c004, 17 },
+  {     524287, 0x00002001, 0x00006001, 18 },
+  {    1048573, 0x00003001, 0x00005001, 19 },
+  {    2097143, 0x00004801, 0x00005801, 20 },
+  {    4194301, 0x00000c01, 0x00001401, 21 },
+  {    8388593, 0x00001e01, 0x00002201, 22 },
+  {   16777213, 0x00000301, 0x00000501, 23 },
+  {   33554393, 0x00001381, 0x00001481, 24 },
+  {   67108859, 0x00000141, 0x000001c1, 25 },
+  {  134217689, 0x000004e1, 0x00000521, 26 },
+  {  268435399, 0x00000391, 0x000003b1, 27 },
+  {  536870909, 0x00000019, 0x00000029, 28 },
+  { 1073741789, 0x0000008d, 0x00000095, 29 },
+  { 2147483647, 0x00000003, 0x00000007, 30 },
+  /* Avoid "decimal constant so large it is unsigned" for 4294967291.  */
+  { 0xfffffffb, 0x00000006, 0x00000008, 31 }
+};
+
+/* The following function returns an index into the above table of the
+   nearest prime number which is greater than N, and near a power of two. */
+
+unsigned int
+hash_table_higher_prime_index (unsigned long n)
+{
+  unsigned int low = 0;
+  unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
+
+  while (low != high)
+    {
+      unsigned int mid = low + (high - low) / 2;
+      if (n > prime_tab[mid].prime)
+	low = mid + 1;
+      else
+	high = mid;
+    }
+
+  /* If we've run out of primes, abort.  */
+  if (n > prime_tab[low].prime)
+    {
+      fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+      abort ();
+    }
+
+  return low;
+}
+
+/* Return X % Y using multiplicative inverse values INV and SHIFT.
+
+   The multiplicative inverses computed above are for 32-bit types,
+   and requires that we be able to compute a highpart multiply.
+
+   FIX: I am not at all convinced that
+     3 loads, 2 multiplications, 3 shifts, and 3 additions
+   will be faster than
+     1 load and 1 modulus
+   on modern systems running a compiler.  */
+
+#ifdef UNSIGNED_64BIT_TYPE
+static inline hashval_t
+mul_mod (hashval_t x, hashval_t y, hashval_t inv, int shift)
+{
+  __extension__ typedef UNSIGNED_64BIT_TYPE ull;
+   hashval_t t1, t2, t3, t4, q, r;
+
+   t1 = ((ull)x * inv) >> 32;
+   t2 = x - t1;
+   t3 = t2 >> 1;
+   t4 = t1 + t3;
+   q  = t4 >> shift;
+   r  = x - (q * y);
+
+   return r;
+}
+#endif
+
+/* Compute the primary table index for HASH given current prime index.  */
+
+hashval_t
+hash_table_mod1 (hashval_t hash, unsigned int index)
+{
+  const struct prime_ent *p = &prime_tab[index];
+#ifdef UNSIGNED_64BIT_TYPE
+  if (sizeof (hashval_t) * CHAR_BIT <= 32)
+    return mul_mod (hash, p->prime, p->inv, p->shift);
+#endif
+  return hash % p->prime;
+}
+
+
+/* Compute the secondary table index for HASH given current prime index.  */
+
+hashval_t
+hash_table_mod2 (hashval_t hash, unsigned int index)
+{
+  const struct prime_ent *p = &prime_tab[index];
+#ifdef UNSIGNED_64BIT_TYPE
+  if (sizeof (hashval_t) * CHAR_BIT <= 32)
+    return 1 + mul_mod (hash, p->prime - 2, p->inv_m2, p->shift);
+#endif
+  return 1 + hash % (p->prime - 2);
+}
diff --git a/gcc/hash-table.h
===================================================================
--- gcc/hash-table.h	(revision 0)
+++ gcc/hash-table.h	(revision 0)
@@ -0,0 +1,783 @@
+/* A type-safe hash table template.
+   Copyright (C) 2012
+   Free Software Foundation, Inc.
+   Contributed by Lawrence Crowl <crowl@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* This file implements a typed hash table.
+   The implementation borrows from libiberty's hashtab.  */
+
+
+#ifndef TYPED_HASHTAB_H
+#define TYPED_HASHTAB_H
+
+#include "hashtab.h"
+
+
+/* The ordinary memory allocator.  */
+/* FIXME (crowl): This allocator may be extracted for wider sharing later.  */
+
+template <typename Type>
+struct xcallocator
+{
+  static Type *control_alloc (size_t count);
+  static Type *data_alloc (size_t count);
+  static void control_free (Type *memory);
+  static void data_free (Type *memory);
+};
+
+
+/* Allocate memory for COUNT control blocks.  */
+
+template <typename Type>
+inline Type *
+xcallocator <Type>::control_alloc (size_t count)
+{
+  return static_cast <Type *> (xcalloc (count, sizeof (Type)));
+}
+
+
+/* Allocate memory for COUNT data blocks.  */ 
+
+template <typename Type>
+inline Type *
+xcallocator <Type>::data_alloc (size_t count)
+{
+  return static_cast <Type *> (xcalloc (count, sizeof (Type)));
+}
+
+
+/* Free memory for control blocks.  */
+
+template <typename Type>
+inline void
+xcallocator <Type>::control_free (Type *memory)
+{
+  return ::free (memory);
+}
+  
+
+/* Free memory for data blocks.  */
+
+template <typename Type>
+inline void
+xcallocator <Type>::data_free (Type *memory)
+{
+  return ::free (memory);
+}
+
+
+/* A common function for hashing a CANDIDATE typed pointer.  */
+
+template <typename Element>
+inline hashval_t
+typed_pointer_hash (const Element *candidate)
+{
+  /* This is a really poor hash function, but it is what the current code uses,
+     so I am reusing it to avoid an additional axis in testing.  */
+  return (hashval_t) ((intptr_t)candidate >> 3);
+}
+
+
+/* A common function for comparing an EXISTING and CANDIDATE typed pointers
+   for equality. */
+
+template <typename Element>
+inline int
+typed_pointer_equal (const Element *existing, const Element * candidate)
+{
+  return existing == candidate;
+}
+
+
+/* A common function for doing nothing on removing a RETIRED slot.  */
+
+template <typename Element>
+inline void
+typed_null_remove (Element *retired ATTRIBUTE_UNUSED)
+{
+}
+
+
+/* A common function for using free on removing a RETIRED slot.  */
+
+template <typename Element>
+inline void
+typed_free_remove (Element *retired)
+{
+  free (retired);
+}
+
+
+/* Table of primes and their inversion information.  */
+
+struct prime_ent
+{
+  hashval_t prime;
+  hashval_t inv;
+  hashval_t inv_m2;     /* inverse of prime-2 */
+  hashval_t shift;
+};
+
+extern struct prime_ent const prime_tab[];
+
+
+/* Functions for computing hash table indexes.  */
+
+extern unsigned int hash_table_higher_prime_index (unsigned long n);
+extern hashval_t hash_table_mod1 (hashval_t hash, unsigned int index);
+extern hashval_t hash_table_mod2 (hashval_t hash, unsigned int index);
+
+
+/* Internal implementation type.  */
+
+template <typename Element>
+struct hash_table_control
+{
+  /* Table itself.  */
+  Element **entries;
+
+  /* Current size (in entries) of the hash table.  */
+  size_t size;
+
+  /* Current number of elements including also deleted elements.  */
+  size_t n_elements;
+
+  /* Current number of deleted elements in the table.  */
+  size_t n_deleted;
+
+  /* The following member is used for debugging. Its value is number
+     of all calls of `htab_find_slot' for the hash table. */
+  unsigned int searches;
+
+  /* The following member is used for debugging.  Its value is number
+     of collisions fixed for time of work with the hash table. */
+  unsigned int collisions;
+
+  /* Current size (in entries) of the hash table, as an index into the
+     table of primes.  */
+  unsigned int size_prime_index;
+};
+
+
+/* User-facing hash table type.
+
+   The table stores elements of type Element.
+
+   It hashes elements with the Hash function.
+     The table currently works with relatively weak hash functions.
+     Use typed_pointer_hash <Element> when hashing pointers instead of objects.
+
+   It compares elements with the Equal function.
+     Two elements with the same hash may not be equal.
+     Use typed_pointer_equal <Element> when hashing pointers instead of objects.
+
+   It removes elements with the Remove function.
+     This feature is useful for freeing memory.
+     Use typed_null_remove <Element> when not freeing objects.
+     Use typed_free_remove <Element> when doing a simple object free.
+
+   Use the Allocator template to allocate and free memory.
+     The default is xcallocator.
+
+*/
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator = xcallocator>
+class hash_table
+{
+
+private:
+
+  hash_table_control <Element> *htab;
+
+  Element **find_empty_slot_for_expand (hashval_t hash);
+  void expand ();
+
+public:
+
+  hash_table ();
+  void create (size_t initial_slots);
+  bool is_created ();
+  void dispose ();
+  Element *find (Element *comparable);
+  Element *find_with_hash (Element *comparable, hashval_t hash);
+  Element **find_slot (Element *comparable, enum insert_option insert);
+  Element **find_slot_with_hash (Element *comparable, hashval_t hash,
+				 enum insert_option insert);
+  void empty ();
+  void clear_slot (Element **slot);
+  void remove_elt (Element *comparable);
+  void remove_elt_with_hash (Element *comparable, hashval_t hash);
+  size_t size();
+  size_t elements();
+  double collisions();
+
+  template <typename Argument,
+	    int (*Callback) (Element **slot, Argument argument)>
+  void traverse_noresize (Argument argument);
+
+  template <typename Argument,
+	    int (*Callback) (Element **slot, Argument argument)>
+  void traverse (Argument argument);
+};
+
+
+/* Construct the hash table.  The only useful operation next is create.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline
+hash_table <Element, Hash, Equal, Remove, Allocator>::hash_table ()
+: htab (NULL)
+{
+}
+
+
+/* See if the table has been created, as opposed to constructed.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline bool
+hash_table <Element, Hash, Equal, Remove, Allocator>::is_created ()
+{
+  return htab != NULL;
+}
+
+
+/* Like find_with_hash, but compute the hash value from the element.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline Element *
+hash_table <Element, Hash, Equal, Remove, Allocator>::find (Element *comparable)
+{
+  return find_with_hash (comparable, Hash (comparable));
+}
+
+
+/* Like find_slot_with_hash, but compute the hash value from the element.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline Element **
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::find_slot (Element *comparable, enum insert_option insert)
+{
+  return find_slot_with_hash (comparable, Hash (comparable), insert);
+}
+
+
+/* Like remove_elt_with_hash, but compute the hash value from the element.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline void
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::remove_elt (Element *comparable)
+{
+  remove_elt_with_hash (comparable, Hash (comparable));
+}
+
+
+/* Return the current size of this hash table.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline size_t
+hash_table <Element, Hash, Equal, Remove, Allocator>::size()
+{
+  return htab->size;
+}
+
+
+/* Return the current number of elements in this hash table. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline size_t
+hash_table <Element, Hash, Equal, Remove, Allocator>::elements()
+{
+  return htab->n_elements - htab->n_deleted;
+}
+
+
+  /* Return the fraction of fixed collisions during all work with given
+     hash table. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+inline double
+hash_table <Element, Hash, Equal, Remove, Allocator>::collisions()
+{
+  if (htab->searches == 0)
+    return 0.0;
+
+  return static_cast <double> (htab->collisions) / htab->searches;
+}
+
+
+/* Create a hash table with at least the given number of INITIAL_SLOTS.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>::create (size_t size)
+{
+  unsigned int size_prime_index;
+
+  size_prime_index = hash_table_higher_prime_index (size);
+  size = prime_tab[size_prime_index].prime;
+
+  htab = Allocator <hash_table_control <Element> > ::control_alloc (1);
+  gcc_assert (htab != NULL);
+  htab->entries = Allocator <Element*> ::data_alloc (size);
+  gcc_assert (htab->entries != NULL);
+  htab->size = size;
+  htab->size_prime_index = size_prime_index;
+}
+
+
+/* Dispose of a hash table.  Free all memory and return this hash table to
+   the non-created state.  Naturally the hash table must already exist.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>::dispose ()
+{
+  size_t size = htab->size;
+  Element **entries = htab->entries;
+
+  for (int i = size - 1; i >= 0; i--)
+    if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
+      Remove (entries[i]);
+
+  Allocator <Element *> ::data_free (entries);
+  Allocator <hash_table_control <Element> > ::control_free (htab);
+  htab = NULL;
+}
+
+
+/* Similar to find_slot, but without several unwanted side effects:
+    - Does not call Equal when it finds an existing entry.
+    - Does not change the count of elements/searches/collisions in the
+      hash table.
+   This function also assumes there are no deleted entries in the table.
+   HASH is the hash value for the element to be inserted.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+Element **
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::find_empty_slot_for_expand (hashval_t hash)
+{
+  hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
+  size_t size = htab->size;
+  Element **slot = htab->entries + index;
+  hashval_t hash2;
+
+  if (*slot == HTAB_EMPTY_ENTRY)
+    return slot;
+  else if (*slot == HTAB_DELETED_ENTRY)
+    abort ();
+
+  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
+  for (;;)
+    {
+      index += hash2;
+      if (index >= size)
+        index -= size;
+
+      slot = htab->entries + index;
+      if (*slot == HTAB_EMPTY_ENTRY)
+        return slot;
+      else if (*slot == HTAB_DELETED_ENTRY)
+        abort ();
+    }
+}
+
+
+/* The following function changes size of memory allocated for the
+   entries and repeatedly inserts the table elements.  The occupancy
+   of the table after the call will be about 50%.  Naturally the hash
+   table must already exist.  Remember also that the place of the
+   table entries is changed.  If memory allocation fails, this function
+   will abort.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>::expand ()
+{
+  Element **oentries;
+  Element **olimit;
+  Element **p;
+  Element **nentries;
+  size_t nsize, osize, elts;
+  unsigned int oindex, nindex;
+
+  oentries = htab->entries;
+  oindex = htab->size_prime_index;
+  osize = htab->size;
+  olimit = oentries + osize;
+  elts = elements ();
+
+  /* Resize only when table after removal of unused elements is either
+     too full or too empty.  */
+  if (elts * 2 > osize || (elts * 8 < osize && osize > 32))
+    {
+      nindex = hash_table_higher_prime_index (elts * 2);
+      nsize = prime_tab[nindex].prime;
+    }
+  else
+    {
+      nindex = oindex;
+      nsize = osize;
+    }
+
+  nentries = Allocator <Element *> ::data_alloc (nsize);
+  gcc_assert (nentries != NULL);
+  htab->entries = nentries;
+  htab->size = nsize;
+  htab->size_prime_index = nindex;
+  htab->n_elements -= htab->n_deleted;
+  htab->n_deleted = 0;
+
+  p = oentries;
+  do
+    {
+      Element *x = *p;
+
+      if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
+        {
+          Element **q = find_empty_slot_for_expand (Hash (x));
+
+          *q = x;
+        }
+
+      p++;
+    }
+  while (p < olimit);
+
+  Allocator <Element *> ::data_free (oentries);
+}
+
+
+/* This function searches for a hash table entry equal to the given
+   COMPARABLE element starting with the given HASH value.  It cannot
+   be used to insert or delete an element. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+Element *
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::find_with_hash (Element *comparable, hashval_t hash)
+{
+  hashval_t index, hash2;
+  size_t size;
+  Element *entry;
+
+  htab->searches++;
+  size = htab->size;
+  index = hash_table_mod1 (hash, htab->size_prime_index);
+
+  entry = htab->entries[index];
+  if (entry == HTAB_EMPTY_ENTRY
+      || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
+    return entry;
+
+  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
+  for (;;)
+    {
+      htab->collisions++;
+      index += hash2;
+      if (index >= size)
+        index -= size;
+
+      entry = htab->entries[index];
+      if (entry == HTAB_EMPTY_ENTRY
+          || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
+        return entry;
+    }
+}
+
+
+/* This function searches for a hash table slot containing an entry
+   equal to the given COMPARABLE element and starting with the given
+   HASH.  To delete an entry, call this with insert=NO_INSERT, then
+   call clear_slot on the slot returned (possibly after doing some
+   checks).  To insert an entry, call this with insert=INSERT, then
+   write the value you want into the returned slot.  When inserting an
+   entry, NULL may be returned if memory allocation fails. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+Element **
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::find_slot_with_hash (Element *comparable, hashval_t hash,
+		       enum insert_option insert)
+{
+  Element **first_deleted_slot;
+  hashval_t index, hash2;
+  size_t size;
+  Element *entry;
+
+  size = htab->size;
+  if (insert == INSERT && size * 3 <= htab->n_elements * 4)
+    {
+      expand ();
+      size = htab->size;
+    }
+
+  index = hash_table_mod1 (hash, htab->size_prime_index);
+
+  htab->searches++;
+  first_deleted_slot = NULL;
+
+  entry = htab->entries[index];
+  if (entry == HTAB_EMPTY_ENTRY)
+    goto empty_entry;
+  else if (entry == HTAB_DELETED_ENTRY)
+    first_deleted_slot = &htab->entries[index];
+  else if (Equal (entry, comparable))
+    return &htab->entries[index];
+      
+  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
+  for (;;)
+    {
+      htab->collisions++;
+      index += hash2;
+      if (index >= size)
+	index -= size;
+      
+      entry = htab->entries[index];
+      if (entry == HTAB_EMPTY_ENTRY)
+	goto empty_entry;
+      else if (entry == HTAB_DELETED_ENTRY)
+	{
+	  if (!first_deleted_slot)
+	    first_deleted_slot = &htab->entries[index];
+	}
+      else if (Equal (entry, comparable))
+	return &htab->entries[index];
+    }
+
+ empty_entry:
+  if (insert == NO_INSERT)
+    return NULL;
+
+  if (first_deleted_slot)
+    {
+      htab->n_deleted--;
+      *first_deleted_slot = static_cast <Element *> (HTAB_EMPTY_ENTRY);
+      return first_deleted_slot;
+    }
+
+  htab->n_elements++;
+  return &htab->entries[index];
+}
+
+
+/* This function clears all entries in the given hash table.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>::empty ()
+{
+  size_t size = htab_size (htab);
+  Element **entries = htab->entries;
+  int i;
+
+  for (i = size - 1; i >= 0; i--)
+    if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
+      Remove (entries[i]);
+
+  /* Instead of clearing megabyte, downsize the table.  */
+  if (size > 1024*1024 / sizeof (PTR))
+    {
+      int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
+      int nsize = prime_tab[nindex].prime;
+
+      Allocator <Element *> ::data_free (htab->entries);
+      htab->entries = Allocator <Element *> ::data_alloc (nsize);
+      htab->size = nsize;
+      htab->size_prime_index = nindex;
+    }
+  else
+    memset (entries, 0, size * sizeof (Element *));
+  htab->n_deleted = 0;
+  htab->n_elements = 0;
+}
+
+
+/* This function clears a specified SLOT in a hash table.  It is
+   useful when you've already done the lookup and don't want to do it
+   again. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::clear_slot (Element **slot)
+{
+  if (slot < htab->entries || slot >= htab->entries + htab->size
+      || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
+    abort ();
+
+  Remove (*slot);
+
+  *slot = HTAB_DELETED_ENTRY;
+  htab->n_deleted++;
+}
+
+
+/* This function deletes an element with the given COMPARABLE value
+   from hash table starting with the given HASH.  If there is no
+   matching element in the hash table, this function does nothing. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::remove_elt_with_hash (Element *comparable, hashval_t hash)
+{
+  Element **slot;
+
+  slot = find_slot_with_hash (comparable, hash, NO_INSERT);
+  if (*slot == HTAB_EMPTY_ENTRY)
+    return;
+
+  Remove (*slot);
+
+  *slot = static_cast <Element *> (HTAB_DELETED_ENTRY);
+  htab->n_deleted++;
+}
+
+
+/* This function scans over the entire hash table calling CALLBACK for
+   each live entry.  If CALLBACK returns false, the iteration stops.
+   ARGUMENT is passed as CALLBACK's second argument. */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+template <typename Argument,
+	  int (*Callback) (Element **slot, Argument argument)>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::traverse_noresize (Argument argument)
+{
+  Element **slot;
+  Element **limit;
+
+  slot = htab->entries;
+  limit = slot + htab->size;
+
+  do
+    {
+      Element *x = *slot;
+
+      if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
+        if (! Callback (slot, argument))
+          break;
+    }
+  while (++slot < limit);
+}
+
+
+/* Like traverse_noresize, but does resize the table when it is too empty
+   to improve effectivity of subsequent calls.  */
+
+template <typename Element,
+	  hashval_t (*Hash) (const Element *candidate),
+	  int (*Equal) (const Element *existing, const Element * candidate),
+	  void (*Remove) (Element *retired),
+	  template <typename Type> class Allocator>
+template <typename Argument,
+	  int (*Callback) (Element **slot, Argument argument)>
+void
+hash_table <Element, Hash, Equal, Remove, Allocator>
+::traverse (Argument argument)
+{
+  size_t size = htab->size;
+  if (elements () * 8 < size && size > 32)
+    expand ();
+
+  traverse_noresize <Argument, Callback> (argument);
+}
+
+#endif /* TYPED_HASHTAB_H */

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-12 20:14 Merge C++ conversion into trunk (4/6 - hash table rewrite) Diego Novillo
@ 2012-08-15 10:59 ` Richard Guenther
  2012-08-15 13:00 ` Richard Guenther
  1 sibling, 0 replies; 29+ messages in thread
From: Richard Guenther @ 2012-08-15 10:59 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches, crowl, Richard Henderson

On Sun, 12 Aug 2012, Diego Novillo wrote:

> This implements a new C++ hash table.
> 
> See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for
> details.
> 
> Diego.

Btw, a new common allocator in hash-table.h should be one using
an obstack.  That's useful at least for short-lived hashtables or
those which never shrink (which is quite common).  The of course
the GGC variant.

Richard.

> 2012-08-12   Lawrence Crowl  <crowl@google.com>
> 
> 	* hash-table.h: New. Implementation borrowed from libiberty/hashtab.c.
> 	* hash-table.c: Likewise.
> 	* tree-ssa-tail-merge.c: Include hash-table.h instead of hashtab.h.
> 	(static htab_t same_succ_htab): Change type to hash_table;
> 	move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(same_succ_print_traverse): Make extern ssa_.... Change callers.
> 	Remove void* casting.
> 	(same_succ_hash): Likewise.
> 	(same_succ_equal): Likewise.
> 	(same_succ_delete): Likewise.
> 	* tree-ssa-threadupdate.c: Include hash-table.h.
> 	(struct local_info): Rename to ssa_local_info_t to avoid overloading
> 	the type name local_info with the variable name local_info.
> 	(static htab_t redirection_data): Change type to hash_table.
> 	Move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(redirection_data_hash): Make extern ssa_.... Change callers.
> 	Remove void* casting.
> 	(redirection_data_eq): Likewise.
> 	(fix_duplicate_block_edges): Likewise.
> 	(create_duplicates): Likewise.
> 	(fixup_template_block): Likewise.
> 	(redirect_edges): Likewise.
> 	(lookup_redirection_data): Change types associated with the hash table
> 	from void* to their actual type. Remove unnecessary casts.
> 	* tree-ssa-ccp.c: Include hash-table.h.
> 	(typedef gimple_htab): New.  Uses hash_table.  Replace specific uses
> 	of htab_t with gimple_htab.  Change users to invoke member functions.
> 	Move specification of helper functions from create call to declaration.
> 	* tree-ssa-coalesce.c: Include hash-table.h instead of hashtab.h.
> 	(hash_ssa_name_by_var): Make extern. Remove void* casting.
> 	(eq_ssa_name_by_var): Likewise.
> 	(coalesce_ssa_name): Change type of local static htab_t ssa_name_hash
> 	to hash_table. Change users to invoke member functions.
> 	Move specification of helper functions from create call to declaration.
> 	* coverage.c: Include hash-table.h instead of hashtab.h.
> 	(static htab_t counts_hash): Change type to hash_table;
> 	move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(htab_counts_entry_hash): Make extern. Rename with coverage_... instead
> 	of htab_... Remove void* casting.
> 	(htab_counts_entry_eq): Likewise.
> 	(htab_counts_entry_del): Likewise.
> 	* tree-ssa-pre.c: Include hash-table.h instead of hashtab.h.
> 	(static htab_t expression_to_id): Change type to hash_table.
> 	Move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(static htab_t phi_translate_table): Likewise.
> 	(pre_expr_eq): Make extern ssa_.... Change callers.
> 	Remove void* casting.
> 	(pre_expr_hash): Likewise.
> 	(expr_pred_trans_hash): Likewise.
> 	(expr_pred_trans_eq): Likewise.
> 	(alloc_expression_id): Change types associated with the hash table
> 	from void* to their actual type. Remove unnecessary casts.
> 	(lookup_expression_id): Likewise.
> 	(phi_trans_lookup): Likewise.
> 	(phi_trans_add): Likewise.
> 	* stringpool.c: Rename uses of libcpp typedef hash_table to
> 	cpp_hash_table.
> 	* Makefile.in: Add hash-table.o to OBJS-libcommon-target.
> 	Add $(HASH_TABLE_H). Add new dependences on $(HASH_TABLE_H).
> 
> diff --git a/gcc/coverage.c b/gcc/coverage.c
> index af52289..3fea525 100644
> --- a/gcc/coverage.c
> +++ b/gcc/coverage.c
> @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "ggc.h"
>  #include "coverage.h"
>  #include "langhooks.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "tree-iterator.h"
>  #include "cgraph.h"
>  #include "dumpfile.h"
> @@ -109,17 +109,11 @@ static unsigned bbg_file_stamp;
>  /* Name of the count data (gcda) file.  */
>  static char *da_file_name;
>  
> -/* Hash table of count data.  */
> -static htab_t counts_hash = NULL;
> -
>  /* The names of merge functions for counters.  */
>  static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
>  static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
>  
>  /* Forward declarations.  */
> -static hashval_t htab_counts_entry_hash (const void *);
> -static int htab_counts_entry_eq (const void *, const void *);
> -static void htab_counts_entry_del (void *);
>  static void read_counts_file (void);
>  static tree build_var (tree, tree, int);
>  static void build_fn_info_type (tree, unsigned, tree);
> @@ -149,32 +143,31 @@ get_gcov_unsigned_t (void)
>    return lang_hooks.types.type_for_mode (mode, true);
>  }
>  \f
> -static hashval_t
> -htab_counts_entry_hash (const void *of)
> +inline hashval_t
> +coverage_counts_entry_hash (const counts_entry_t *entry)
>  {
> -  const counts_entry_t *const entry = (const counts_entry_t *) of;
> -
>    return entry->ident * GCOV_COUNTERS + entry->ctr;
>  }
>  
> -static int
> -htab_counts_entry_eq (const void *of1, const void *of2)
> +inline int
> +coverage_counts_entry_eq (const counts_entry_t *entry1,
> +                          const counts_entry_t *entry2)
>  {
> -  const counts_entry_t *const entry1 = (const counts_entry_t *) of1;
> -  const counts_entry_t *const entry2 = (const counts_entry_t *) of2;
> -
>    return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
>  }
>  
> -static void
> -htab_counts_entry_del (void *of)
> +inline void
> +coverage_counts_entry_del (counts_entry_t *entry)
>  {
> -  counts_entry_t *const entry = (counts_entry_t *) of;
> -
>    free (entry->counts);
>    free (entry);
>  }
>  
> +/* Hash table of count data.  */
> +static hash_table <counts_entry_t, coverage_counts_entry_hash,
> +		   coverage_counts_entry_eq, coverage_counts_entry_del>
> +		  counts_hash;
> +
>  /* Read in the counts file, if available.  */
>  
>  static void
> @@ -214,9 +207,7 @@ read_counts_file (void)
>    tag = gcov_read_unsigned ();
>    bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
>  
> -  counts_hash = htab_create (10,
> -			     htab_counts_entry_hash, htab_counts_entry_eq,
> -			     htab_counts_entry_del);
> +  counts_hash.create (10);
>    while ((tag = gcov_read_unsigned ()))
>      {
>        gcov_unsigned_t length;
> @@ -264,8 +255,7 @@ read_counts_file (void)
>  	  elt.ident = fn_ident;
>  	  elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
>  
> -	  slot = (counts_entry_t **) htab_find_slot
> -	    (counts_hash, &elt, INSERT);
> +	  slot = counts_hash.find_slot (&elt, INSERT);
>  	  entry = *slot;
>  	  if (!entry)
>  	    {
> @@ -285,14 +275,14 @@ read_counts_file (void)
>  	      error ("checksum is (%x,%x) instead of (%x,%x)",
>  		     entry->lineno_checksum, entry->cfg_checksum,
>  		     lineno_checksum, cfg_checksum);
> -	      htab_delete (counts_hash);
> +	      counts_hash.dispose ();
>  	      break;
>  	    }
>  	  else if (entry->summary.num != n_counts)
>  	    {
>  	      error ("Profile data for function %u is corrupted", fn_ident);
>  	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
> -	      htab_delete (counts_hash);
> +	      counts_hash.dispose ();
>  	      break;
>  	    }
>  	  else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
> @@ -318,7 +308,7 @@ read_counts_file (void)
>  	{
>  	  error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted",
>  		 da_file_name);
> -	  htab_delete (counts_hash);
> +	  counts_hash.dispose ();
>  	  break;
>  	}
>      }
> @@ -336,7 +326,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
>    counts_entry_t *entry, elt;
>  
>    /* No hash table, no counts.  */
> -  if (!counts_hash)
> +  if (!counts_hash.is_created ())
>      {
>        static int warned = 0;
>  
> @@ -350,7 +340,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
>  
>    elt.ident = current_function_funcdef_no + 1;
>    elt.ctr = counter;
> -  entry = (counts_entry_t *) htab_find (counts_hash, &elt);
> +  entry = counts_hash.find (&elt);
>    if (!entry || !entry->summary.num)
>      /* The function was not emitted, or is weak and not chosen in the
>         final executable.  Silently fail, because there's nothing we
> diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
> index 9b186dd..9f602e9 100644
> --- a/gcc/tree-ssa-pre.c
> +++ b/gcc/tree-ssa-pre.c
> @@ -30,7 +30,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-inline.h"
>  #include "tree-flow.h"
>  #include "gimple.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "tree-iterator.h"
>  #include "alloc-pool.h"
>  #include "obstack.h"
> @@ -177,12 +177,11 @@ typedef struct pre_expr_d
>  #define PRE_EXPR_REFERENCE(e) (e)->u.reference
>  #define PRE_EXPR_CONSTANT(e) (e)->u.constant
>  
> -static int
> -pre_expr_eq (const void *p1, const void *p2)
> -{
> -  const struct pre_expr_d *e1 = (const struct pre_expr_d *) p1;
> -  const struct pre_expr_d *e2 = (const struct pre_expr_d *) p2;
> +/* Compare E1 and E1 for equality.  */
>  
> +inline int
> +ssa_pre_expr_eq (const struct pre_expr_d *e1, const struct pre_expr_d *e2)
> +{
>    if (e1->kind != e2->kind)
>      return false;
>  
> @@ -203,10 +202,11 @@ pre_expr_eq (const void *p1, const void *p2)
>      }
>  }
>  
> -static hashval_t
> -pre_expr_hash (const void *p1)
> +/* Hash E.  */
> +
> +inline hashval_t
> +ssa_pre_expr_hash (const struct pre_expr_d *e)
>  {
> -  const struct pre_expr_d *e = (const struct pre_expr_d *) p1;
>    switch (e->kind)
>      {
>      case CONSTANT:
> @@ -222,7 +222,6 @@ pre_expr_hash (const void *p1)
>      }
>  }
>  
> -
>  /* Next global expression id number.  */
>  static unsigned int next_expression_id;
>  
> @@ -230,7 +229,9 @@ static unsigned int next_expression_id;
>  DEF_VEC_P (pre_expr);
>  DEF_VEC_ALLOC_P (pre_expr, heap);
>  static VEC(pre_expr, heap) *expressions;
> -static htab_t expression_to_id;
> +static hash_table <pre_expr_d, ssa_pre_expr_hash, ssa_pre_expr_eq,
> +		   typed_null_remove <pre_expr_d> >
> +		  expression_to_id;
>  static VEC(unsigned, heap) *name_to_id;
>  
>  /* Allocate an expression id for EXPR.  */
> @@ -238,7 +239,7 @@ static VEC(unsigned, heap) *name_to_id;
>  static inline unsigned int
>  alloc_expression_id (pre_expr expr)
>  {
> -  void **slot;
> +  struct pre_expr_d **slot;
>    /* Make sure we won't overflow. */
>    gcc_assert (next_expression_id + 1 > next_expression_id);
>    expr->id = next_expression_id++;
> @@ -257,7 +258,7 @@ alloc_expression_id (pre_expr expr)
>      }
>    else
>      {
> -      slot = htab_find_slot (expression_to_id, expr, INSERT);
> +      slot = expression_to_id.find_slot (expr, INSERT);
>        gcc_assert (!*slot);
>        *slot = expr;
>      }
> @@ -275,7 +276,7 @@ get_expression_id (const pre_expr expr)
>  static inline unsigned int
>  lookup_expression_id (const pre_expr expr)
>  {
> -  void **slot;
> +  struct pre_expr_d **slot;
>  
>    if (expr->kind == NAME)
>      {
> @@ -286,7 +287,7 @@ lookup_expression_id (const pre_expr expr)
>      }
>    else
>      {
> -      slot = htab_find_slot (expression_to_id, expr, NO_INSERT);
> +      slot = expression_to_id.find_slot (expr, NO_INSERT);
>        if (!slot)
>  	return 0;
>        return ((pre_expr)*slot)->id;
> @@ -479,11 +480,6 @@ static bitmap need_eh_cleanup;
>  /* Set of blocks with statements that have had their AB properties changed.  */
>  static bitmap need_ab_cleanup;
>  
> -/* The phi_translate_table caches phi translations for a given
> -   expression and predecessor.  */
> -
> -static htab_t phi_translate_table;
> -
>  /* A three tuple {e, pred, v} used to cache phi translations in the
>     phi_translate_table.  */
>  
> @@ -506,21 +502,19 @@ typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
>  
>  /* Return the hash value for a phi translation table entry.  */
>  
> -static hashval_t
> -expr_pred_trans_hash (const void *p)
> +inline hashval_t
> +ssa_expr_pred_trans_hash (const expr_pred_trans_d *ve)
>  {
> -  const_expr_pred_trans_t const ve = (const_expr_pred_trans_t) p;
>    return ve->hashcode;
>  }
>  
>  /* Return true if two phi translation table entries are the same.
>     P1 and P2 should point to the expr_pred_trans_t's to be compared.*/
>  
> -static int
> -expr_pred_trans_eq (const void *p1, const void *p2)
> +inline int
> +ssa_expr_pred_trans_eq (const expr_pred_trans_d *ve1,
> +			const expr_pred_trans_d *ve2)
>  {
> -  const_expr_pred_trans_t const ve1 = (const_expr_pred_trans_t) p1;
> -  const_expr_pred_trans_t const ve2 = (const_expr_pred_trans_t) p2;
>    basic_block b1 = ve1->pred;
>    basic_block b2 = ve2->pred;
>  
> @@ -528,9 +522,17 @@ expr_pred_trans_eq (const void *p1, const void *p2)
>       be equal.  */
>    if (b1 != b2)
>      return false;
> -  return pre_expr_eq (ve1->e, ve2->e);
> +  return ssa_pre_expr_eq (ve1->e, ve2->e);
>  }
>  
> +/* The phi_translate_table caches phi translations for a given
> +   expression and predecessor.  */
> +
> +static hash_table <expr_pred_trans_d, ssa_expr_pred_trans_hash,
> +		   ssa_expr_pred_trans_eq,
> +		   typed_free_remove <expr_pred_trans_d> >
> +		  phi_translate_table;
> +
>  /* Search in the phi translation table for the translation of
>     expression E in basic block PRED.
>     Return the translated value, if found, NULL otherwise.  */
> @@ -538,18 +540,18 @@ expr_pred_trans_eq (const void *p1, const void *p2)
>  static inline pre_expr
>  phi_trans_lookup (pre_expr e, basic_block pred)
>  {
> -  void **slot;
> +  expr_pred_trans_t *slot;
>    struct expr_pred_trans_d ept;
>  
>    ept.e = e;
>    ept.pred = pred;
> -  ept.hashcode = iterative_hash_hashval_t (pre_expr_hash (e), pred->index);
> -  slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode,
> +  ept.hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e), pred->index);
> +  slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode,
>  				   NO_INSERT);
>    if (!slot)
>      return NULL;
>    else
> -    return ((expr_pred_trans_t) *slot)->v;
> +    return (*slot)->v;
>  }
>  
>  
> @@ -559,18 +561,18 @@ phi_trans_lookup (pre_expr e, basic_block pred)
>  static inline void
>  phi_trans_add (pre_expr e, pre_expr v, basic_block pred)
>  {
> -  void **slot;
> +  expr_pred_trans_t *slot;
>    expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d);
>    new_pair->e = e;
>    new_pair->pred = pred;
>    new_pair->v = v;
> -  new_pair->hashcode = iterative_hash_hashval_t (pre_expr_hash (e),
> +  new_pair->hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e),
>  						 pred->index);
>  
> -  slot = htab_find_slot_with_hash (phi_translate_table, new_pair,
> +  slot = phi_translate_table.find_slot_with_hash (new_pair,
>  				   new_pair->hashcode, INSERT);
>    free (*slot);
> -  *slot = (void *) new_pair;
> +  *slot = new_pair;
>  }
>  
>  
> @@ -1607,12 +1609,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
>  		if (double_int_fits_in_shwi_p (off))
>  		  newop.off = off.low;
>  	      }
> -	    VEC_replace (vn_reference_op_s, newoperands, j, &newop);
> +	    VEC_replace (vn_reference_op_s, newoperands, j, newop);
>  	    /* If it transforms from an SSA_NAME to an address, fold with
>  	       a preceding indirect reference.  */
>  	    if (j > 0 && op[0] && TREE_CODE (op[0]) == ADDR_EXPR
>  		&& VEC_index (vn_reference_op_s,
> -			      newoperands, j - 1)->opcode == MEM_REF)
> +			      newoperands, j - 1).opcode == MEM_REF)
>  	      vn_reference_fold_indirect (&newoperands, &j);
>  	  }
>  	if (i != VEC_length (vn_reference_op_s, operands))
> @@ -2596,8 +2598,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
>  				  unsigned int *operand, gimple_seq *stmts,
>  				  gimple domstmt)
>  {
> -  vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
> -					*operand);
> +  vn_reference_op_t currop = &VEC_index (vn_reference_op_s, ref->operands,
> +					 *operand);
>    tree genop;
>    ++*operand;
>    switch (currop->opcode)
> @@ -2674,8 +2676,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
>        {
>  	pre_expr op0expr, op1expr;
>  	tree genop0 = NULL_TREE, genop1 = NULL_TREE;
> -	vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands,
> -					      ++*operand);
> +	vn_reference_op_t nextop = &VEC_index (vn_reference_op_s, ref->operands,
> +					       ++*operand);
>  	tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
>  							stmts, domstmt);
>  	if (!baseop)
> @@ -3488,7 +3490,7 @@ do_regular_insertion (basic_block block, basic_block dom)
>  		    do_insertion = true;
>  		  if (first_s == NULL)
>  		    first_s = edoubleprime;
> -		  else if (!pre_expr_eq (first_s, edoubleprime))
> +		  else if (!ssa_pre_expr_eq (first_s, edoubleprime))
>  		    all_same = false;
>  		}
>  	    }
> @@ -4767,7 +4769,7 @@ init_pre (bool do_fre)
>  
>    next_expression_id = 1;
>    expressions = NULL;
> -  VEC_safe_push (pre_expr, heap, expressions, NULL);
> +  VEC_safe_push (pre_expr, heap, expressions, (pre_expr)NULL);
>    value_expressions = VEC_alloc (bitmap_set_t, heap, get_max_value_id () + 1);
>    VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
>  			 get_max_value_id() + 1);
> @@ -4790,11 +4792,8 @@ init_pre (bool do_fre)
>    calculate_dominance_info (CDI_DOMINATORS);
>  
>    bitmap_obstack_initialize (&grand_bitmap_obstack);
> -  phi_translate_table = htab_create (5110, expr_pred_trans_hash,
> -				     expr_pred_trans_eq, free);
> -  expression_to_id = htab_create (num_ssa_names * 3,
> -				  pre_expr_hash,
> -				  pre_expr_eq, NULL);
> +  phi_translate_table.create (5110);
> +  expression_to_id.create (num_ssa_names * 3);
>    bitmap_set_pool = create_alloc_pool ("Bitmap sets",
>  				       sizeof (struct bitmap_set), 30);
>    pre_expr_pool = create_alloc_pool ("pre_expr nodes",
> @@ -4826,8 +4825,8 @@ fini_pre (bool do_fre)
>    bitmap_obstack_release (&grand_bitmap_obstack);
>    free_alloc_pool (bitmap_set_pool);
>    free_alloc_pool (pre_expr_pool);
> -  htab_delete (phi_translate_table);
> -  htab_delete (expression_to_id);
> +  phi_translate_table.dispose ();
> +  expression_to_id.dispose ();
>    VEC_free (unsigned, heap, name_to_id);
>  
>    free_aux_for_blocks ();
> diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
> index a2d4633..57d9f99 100644
> --- a/gcc/tree-ssa-tail-merge.c
> +++ b/gcc/tree-ssa-tail-merge.c
> @@ -193,7 +193,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "bitmap.h"
>  #include "tree-ssa-alias.h"
>  #include "params.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "gimple-pretty-print.h"
>  #include "tree-ssa-sccvn.h"
>  #include "tree-dump.h"
> @@ -368,11 +368,10 @@ same_succ_print (FILE *file, const same_succ e)
>  
>  /* Prints same_succ VE to VFILE.  */
>  
> -static int
> -same_succ_print_traverse (void **ve, void *vfile)
> +inline int
> +ssa_same_succ_print_traverse (same_succ *pe, FILE *file)
>  {
> -  const same_succ e = *((const same_succ *)ve);
> -  FILE *file = ((FILE*)vfile);
> +  const same_succ e = *pe;
>    same_succ_print (file, e);
>    return 1;
>  }
> @@ -416,10 +415,9 @@ stmt_update_dep_bb (gimple stmt)
>  
>  /* Calculates hash value for same_succ VE.  */
>  
> -static hashval_t
> -same_succ_hash (const void *ve)
> +hashval_t
> +ssa_same_succ_hash (const_same_succ e)
>  {
> -  const_same_succ e = (const_same_succ)ve;
>    hashval_t hashval = bitmap_hash (e->succs);
>    int flags;
>    unsigned int i;
> @@ -515,11 +513,9 @@ inverse_flags (const_same_succ e1, const_same_succ e2)
>  
>  /* Compares SAME_SUCCs VE1 and VE2.  */
>  
> -static int
> -same_succ_equal (const void *ve1, const void *ve2)
> +int
> +ssa_same_succ_equal (const_same_succ e1, const_same_succ e2)
>  {
> -  const_same_succ e1 = (const_same_succ)ve1;
> -  const_same_succ e2 = (const_same_succ)ve2;
>    unsigned int i, first1, first2;
>    gimple_stmt_iterator gsi1, gsi2;
>    gimple s1, s2;
> @@ -590,17 +586,15 @@ same_succ_alloc (void)
>  
>  /* Delete same_succ VE.  */
>  
> -static void
> -same_succ_delete (void *ve)
> +inline void
> +ssa_same_succ_delete (same_succ e)
>  {
> -  same_succ e = (same_succ)ve;
> -
>    BITMAP_FREE (e->bbs);
>    BITMAP_FREE (e->succs);
>    BITMAP_FREE (e->inverse);
>    VEC_free (int, heap, e->succ_flags);
>  
> -  XDELETE (ve);
> +  XDELETE (e);
>  }
>  
>  /* Reset same_succ SAME.  */
> @@ -616,7 +610,9 @@ same_succ_reset (same_succ same)
>  
>  /* Hash table with all same_succ entries.  */
>  
> -static htab_t same_succ_htab;
> +static hash_table <struct same_succ_def, ssa_same_succ_hash,
> +		   ssa_same_succ_equal, ssa_same_succ_delete>
> +		  same_succ_htab;
>  
>  /* Array that is used to store the edge flags for a successor.  */
>  
> @@ -637,7 +633,7 @@ extern void debug_same_succ (void);
>  DEBUG_FUNCTION void
>  debug_same_succ ( void)
>  {
> -  htab_traverse (same_succ_htab, same_succ_print_traverse, stderr);
> +  same_succ_htab.traverse <FILE *, ssa_same_succ_print_traverse> (stderr);
>  }
>  
>  DEF_VEC_P (same_succ);
> @@ -696,10 +692,9 @@ find_same_succ_bb (basic_block bb, same_succ *same_p)
>    EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
>      VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
>  
> -  same->hashval = same_succ_hash (same);
> +  same->hashval = ssa_same_succ_hash (same);
>  
> -  slot = (same_succ *) htab_find_slot_with_hash (same_succ_htab, same,
> -						   same->hashval, INSERT);
> +  slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
>    if (*slot == NULL)
>      {
>        *slot = same;
> @@ -733,7 +728,7 @@ find_same_succ (void)
>  	same = same_succ_alloc ();
>      }
>  
> -  same_succ_delete (same);
> +  ssa_same_succ_delete (same);
>  }
>  
>  /* Initializes worklist administration.  */
> @@ -742,9 +737,7 @@ static void
>  init_worklist (void)
>  {
>    alloc_aux_for_blocks (sizeof (struct aux_bb_info));
> -  same_succ_htab
> -    = htab_create (n_basic_blocks, same_succ_hash, same_succ_equal,
> -		   same_succ_delete);
> +  same_succ_htab.create (n_basic_blocks);
>    same_succ_edge_flags = XCNEWVEC (int, last_basic_block);
>    deleted_bbs = BITMAP_ALLOC (NULL);
>    deleted_bb_preds = BITMAP_ALLOC (NULL);
> @@ -764,8 +757,7 @@ static void
>  delete_worklist (void)
>  {
>    free_aux_for_blocks ();
> -  htab_delete (same_succ_htab);
> -  same_succ_htab = NULL;
> +  same_succ_htab.dispose ();
>    XDELETEVEC (same_succ_edge_flags);
>    same_succ_edge_flags = NULL;
>    BITMAP_FREE (deleted_bbs);
> @@ -795,7 +787,7 @@ same_succ_flush_bb (basic_block bb)
>    same_succ same = BB_SAME_SUCC (bb);
>    BB_SAME_SUCC (bb) = NULL;
>    if (bitmap_single_bit_set_p (same->bbs))
> -    htab_remove_elt_with_hash (same_succ_htab, same, same->hashval);
> +    same_succ_htab.remove_elt_with_hash (same, same->hashval);
>    else
>      bitmap_clear_bit (same->bbs, bb->index);
>  }
> @@ -868,7 +860,7 @@ update_worklist (void)
>        if (same == NULL)
>  	same = same_succ_alloc ();
>      }
> -  same_succ_delete (same);
> +  ssa_same_succ_delete (same);
>    bitmap_clear (deleted_bb_preds);
>  }
>  
> @@ -1637,7 +1629,7 @@ tail_merge_optimize (unsigned int todo)
>  
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      fprintf (dump_file, "htab collision / search: %f\n",
> -	     htab_collisions (same_succ_htab));
> +	     same_succ_htab.collisions ());
>  
>    if (nr_bbs_removed_total > 0)
>      {
> diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
> index a0536db..3ecb303 100644
> --- a/gcc/tree-ssa-threadupdate.c
> +++ b/gcc/tree-ssa-threadupdate.c
> @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-flow.h"
>  #include "dumpfile.h"
>  #include "cfgloop.h"
> +#include "hash-table.h"
>  
>  /* Given a block B, update the CFG and SSA graph to reflect redirecting
>     one or more in-edges to B to instead reach the destination of an
> @@ -126,11 +127,8 @@ struct redirection_data
>    struct el *incoming_edges;
>  };
>  
> -/* Main data structure to hold information for duplicates of BB.  */
> -static htab_t redirection_data;
> -
>  /* Data structure of information to pass to hash table traversal routines.  */
> -struct local_info
> +struct ssa_local_info_t
>  {
>    /* The current block we are working on.  */
>    basic_block bb;
> @@ -220,24 +218,32 @@ create_block_for_threading (basic_block bb, struct redirection_data *rd)
>  }
>  
>  /* Hashing and equality routines for our hash table.  */
> -static hashval_t
> -redirection_data_hash (const void *p)
> +inline hashval_t
> +ssa_redirection_data_hash (const struct redirection_data *p)
>  {
> -  edge e = ((const struct redirection_data *)p)->outgoing_edge;
> +  edge e = p->outgoing_edge;
>    return e->dest->index;
>  }
>  
> -static int
> -redirection_data_eq (const void *p1, const void *p2)
> +inline int
> +ssa_redirection_data_eq (const struct redirection_data *p1,
> +			 const struct redirection_data *p2)
>  {
> -  edge e1 = ((const struct redirection_data *)p1)->outgoing_edge;
> -  edge e2 = ((const struct redirection_data *)p2)->outgoing_edge;
> -  edge e3 = ((const struct redirection_data *)p1)->intermediate_edge;
> -  edge e4 = ((const struct redirection_data *)p2)->intermediate_edge;
> +  edge e1 = p1->outgoing_edge;
> +  edge e2 = p2->outgoing_edge;
> +  edge e3 = p1->intermediate_edge;
> +  edge e4 = p2->intermediate_edge;
>  
>    return e1 == e2 && e3 == e4;
>  }
>  
> +/* Main data structure to hold information for duplicates of BB.  */
> +
> +static hash_table <struct redirection_data, ssa_redirection_data_hash,
> +		   ssa_redirection_data_eq,
> +		   typed_free_remove<struct redirection_data> >
> +		  redirection_data;
> +
>  /* Given an outgoing edge E lookup and return its entry in our hash table.
>  
>     If INSERT is true, then we insert the entry into the hash table if
> @@ -247,7 +253,7 @@ redirection_data_eq (const void *p1, const void *p2)
>  static struct redirection_data *
>  lookup_redirection_data (edge e, enum insert_option insert)
>  {
> -  void **slot;
> +  struct redirection_data **slot;
>    struct redirection_data *elt;
>  
>   /* Build a hash table element so we can see if E is already
> @@ -259,7 +265,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
>    elt->dup_block = NULL;
>    elt->incoming_edges = NULL;
>  
> -  slot = htab_find_slot (redirection_data, elt, insert);
> +  slot = redirection_data.find_slot (elt, insert);
>  
>    /* This will only happen if INSERT is false and the entry is not
>       in the hash table.  */
> @@ -273,7 +279,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
>       INSERT is true.  */
>    if (*slot == NULL)
>      {
> -      *slot = (void *)elt;
> +      *slot = elt;
>        elt->incoming_edges = XNEW (struct el);
>        elt->incoming_edges->e = e;
>        elt->incoming_edges->next = NULL;
> @@ -287,7 +293,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
>        free (elt);
>  
>        /* Get the entry stored in the hash table.  */
> -      elt = (struct redirection_data *) *slot;
> +      elt = *slot;
>  
>        /* If insertion was requested, then we need to add INCOMING_EDGE
>  	 to the list of incoming edges associated with E.  */
> @@ -375,9 +381,9 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
>  
>  /* Wire up the outgoing edges from the duplicate block and
>     update any PHIs as needed.  */
> -static void
> -fix_duplicate_block_edges (struct redirection_data *rd,
> -			   struct local_info *local_info)
> +void
> +ssa_fix_duplicate_block_edges (struct redirection_data *rd,
> +			       ssa_local_info_t *local_info)
>  {
>    /* If we were threading through an joiner block, then we want
>       to keep its control statement and redirect an outgoing edge.
> @@ -412,11 +418,11 @@ fix_duplicate_block_edges (struct redirection_data *rd,
>  }
>  /* Hash table traversal callback routine to create duplicate blocks.  */
>  
> -static int
> -create_duplicates (void **slot, void *data)
> +int
> +ssa_create_duplicates (struct redirection_data **slot,
> +		       ssa_local_info_t *local_info)
>  {
> -  struct redirection_data *rd = (struct redirection_data *) *slot;
> -  struct local_info *local_info = (struct local_info *)data;
> +  struct redirection_data *rd = *slot;
>  
>    /* Create a template block if we have not done so already.  Otherwise
>       use the template to create a new block.  */
> @@ -435,7 +441,7 @@ create_duplicates (void **slot, void *data)
>  
>        /* Go ahead and wire up outgoing edges and update PHIs for the duplicate
>  	 block.   */
> -      fix_duplicate_block_edges (rd, local_info);
> +      ssa_fix_duplicate_block_edges (rd, local_info);
>      }
>  
>    /* Keep walking the hash table.  */
> @@ -446,11 +452,11 @@ create_duplicates (void **slot, void *data)
>     block creation.  This hash table traversal callback creates the
>     outgoing edge for the template block.  */
>  
> -static int
> -fixup_template_block (void **slot, void *data)
> +inline int
> +ssa_fixup_template_block (struct redirection_data **slot,
> +			  ssa_local_info_t *local_info)
>  {
> -  struct redirection_data *rd = (struct redirection_data *) *slot;
> -  struct local_info *local_info = (struct local_info *)data;
> +  struct redirection_data *rd = *slot;
>  
>    /* If this is the template block halt the traversal after updating
>       it appropriately.
> @@ -461,7 +467,7 @@ fixup_template_block (void **slot, void *data)
>       a new outgoing edge.  In both cases we may need to update PHIs.  */
>    if (rd->dup_block && rd->dup_block == local_info->template_block)
>      {
> -      fix_duplicate_block_edges (rd, local_info);
> +      ssa_fix_duplicate_block_edges (rd, local_info);
>        return 0;
>      }
>  
> @@ -471,11 +477,11 @@ fixup_template_block (void **slot, void *data)
>  /* Hash table traversal callback to redirect each incoming edge
>     associated with this hash table element to its new destination.  */
>  
> -static int
> -redirect_edges (void **slot, void *data)
> +int
> +ssa_redirect_edges (struct redirection_data **slot,
> +		    ssa_local_info_t *local_info)
>  {
> -  struct redirection_data *rd = (struct redirection_data *) *slot;
> -  struct local_info *local_info = (struct local_info *)data;
> +  struct redirection_data *rd = *slot;
>    struct el *next, *el;
>  
>    /* Walk over all the incoming edges associated associated with this
> @@ -594,17 +600,14 @@ thread_block (basic_block bb, bool noloop_only)
>       redirect to a duplicate of BB.  */
>    edge e, e2;
>    edge_iterator ei;
> -  struct local_info local_info;
> +  ssa_local_info_t local_info;
>    struct loop *loop = bb->loop_father;
>  
>    /* To avoid scanning a linear array for the element we need we instead
>       use a hash table.  For normal code there should be no noticeable
>       difference.  However, if we have a block with a large number of
>       incoming and outgoing edges such linear searches can get expensive.  */
> -  redirection_data = htab_create (EDGE_COUNT (bb->succs),
> -				  redirection_data_hash,
> -				  redirection_data_eq,
> -				  free);
> +  redirection_data.create (EDGE_COUNT (bb->succs));
>  
>    /* If we thread the latch of the loop to its exit, the loop ceases to
>       exist.  Make sure we do not restrict ourselves in order to preserve
> @@ -678,24 +681,26 @@ thread_block (basic_block bb, bool noloop_only)
>    local_info.template_block = NULL;
>    local_info.bb = bb;
>    local_info.jumps_threaded = false;
> -  htab_traverse (redirection_data, create_duplicates, &local_info);
> +  redirection_data.traverse <ssa_local_info_t *, ssa_create_duplicates>
> +			    (&local_info);
>  
>    /* The template does not have an outgoing edge.  Create that outgoing
>       edge and update PHI nodes as the edge's target as necessary.
>  
>       We do this after creating all the duplicates to avoid creating
>       unnecessary edges.  */
> -  htab_traverse (redirection_data, fixup_template_block, &local_info);
> +  redirection_data.traverse <ssa_local_info_t *, ssa_fixup_template_block>
> +			    (&local_info);
>  
>    /* The hash table traversals above created the duplicate blocks (and the
>       statements within the duplicate blocks).  This loop creates PHI nodes for
>       the duplicated blocks and redirects the incoming edges into BB to reach
>       the duplicates of BB.  */
> -  htab_traverse (redirection_data, redirect_edges, &local_info);
> +  redirection_data.traverse <ssa_local_info_t *, ssa_redirect_edges>
> +			    (&local_info);
>  
>    /* Done with this block.  Clear REDIRECTION_DATA.  */
> -  htab_delete (redirection_data);
> -  redirection_data = NULL;
> +  redirection_data.dispose ();
>  
>    if (noloop_only
>        && bb == bb->loop_father->header)
> diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
> index 8244f0c..d0973f4 100644
> --- a/libcpp/identifiers.c
> +++ b/libcpp/identifiers.c
> @@ -28,12 +28,12 @@ along with this program; see the file COPYING3.  If not see
>  #include "cpplib.h"
>  #include "internal.h"
>  
> -static hashnode alloc_node (hash_table *);
> +static hashnode alloc_node (cpp_hash_table *);
>  
>  /* Return an identifier node for hashtable.c.  Used by cpplib except
>     when integrated with the C front ends.  */
>  static hashnode
> -alloc_node (hash_table *table)
> +alloc_node (cpp_hash_table *table)
>  {
>    cpp_hashnode *node;
>  
> @@ -45,7 +45,7 @@ alloc_node (hash_table *table)
>  /* Set up the identifier hash table.  Use TABLE if non-null, otherwise
>     create our own.  */
>  void
> -_cpp_init_hashtable (cpp_reader *pfile, hash_table *table)
> +_cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table)
>  {
>    struct spec_nodes *s;
>  
> diff --git a/libcpp/include/symtab.h b/libcpp/include/symtab.h
> index 4107a6f..30d7645 100644
> --- a/libcpp/include/symtab.h
> +++ b/libcpp/include/symtab.h
> @@ -38,7 +38,7 @@ struct GTY(()) ht_identifier {
>  #define HT_LEN(NODE) ((NODE)->len)
>  #define HT_STR(NODE) ((NODE)->str)
>  
> -typedef struct ht hash_table;
> +typedef struct ht cpp_hash_table;
>  typedef struct ht_identifier *hashnode;
>  
>  enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC};
> @@ -51,7 +51,7 @@ struct ht
>  
>    hashnode *entries;
>    /* Call back, allocate a node.  */
> -  hashnode (*alloc_node) (hash_table *);
> +  hashnode (*alloc_node) (cpp_hash_table *);
>    /* Call back, allocate something that hangs off a node like a cpp_macro.  
>       NULL means use the usual allocator.  */
>    void * (*alloc_subobject) (size_t);
> @@ -71,14 +71,14 @@ struct ht
>  };
>  
>  /* Initialize the hashtable with 2 ^ order entries.  */
> -extern hash_table *ht_create (unsigned int order);
> +extern cpp_hash_table *ht_create (unsigned int order);
>  
>  /* Frees all memory associated with a hash table.  */
> -extern void ht_destroy (hash_table *);
> +extern void ht_destroy (cpp_hash_table *);
>  
> -extern hashnode ht_lookup (hash_table *, const unsigned char *,
> +extern hashnode ht_lookup (cpp_hash_table *, const unsigned char *,
>  			   size_t, enum ht_lookup_option);
> -extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
> +extern hashnode ht_lookup_with_hash (cpp_hash_table *, const unsigned char *,
>                                       size_t, unsigned int,
>                                       enum ht_lookup_option);
>  #define HT_HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
> @@ -88,17 +88,17 @@ extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
>     TABLE->PFILE, the node, and a PTR, and the callback sequence stops
>     if the callback returns zero.  */
>  typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
> -extern void ht_forall (hash_table *, ht_cb, const void *);
> +extern void ht_forall (cpp_hash_table *, ht_cb, const void *);
>  
>  /* For all nodes in TABLE, call the callback.  If the callback returns
>     a nonzero value, the node is removed from the table.  */
> -extern void ht_purge (hash_table *, ht_cb, const void *);
> +extern void ht_purge (cpp_hash_table *, ht_cb, const void *);
>  
>  /* Restore the hash table.  */
> -extern void ht_load (hash_table *ht, hashnode *entries,
> +extern void ht_load (cpp_hash_table *ht, hashnode *entries,
>  		     unsigned int nslots, unsigned int nelements, bool own);
>  
>  /* Dump allocation statistics to stderr.  */
> -extern void ht_dump_statistics (hash_table *);
> +extern void ht_dump_statistics (cpp_hash_table *);
>  
>  #endif /* LIBCPP_SYMTAB_H */
> diff --git a/libcpp/init.c b/libcpp/init.c
> index 7752fea..040ab34 100644
> --- a/libcpp/init.c
> +++ b/libcpp/init.c
> @@ -149,7 +149,7 @@ init_library (void)
>  
>  /* Initialize a cpp_reader structure.  */
>  cpp_reader *
> -cpp_create_reader (enum c_lang lang, hash_table *table,
> +cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
>  		   struct line_maps *line_table)
>  {
>    cpp_reader *pfile;
> diff --git a/libcpp/internal.h b/libcpp/internal.h
> index 37aac82..79dd54f 100644
> --- a/libcpp/internal.h
> +++ b/libcpp/internal.h
> @@ -619,7 +619,7 @@ extern void _cpp_push_token_context (cpp_reader *, cpp_hashnode *,
>  extern void _cpp_backup_tokens_direct (cpp_reader *, unsigned int);
>  
>  /* In identifiers.c */
> -extern void _cpp_init_hashtable (cpp_reader *, hash_table *);
> +extern void _cpp_init_hashtable (cpp_reader *, cpp_hash_table *);
>  extern void _cpp_destroy_hashtable (cpp_reader *);
>  
>  /* In files.c */
> diff --git a/libcpp/symtab.c b/libcpp/symtab.c
> index 48a5338..a3537a0 100644
> --- a/libcpp/symtab.c
> +++ b/libcpp/symtab.c
> @@ -31,7 +31,7 @@ along with this program; see the file COPYING3.  If not see
>     existing entry with a potential new one.  */
>  
>  static unsigned int calc_hash (const unsigned char *, size_t);
> -static void ht_expand (hash_table *);
> +static void ht_expand (cpp_hash_table *);
>  static double approx_sqrt (double);
>  
>  /* A deleted entry.  */
> @@ -53,13 +53,13 @@ calc_hash (const unsigned char *str, size_t len)
>  
>  /* Initialize an identifier hashtable.  */
>  
> -hash_table *
> +cpp_hash_table *
>  ht_create (unsigned int order)
>  {
>    unsigned int nslots = 1 << order;
> -  hash_table *table;
> +  cpp_hash_table *table;
>  
> -  table = XCNEW (hash_table);
> +  table = XCNEW (cpp_hash_table);
>  
>    /* Strings need no alignment.  */
>    _obstack_begin (&table->stack, 0, 0,
> @@ -77,7 +77,7 @@ ht_create (unsigned int order)
>  /* Frees all memory associated with a hash table.  */
>  
>  void
> -ht_destroy (hash_table *table)
> +ht_destroy (cpp_hash_table *table)
>  {
>    obstack_free (&table->stack, NULL);
>    if (table->entries_owned)
> @@ -91,7 +91,7 @@ ht_destroy (hash_table *table)
>     returns NULL.  Otherwise insert and returns a new entry.  A new
>     string is allocated.  */
>  hashnode
> -ht_lookup (hash_table *table, const unsigned char *str, size_t len,
> +ht_lookup (cpp_hash_table *table, const unsigned char *str, size_t len,
>  	   enum ht_lookup_option insert)
>  {
>    return ht_lookup_with_hash (table, str, len, calc_hash (str, len),
> @@ -99,7 +99,7 @@ ht_lookup (hash_table *table, const unsigned char *str, size_t len,
>  }
>  
>  hashnode
> -ht_lookup_with_hash (hash_table *table, const unsigned char *str,
> +ht_lookup_with_hash (cpp_hash_table *table, const unsigned char *str,
>  		     size_t len, unsigned int hash,
>  		     enum ht_lookup_option insert)
>  {
> @@ -182,7 +182,7 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
>  /* Double the size of a hash table, re-hashing existing entries.  */
>  
>  static void
> -ht_expand (hash_table *table)
> +ht_expand (cpp_hash_table *table)
>  {
>    hashnode *nentries, *p, *limit;
>    unsigned int size, sizemask;
> @@ -224,7 +224,7 @@ ht_expand (hash_table *table)
>  /* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
>     the node, and V.  */
>  void
> -ht_forall (hash_table *table, ht_cb cb, const void *v)
> +ht_forall (cpp_hash_table *table, ht_cb cb, const void *v)
>  {
>    hashnode *p, *limit;
>  
> @@ -242,7 +242,7 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
>  /* Like ht_forall, but a nonzero return from the callback means that
>     the entry should be removed from the table.  */
>  void
> -ht_purge (hash_table *table, ht_cb cb, const void *v)
> +ht_purge (cpp_hash_table *table, ht_cb cb, const void *v)
>  {
>    hashnode *p, *limit;
>  
> @@ -259,7 +259,7 @@ ht_purge (hash_table *table, ht_cb cb, const void *v)
>  
>  /* Restore the hash table.  */
>  void
> -ht_load (hash_table *ht, hashnode *entries,
> +ht_load (cpp_hash_table *ht, hashnode *entries,
>  	 unsigned int nslots, unsigned int nelements,
>  	 bool own)
>  {
> @@ -274,7 +274,7 @@ ht_load (hash_table *ht, hashnode *entries,
>  /* Dump allocation statistics to stderr.  */
>  
>  void
> -ht_dump_statistics (hash_table *table)
> +ht_dump_statistics (cpp_hash_table *table)
>  {
>    size_t nelts, nids, overhead, headers;
>    size_t total_bytes, longest, deleted = 0;
> diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
> index 83ed653..4332398 100644
> --- a/gcc/tree-ssa-ccp.c
> +++ b/gcc/tree-ssa-ccp.c
> @@ -130,6 +130,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "dbgcnt.h"
>  #include "gimple-fold.h"
>  #include "params.h"
> +#include "hash-table.h"
>  
>  
>  /* Possible lattice values.  */
> @@ -1688,11 +1689,17 @@ evaluate_stmt (gimple stmt)
>    return val;
>  }
>  
> +typedef hash_table <gimple_statement_d, typed_pointer_hash<gimple_statement_d>,
> +		    typed_pointer_equal<gimple_statement_d>,
> +		    typed_null_remove<gimple_statement_d> >
> +		   gimple_htab;
> +
>  /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
>     each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
>  
>  static void
> -insert_clobber_before_stack_restore (tree saved_val, tree var, htab_t *visited)
> +insert_clobber_before_stack_restore (tree saved_val, tree var,
> +				     gimple_htab *visited)
>  {
>    gimple stmt, clobber_stmt;
>    tree clobber;
> @@ -1712,10 +1719,10 @@ insert_clobber_before_stack_restore (tree saved_val, tree var, htab_t *visited)
>        }
>      else if (gimple_code (stmt) == GIMPLE_PHI)
>        {
> -	if (*visited == NULL)
> -	  *visited = htab_create (10, htab_hash_pointer, htab_eq_pointer, NULL);
> +	if (!visited->is_created ())
> +	  visited->create (10);
>  
> -	slot = (gimple *)htab_find_slot (*visited, stmt, INSERT);
> +	slot = visited->find_slot (stmt, INSERT);
>  	if (*slot != NULL)
>  	  continue;
>  
> @@ -1758,7 +1765,7 @@ insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
>  {
>    gimple stmt;
>    tree saved_val;
> -  htab_t visited = NULL;
> +  gimple_htab visited;
>  
>    for (; !gsi_end_p (i); gsi_prev_dom_bb_nondebug (&i))
>      {
> @@ -1775,8 +1782,8 @@ insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
>        break;
>      }
>  
> -  if (visited != NULL)
> -    htab_delete (visited);
> +  if (visited.is_created ())
> +    visited.dispose ();
>  }
>  
>  /* Detects a __builtin_alloca_with_align with constant size argument.  Declares
> diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c
> index b8b1a51..399e7fc 100644
> --- a/gcc/tree-ssa-coalesce.c
> +++ b/gcc/tree-ssa-coalesce.c
> @@ -29,7 +29,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "bitmap.h"
>  #include "dumpfile.h"
>  #include "tree-flow.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "tree-ssa-live.h"
>  #include "diagnostic-core.h"
>  
> @@ -1258,22 +1258,19 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
>      }
>  }
>  
> -/* Returns a hash code for P.  */
> +/* Returns a hash code for N.  */
>  
> -static hashval_t
> -hash_ssa_name_by_var (const void *p)
> +inline hashval_t
> +hash_ssa_name_by_var (const_tree n)
>  {
> -  const_tree n = (const_tree) p;
>    return (hashval_t) htab_hash_pointer (SSA_NAME_VAR (n));
>  }
>  
> -/* Returns nonzero if P1 and P2 are equal.  */
> +/* Returns nonzero if N1 and N2 are equal.  */
>  
> -static int
> -eq_ssa_name_by_var (const void *p1, const void *p2)
> +inline int
> +eq_ssa_name_by_var (const_tree n1, const_tree n2)
>  {
> -  const_tree n1 = (const_tree) p1;
> -  const_tree n2 = (const_tree) p2;
>    return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
>  }
>  
> @@ -1289,7 +1286,9 @@ coalesce_ssa_name (void)
>    bitmap used_in_copies = BITMAP_ALLOC (NULL);
>    var_map map;
>    unsigned int i;
> -  static htab_t ssa_name_hash;
> +  static hash_table <tree_node, hash_ssa_name_by_var, eq_ssa_name_by_var,
> +		     typed_null_remove<tree_node> >
> +		    ssa_name_hash;
>  
>    cl = create_coalesce_list ();
>    map = create_outofssa_var_map (cl, used_in_copies);
> @@ -1298,8 +1297,7 @@ coalesce_ssa_name (void)
>       so debug info remains undisturbed.  */
>    if (!optimize)
>      {
> -      ssa_name_hash = htab_create (10, hash_ssa_name_by_var,
> -      				   eq_ssa_name_by_var, NULL);
> +      ssa_name_hash.create (10);
>        for (i = 1; i < num_ssa_names; i++)
>  	{
>  	  tree a = ssa_name (i);
> @@ -1309,7 +1307,7 @@ coalesce_ssa_name (void)
>  	      && !DECL_IGNORED_P (SSA_NAME_VAR (a))
>  	      && (!has_zero_uses (a) || !SSA_NAME_IS_DEFAULT_DEF (a)))
>  	    {
> -	      tree *slot = (tree *) htab_find_slot (ssa_name_hash, a, INSERT);
> +	      tree *slot = ssa_name_hash.find_slot (a, INSERT);
>  
>  	      if (!*slot)
>  		*slot = a;
> @@ -1322,7 +1320,7 @@ coalesce_ssa_name (void)
>  		}
>  	    }
>  	}
> -      htab_delete (ssa_name_hash);
> +      ssa_name_hash.dispose ();
>      }
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      dump_var_map (dump_file, map);
> diff --git a/gcc/hash-table.c
> ===================================================================
> --- gcc/hash-table.c	(revision 0)
> +++ gcc/hash-table.c	(revision 0)
> @@ -0,0 +1,190 @@
> +/* A type-safe hash table template.
> +   Copyright (C) 2012
> +   Free Software Foundation, Inc.
> +   Contributed by Lawrence Crowl <crowl@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +
> +/* This file implements a typed hash table.
> +   The implementation borrows from libiberty's hashtab.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "hash-table.h"
> +
> +
> +/* Table of primes and multiplicative inverses.
> +
> +   Note that these are not minimally reduced inverses.  Unlike when generating
> +   code to divide by a constant, we want to be able to use the same algorithm
> +   all the time.  All of these inverses (are implied to) have bit 32 set.
> +
> +   For the record, here's the function that computed the table; it's a 
> +   vastly simplified version of the function of the same name from gcc.  */
> +
> +#if 0
> +unsigned int
> +ceil_log2 (unsigned int x)
> +{
> +  int i;
> +  for (i = 31; i >= 0 ; --i)
> +    if (x > (1u << i))
> +      return i+1;
> +  abort ();
> +}
> +
> +unsigned int
> +choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp)
> +{
> +  unsigned long long mhigh;
> +  double nx;
> +  int lgup, post_shift;
> +  int pow, pow2;
> +  int n = 32, precision = 32;
> +
> +  lgup = ceil_log2 (d);
> +  pow = n + lgup;
> +  pow2 = n + lgup - precision;
> +
> +  nx = ldexp (1.0, pow) + ldexp (1.0, pow2);
> +  mhigh = nx / d;
> +
> +  *shiftp = lgup - 1;
> +  *mlp = mhigh;
> +  return mhigh >> 32;
> +}
> +#endif
> +
> +struct prime_ent const prime_tab[] = {
> +  {          7, 0x24924925, 0x9999999b, 2 },
> +  {         13, 0x3b13b13c, 0x745d1747, 3 },
> +  {         31, 0x08421085, 0x1a7b9612, 4 },
> +  {         61, 0x0c9714fc, 0x15b1e5f8, 5 },
> +  {        127, 0x02040811, 0x0624dd30, 6 },
> +  {        251, 0x05197f7e, 0x073260a5, 7 },
> +  {        509, 0x01824366, 0x02864fc8, 8 },
> +  {       1021, 0x00c0906d, 0x014191f7, 9 },
> +  {       2039, 0x0121456f, 0x0161e69e, 10 },
> +  {       4093, 0x00300902, 0x00501908, 11 },
> +  {       8191, 0x00080041, 0x00180241, 12 },
> +  {      16381, 0x000c0091, 0x00140191, 13 },
> +  {      32749, 0x002605a5, 0x002a06e6, 14 },
> +  {      65521, 0x000f00e2, 0x00110122, 15 },
> +  {     131071, 0x00008001, 0x00018003, 16 },
> +  {     262139, 0x00014002, 0x0001c004, 17 },
> +  {     524287, 0x00002001, 0x00006001, 18 },
> +  {    1048573, 0x00003001, 0x00005001, 19 },
> +  {    2097143, 0x00004801, 0x00005801, 20 },
> +  {    4194301, 0x00000c01, 0x00001401, 21 },
> +  {    8388593, 0x00001e01, 0x00002201, 22 },
> +  {   16777213, 0x00000301, 0x00000501, 23 },
> +  {   33554393, 0x00001381, 0x00001481, 24 },
> +  {   67108859, 0x00000141, 0x000001c1, 25 },
> +  {  134217689, 0x000004e1, 0x00000521, 26 },
> +  {  268435399, 0x00000391, 0x000003b1, 27 },
> +  {  536870909, 0x00000019, 0x00000029, 28 },
> +  { 1073741789, 0x0000008d, 0x00000095, 29 },
> +  { 2147483647, 0x00000003, 0x00000007, 30 },
> +  /* Avoid "decimal constant so large it is unsigned" for 4294967291.  */
> +  { 0xfffffffb, 0x00000006, 0x00000008, 31 }
> +};
> +
> +/* The following function returns an index into the above table of the
> +   nearest prime number which is greater than N, and near a power of two. */
> +
> +unsigned int
> +hash_table_higher_prime_index (unsigned long n)
> +{
> +  unsigned int low = 0;
> +  unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
> +
> +  while (low != high)
> +    {
> +      unsigned int mid = low + (high - low) / 2;
> +      if (n > prime_tab[mid].prime)
> +	low = mid + 1;
> +      else
> +	high = mid;
> +    }
> +
> +  /* If we've run out of primes, abort.  */
> +  if (n > prime_tab[low].prime)
> +    {
> +      fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
> +      abort ();
> +    }
> +
> +  return low;
> +}
> +
> +/* Return X % Y using multiplicative inverse values INV and SHIFT.
> +
> +   The multiplicative inverses computed above are for 32-bit types,
> +   and requires that we be able to compute a highpart multiply.
> +
> +   FIX: I am not at all convinced that
> +     3 loads, 2 multiplications, 3 shifts, and 3 additions
> +   will be faster than
> +     1 load and 1 modulus
> +   on modern systems running a compiler.  */
> +
> +#ifdef UNSIGNED_64BIT_TYPE
> +static inline hashval_t
> +mul_mod (hashval_t x, hashval_t y, hashval_t inv, int shift)
> +{
> +  __extension__ typedef UNSIGNED_64BIT_TYPE ull;
> +   hashval_t t1, t2, t3, t4, q, r;
> +
> +   t1 = ((ull)x * inv) >> 32;
> +   t2 = x - t1;
> +   t3 = t2 >> 1;
> +   t4 = t1 + t3;
> +   q  = t4 >> shift;
> +   r  = x - (q * y);
> +
> +   return r;
> +}
> +#endif
> +
> +/* Compute the primary table index for HASH given current prime index.  */
> +
> +hashval_t
> +hash_table_mod1 (hashval_t hash, unsigned int index)
> +{
> +  const struct prime_ent *p = &prime_tab[index];
> +#ifdef UNSIGNED_64BIT_TYPE
> +  if (sizeof (hashval_t) * CHAR_BIT <= 32)
> +    return mul_mod (hash, p->prime, p->inv, p->shift);
> +#endif
> +  return hash % p->prime;
> +}
> +
> +
> +/* Compute the secondary table index for HASH given current prime index.  */
> +
> +hashval_t
> +hash_table_mod2 (hashval_t hash, unsigned int index)
> +{
> +  const struct prime_ent *p = &prime_tab[index];
> +#ifdef UNSIGNED_64BIT_TYPE
> +  if (sizeof (hashval_t) * CHAR_BIT <= 32)
> +    return 1 + mul_mod (hash, p->prime - 2, p->inv_m2, p->shift);
> +#endif
> +  return 1 + hash % (p->prime - 2);
> +}
> diff --git a/gcc/hash-table.h
> ===================================================================
> --- gcc/hash-table.h	(revision 0)
> +++ gcc/hash-table.h	(revision 0)
> @@ -0,0 +1,783 @@
> +/* A type-safe hash table template.
> +   Copyright (C) 2012
> +   Free Software Foundation, Inc.
> +   Contributed by Lawrence Crowl <crowl@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +
> +/* This file implements a typed hash table.
> +   The implementation borrows from libiberty's hashtab.  */
> +
> +
> +#ifndef TYPED_HASHTAB_H
> +#define TYPED_HASHTAB_H
> +
> +#include "hashtab.h"
> +
> +
> +/* The ordinary memory allocator.  */
> +/* FIXME (crowl): This allocator may be extracted for wider sharing later.  */
> +
> +template <typename Type>
> +struct xcallocator
> +{
> +  static Type *control_alloc (size_t count);
> +  static Type *data_alloc (size_t count);
> +  static void control_free (Type *memory);
> +  static void data_free (Type *memory);
> +};
> +
> +
> +/* Allocate memory for COUNT control blocks.  */
> +
> +template <typename Type>
> +inline Type *
> +xcallocator <Type>::control_alloc (size_t count)
> +{
> +  return static_cast <Type *> (xcalloc (count, sizeof (Type)));
> +}
> +
> +
> +/* Allocate memory for COUNT data blocks.  */ 
> +
> +template <typename Type>
> +inline Type *
> +xcallocator <Type>::data_alloc (size_t count)
> +{
> +  return static_cast <Type *> (xcalloc (count, sizeof (Type)));
> +}
> +
> +
> +/* Free memory for control blocks.  */
> +
> +template <typename Type>
> +inline void
> +xcallocator <Type>::control_free (Type *memory)
> +{
> +  return ::free (memory);
> +}
> +  
> +
> +/* Free memory for data blocks.  */
> +
> +template <typename Type>
> +inline void
> +xcallocator <Type>::data_free (Type *memory)
> +{
> +  return ::free (memory);
> +}
> +
> +
> +/* A common function for hashing a CANDIDATE typed pointer.  */
> +
> +template <typename Element>
> +inline hashval_t
> +typed_pointer_hash (const Element *candidate)
> +{
> +  /* This is a really poor hash function, but it is what the current code uses,
> +     so I am reusing it to avoid an additional axis in testing.  */
> +  return (hashval_t) ((intptr_t)candidate >> 3);
> +}
> +
> +
> +/* A common function for comparing an EXISTING and CANDIDATE typed pointers
> +   for equality. */
> +
> +template <typename Element>
> +inline int
> +typed_pointer_equal (const Element *existing, const Element * candidate)
> +{
> +  return existing == candidate;
> +}
> +
> +
> +/* A common function for doing nothing on removing a RETIRED slot.  */
> +
> +template <typename Element>
> +inline void
> +typed_null_remove (Element *retired ATTRIBUTE_UNUSED)
> +{
> +}
> +
> +
> +/* A common function for using free on removing a RETIRED slot.  */
> +
> +template <typename Element>
> +inline void
> +typed_free_remove (Element *retired)
> +{
> +  free (retired);
> +}
> +
> +
> +/* Table of primes and their inversion information.  */
> +
> +struct prime_ent
> +{
> +  hashval_t prime;
> +  hashval_t inv;
> +  hashval_t inv_m2;     /* inverse of prime-2 */
> +  hashval_t shift;
> +};
> +
> +extern struct prime_ent const prime_tab[];
> +
> +
> +/* Functions for computing hash table indexes.  */
> +
> +extern unsigned int hash_table_higher_prime_index (unsigned long n);
> +extern hashval_t hash_table_mod1 (hashval_t hash, unsigned int index);
> +extern hashval_t hash_table_mod2 (hashval_t hash, unsigned int index);
> +
> +
> +/* Internal implementation type.  */
> +
> +template <typename Element>
> +struct hash_table_control
> +{
> +  /* Table itself.  */
> +  Element **entries;
> +
> +  /* Current size (in entries) of the hash table.  */
> +  size_t size;
> +
> +  /* Current number of elements including also deleted elements.  */
> +  size_t n_elements;
> +
> +  /* Current number of deleted elements in the table.  */
> +  size_t n_deleted;
> +
> +  /* The following member is used for debugging. Its value is number
> +     of all calls of `htab_find_slot' for the hash table. */
> +  unsigned int searches;
> +
> +  /* The following member is used for debugging.  Its value is number
> +     of collisions fixed for time of work with the hash table. */
> +  unsigned int collisions;
> +
> +  /* Current size (in entries) of the hash table, as an index into the
> +     table of primes.  */
> +  unsigned int size_prime_index;
> +};
> +
> +
> +/* User-facing hash table type.
> +
> +   The table stores elements of type Element.
> +
> +   It hashes elements with the Hash function.
> +     The table currently works with relatively weak hash functions.
> +     Use typed_pointer_hash <Element> when hashing pointers instead of objects.
> +
> +   It compares elements with the Equal function.
> +     Two elements with the same hash may not be equal.
> +     Use typed_pointer_equal <Element> when hashing pointers instead of objects.
> +
> +   It removes elements with the Remove function.
> +     This feature is useful for freeing memory.
> +     Use typed_null_remove <Element> when not freeing objects.
> +     Use typed_free_remove <Element> when doing a simple object free.
> +
> +   Use the Allocator template to allocate and free memory.
> +     The default is xcallocator.
> +
> +*/
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator = xcallocator>
> +class hash_table
> +{
> +
> +private:
> +
> +  hash_table_control <Element> *htab;
> +
> +  Element **find_empty_slot_for_expand (hashval_t hash);
> +  void expand ();
> +
> +public:
> +
> +  hash_table ();
> +  void create (size_t initial_slots);
> +  bool is_created ();
> +  void dispose ();
> +  Element *find (Element *comparable);
> +  Element *find_with_hash (Element *comparable, hashval_t hash);
> +  Element **find_slot (Element *comparable, enum insert_option insert);
> +  Element **find_slot_with_hash (Element *comparable, hashval_t hash,
> +				 enum insert_option insert);
> +  void empty ();
> +  void clear_slot (Element **slot);
> +  void remove_elt (Element *comparable);
> +  void remove_elt_with_hash (Element *comparable, hashval_t hash);
> +  size_t size();
> +  size_t elements();
> +  double collisions();
> +
> +  template <typename Argument,
> +	    int (*Callback) (Element **slot, Argument argument)>
> +  void traverse_noresize (Argument argument);
> +
> +  template <typename Argument,
> +	    int (*Callback) (Element **slot, Argument argument)>
> +  void traverse (Argument argument);
> +};
> +
> +
> +/* Construct the hash table.  The only useful operation next is create.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline
> +hash_table <Element, Hash, Equal, Remove, Allocator>::hash_table ()
> +: htab (NULL)
> +{
> +}
> +
> +
> +/* See if the table has been created, as opposed to constructed.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline bool
> +hash_table <Element, Hash, Equal, Remove, Allocator>::is_created ()
> +{
> +  return htab != NULL;
> +}
> +
> +
> +/* Like find_with_hash, but compute the hash value from the element.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline Element *
> +hash_table <Element, Hash, Equal, Remove, Allocator>::find (Element *comparable)
> +{
> +  return find_with_hash (comparable, Hash (comparable));
> +}
> +
> +
> +/* Like find_slot_with_hash, but compute the hash value from the element.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline Element **
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_slot (Element *comparable, enum insert_option insert)
> +{
> +  return find_slot_with_hash (comparable, Hash (comparable), insert);
> +}
> +
> +
> +/* Like remove_elt_with_hash, but compute the hash value from the element.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::remove_elt (Element *comparable)
> +{
> +  remove_elt_with_hash (comparable, Hash (comparable));
> +}
> +
> +
> +/* Return the current size of this hash table.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline size_t
> +hash_table <Element, Hash, Equal, Remove, Allocator>::size()
> +{
> +  return htab->size;
> +}
> +
> +
> +/* Return the current number of elements in this hash table. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline size_t
> +hash_table <Element, Hash, Equal, Remove, Allocator>::elements()
> +{
> +  return htab->n_elements - htab->n_deleted;
> +}
> +
> +
> +  /* Return the fraction of fixed collisions during all work with given
> +     hash table. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline double
> +hash_table <Element, Hash, Equal, Remove, Allocator>::collisions()
> +{
> +  if (htab->searches == 0)
> +    return 0.0;
> +
> +  return static_cast <double> (htab->collisions) / htab->searches;
> +}
> +
> +
> +/* Create a hash table with at least the given number of INITIAL_SLOTS.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::create (size_t size)
> +{
> +  unsigned int size_prime_index;
> +
> +  size_prime_index = hash_table_higher_prime_index (size);
> +  size = prime_tab[size_prime_index].prime;
> +
> +  htab = Allocator <hash_table_control <Element> > ::control_alloc (1);
> +  gcc_assert (htab != NULL);
> +  htab->entries = Allocator <Element*> ::data_alloc (size);
> +  gcc_assert (htab->entries != NULL);
> +  htab->size = size;
> +  htab->size_prime_index = size_prime_index;
> +}
> +
> +
> +/* Dispose of a hash table.  Free all memory and return this hash table to
> +   the non-created state.  Naturally the hash table must already exist.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::dispose ()
> +{
> +  size_t size = htab->size;
> +  Element **entries = htab->entries;
> +
> +  for (int i = size - 1; i >= 0; i--)
> +    if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
> +      Remove (entries[i]);
> +
> +  Allocator <Element *> ::data_free (entries);
> +  Allocator <hash_table_control <Element> > ::control_free (htab);
> +  htab = NULL;
> +}
> +
> +
> +/* Similar to find_slot, but without several unwanted side effects:
> +    - Does not call Equal when it finds an existing entry.
> +    - Does not change the count of elements/searches/collisions in the
> +      hash table.
> +   This function also assumes there are no deleted entries in the table.
> +   HASH is the hash value for the element to be inserted.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +Element **
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_empty_slot_for_expand (hashval_t hash)
> +{
> +  hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
> +  size_t size = htab->size;
> +  Element **slot = htab->entries + index;
> +  hashval_t hash2;
> +
> +  if (*slot == HTAB_EMPTY_ENTRY)
> +    return slot;
> +  else if (*slot == HTAB_DELETED_ENTRY)
> +    abort ();
> +
> +  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> +  for (;;)
> +    {
> +      index += hash2;
> +      if (index >= size)
> +        index -= size;
> +
> +      slot = htab->entries + index;
> +      if (*slot == HTAB_EMPTY_ENTRY)
> +        return slot;
> +      else if (*slot == HTAB_DELETED_ENTRY)
> +        abort ();
> +    }
> +}
> +
> +
> +/* The following function changes size of memory allocated for the
> +   entries and repeatedly inserts the table elements.  The occupancy
> +   of the table after the call will be about 50%.  Naturally the hash
> +   table must already exist.  Remember also that the place of the
> +   table entries is changed.  If memory allocation fails, this function
> +   will abort.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::expand ()
> +{
> +  Element **oentries;
> +  Element **olimit;
> +  Element **p;
> +  Element **nentries;
> +  size_t nsize, osize, elts;
> +  unsigned int oindex, nindex;
> +
> +  oentries = htab->entries;
> +  oindex = htab->size_prime_index;
> +  osize = htab->size;
> +  olimit = oentries + osize;
> +  elts = elements ();
> +
> +  /* Resize only when table after removal of unused elements is either
> +     too full or too empty.  */
> +  if (elts * 2 > osize || (elts * 8 < osize && osize > 32))
> +    {
> +      nindex = hash_table_higher_prime_index (elts * 2);
> +      nsize = prime_tab[nindex].prime;
> +    }
> +  else
> +    {
> +      nindex = oindex;
> +      nsize = osize;
> +    }
> +
> +  nentries = Allocator <Element *> ::data_alloc (nsize);
> +  gcc_assert (nentries != NULL);
> +  htab->entries = nentries;
> +  htab->size = nsize;
> +  htab->size_prime_index = nindex;
> +  htab->n_elements -= htab->n_deleted;
> +  htab->n_deleted = 0;
> +
> +  p = oentries;
> +  do
> +    {
> +      Element *x = *p;
> +
> +      if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
> +        {
> +          Element **q = find_empty_slot_for_expand (Hash (x));
> +
> +          *q = x;
> +        }
> +
> +      p++;
> +    }
> +  while (p < olimit);
> +
> +  Allocator <Element *> ::data_free (oentries);
> +}
> +
> +
> +/* This function searches for a hash table entry equal to the given
> +   COMPARABLE element starting with the given HASH value.  It cannot
> +   be used to insert or delete an element. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +Element *
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_with_hash (Element *comparable, hashval_t hash)
> +{
> +  hashval_t index, hash2;
> +  size_t size;
> +  Element *entry;
> +
> +  htab->searches++;
> +  size = htab->size;
> +  index = hash_table_mod1 (hash, htab->size_prime_index);
> +
> +  entry = htab->entries[index];
> +  if (entry == HTAB_EMPTY_ENTRY
> +      || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
> +    return entry;
> +
> +  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> +  for (;;)
> +    {
> +      htab->collisions++;
> +      index += hash2;
> +      if (index >= size)
> +        index -= size;
> +
> +      entry = htab->entries[index];
> +      if (entry == HTAB_EMPTY_ENTRY
> +          || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
> +        return entry;
> +    }
> +}
> +
> +
> +/* This function searches for a hash table slot containing an entry
> +   equal to the given COMPARABLE element and starting with the given
> +   HASH.  To delete an entry, call this with insert=NO_INSERT, then
> +   call clear_slot on the slot returned (possibly after doing some
> +   checks).  To insert an entry, call this with insert=INSERT, then
> +   write the value you want into the returned slot.  When inserting an
> +   entry, NULL may be returned if memory allocation fails. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +Element **
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_slot_with_hash (Element *comparable, hashval_t hash,
> +		       enum insert_option insert)
> +{
> +  Element **first_deleted_slot;
> +  hashval_t index, hash2;
> +  size_t size;
> +  Element *entry;
> +
> +  size = htab->size;
> +  if (insert == INSERT && size * 3 <= htab->n_elements * 4)
> +    {
> +      expand ();
> +      size = htab->size;
> +    }
> +
> +  index = hash_table_mod1 (hash, htab->size_prime_index);
> +
> +  htab->searches++;
> +  first_deleted_slot = NULL;
> +
> +  entry = htab->entries[index];
> +  if (entry == HTAB_EMPTY_ENTRY)
> +    goto empty_entry;
> +  else if (entry == HTAB_DELETED_ENTRY)
> +    first_deleted_slot = &htab->entries[index];
> +  else if (Equal (entry, comparable))
> +    return &htab->entries[index];
> +      
> +  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> +  for (;;)
> +    {
> +      htab->collisions++;
> +      index += hash2;
> +      if (index >= size)
> +	index -= size;
> +      
> +      entry = htab->entries[index];
> +      if (entry == HTAB_EMPTY_ENTRY)
> +	goto empty_entry;
> +      else if (entry == HTAB_DELETED_ENTRY)
> +	{
> +	  if (!first_deleted_slot)
> +	    first_deleted_slot = &htab->entries[index];
> +	}
> +      else if (Equal (entry, comparable))
> +	return &htab->entries[index];
> +    }
> +
> + empty_entry:
> +  if (insert == NO_INSERT)
> +    return NULL;
> +
> +  if (first_deleted_slot)
> +    {
> +      htab->n_deleted--;
> +      *first_deleted_slot = static_cast <Element *> (HTAB_EMPTY_ENTRY);
> +      return first_deleted_slot;
> +    }
> +
> +  htab->n_elements++;
> +  return &htab->entries[index];
> +}
> +
> +
> +/* This function clears all entries in the given hash table.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::empty ()
> +{
> +  size_t size = htab_size (htab);
> +  Element **entries = htab->entries;
> +  int i;
> +
> +  for (i = size - 1; i >= 0; i--)
> +    if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
> +      Remove (entries[i]);
> +
> +  /* Instead of clearing megabyte, downsize the table.  */
> +  if (size > 1024*1024 / sizeof (PTR))
> +    {
> +      int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
> +      int nsize = prime_tab[nindex].prime;
> +
> +      Allocator <Element *> ::data_free (htab->entries);
> +      htab->entries = Allocator <Element *> ::data_alloc (nsize);
> +      htab->size = nsize;
> +      htab->size_prime_index = nindex;
> +    }
> +  else
> +    memset (entries, 0, size * sizeof (Element *));
> +  htab->n_deleted = 0;
> +  htab->n_elements = 0;
> +}
> +
> +
> +/* This function clears a specified SLOT in a hash table.  It is
> +   useful when you've already done the lookup and don't want to do it
> +   again. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::clear_slot (Element **slot)
> +{
> +  if (slot < htab->entries || slot >= htab->entries + htab->size
> +      || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
> +    abort ();
> +
> +  Remove (*slot);
> +
> +  *slot = HTAB_DELETED_ENTRY;
> +  htab->n_deleted++;
> +}
> +
> +
> +/* This function deletes an element with the given COMPARABLE value
> +   from hash table starting with the given HASH.  If there is no
> +   matching element in the hash table, this function does nothing. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::remove_elt_with_hash (Element *comparable, hashval_t hash)
> +{
> +  Element **slot;
> +
> +  slot = find_slot_with_hash (comparable, hash, NO_INSERT);
> +  if (*slot == HTAB_EMPTY_ENTRY)
> +    return;
> +
> +  Remove (*slot);
> +
> +  *slot = static_cast <Element *> (HTAB_DELETED_ENTRY);
> +  htab->n_deleted++;
> +}
> +
> +
> +/* This function scans over the entire hash table calling CALLBACK for
> +   each live entry.  If CALLBACK returns false, the iteration stops.
> +   ARGUMENT is passed as CALLBACK's second argument. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +template <typename Argument,
> +	  int (*Callback) (Element **slot, Argument argument)>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::traverse_noresize (Argument argument)
> +{
> +  Element **slot;
> +  Element **limit;
> +
> +  slot = htab->entries;
> +  limit = slot + htab->size;
> +
> +  do
> +    {
> +      Element *x = *slot;
> +
> +      if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
> +        if (! Callback (slot, argument))
> +          break;
> +    }
> +  while (++slot < limit);
> +}
> +
> +
> +/* Like traverse_noresize, but does resize the table when it is too empty
> +   to improve effectivity of subsequent calls.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +template <typename Argument,
> +	  int (*Callback) (Element **slot, Argument argument)>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::traverse (Argument argument)
> +{
> +  size_t size = htab->size;
> +  if (elements () * 8 < size && size > 32)
> +    expand ();
> +
> +  traverse_noresize <Argument, Callback> (argument);
> +}
> +
> +#endif /* TYPED_HASHTAB_H */
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-12 20:14 Merge C++ conversion into trunk (4/6 - hash table rewrite) Diego Novillo
  2012-08-15 10:59 ` Richard Guenther
@ 2012-08-15 13:00 ` Richard Guenther
  2012-08-15 13:41   ` Richard Guenther
  2012-08-15 21:52   ` Lawrence Crowl
  1 sibling, 2 replies; 29+ messages in thread
From: Richard Guenther @ 2012-08-15 13:00 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches, Richard Henderson, crowl

On Sun, 12 Aug 2012, Diego Novillo wrote:

> This implements a new C++ hash table.
> 
> See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for
> details.
> 
> Diego.

Now as we see the result I'd have prefered a more C++-way instead
of making the conversion simple ...

Like

template <typename Element>
class hash_table
{
...
};

template <typename Element>
class pointer_hash
{
  hashval_t hash ();
  int equal (const Element *);
  ~Element ();
  Element e;
};

and

/* Hash table with all same_succ entries.  */

static hash_table <pointer_hash <struct same_succ_def> > same_succ_htab;

The existing way is simply too ugly ... so, why did you not invent
a "nice" C++ way?  (please consider reverting the hashtable patch)

Thanks,
Richard.


> 
> 2012-08-12   Lawrence Crowl  <crowl@google.com>
> 
> 	* hash-table.h: New. Implementation borrowed from libiberty/hashtab.c.
> 	* hash-table.c: Likewise.
> 	* tree-ssa-tail-merge.c: Include hash-table.h instead of hashtab.h.
> 	(static htab_t same_succ_htab): Change type to hash_table;
> 	move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(same_succ_print_traverse): Make extern ssa_.... Change callers.
> 	Remove void* casting.
> 	(same_succ_hash): Likewise.
> 	(same_succ_equal): Likewise.
> 	(same_succ_delete): Likewise.
> 	* tree-ssa-threadupdate.c: Include hash-table.h.
> 	(struct local_info): Rename to ssa_local_info_t to avoid overloading
> 	the type name local_info with the variable name local_info.
> 	(static htab_t redirection_data): Change type to hash_table.
> 	Move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(redirection_data_hash): Make extern ssa_.... Change callers.
> 	Remove void* casting.
> 	(redirection_data_eq): Likewise.
> 	(fix_duplicate_block_edges): Likewise.
> 	(create_duplicates): Likewise.
> 	(fixup_template_block): Likewise.
> 	(redirect_edges): Likewise.
> 	(lookup_redirection_data): Change types associated with the hash table
> 	from void* to their actual type. Remove unnecessary casts.
> 	* tree-ssa-ccp.c: Include hash-table.h.
> 	(typedef gimple_htab): New.  Uses hash_table.  Replace specific uses
> 	of htab_t with gimple_htab.  Change users to invoke member functions.
> 	Move specification of helper functions from create call to declaration.
> 	* tree-ssa-coalesce.c: Include hash-table.h instead of hashtab.h.
> 	(hash_ssa_name_by_var): Make extern. Remove void* casting.
> 	(eq_ssa_name_by_var): Likewise.
> 	(coalesce_ssa_name): Change type of local static htab_t ssa_name_hash
> 	to hash_table. Change users to invoke member functions.
> 	Move specification of helper functions from create call to declaration.
> 	* coverage.c: Include hash-table.h instead of hashtab.h.
> 	(static htab_t counts_hash): Change type to hash_table;
> 	move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(htab_counts_entry_hash): Make extern. Rename with coverage_... instead
> 	of htab_... Remove void* casting.
> 	(htab_counts_entry_eq): Likewise.
> 	(htab_counts_entry_del): Likewise.
> 	* tree-ssa-pre.c: Include hash-table.h instead of hashtab.h.
> 	(static htab_t expression_to_id): Change type to hash_table.
> 	Move specification of helper functions from create call to declaration.
> 	Change users to invoke member functions.
> 	(static htab_t phi_translate_table): Likewise.
> 	(pre_expr_eq): Make extern ssa_.... Change callers.
> 	Remove void* casting.
> 	(pre_expr_hash): Likewise.
> 	(expr_pred_trans_hash): Likewise.
> 	(expr_pred_trans_eq): Likewise.
> 	(alloc_expression_id): Change types associated with the hash table
> 	from void* to their actual type. Remove unnecessary casts.
> 	(lookup_expression_id): Likewise.
> 	(phi_trans_lookup): Likewise.
> 	(phi_trans_add): Likewise.
> 	* stringpool.c: Rename uses of libcpp typedef hash_table to
> 	cpp_hash_table.
> 	* Makefile.in: Add hash-table.o to OBJS-libcommon-target.
> 	Add $(HASH_TABLE_H). Add new dependences on $(HASH_TABLE_H).
> 
> diff --git a/gcc/coverage.c b/gcc/coverage.c
> index af52289..3fea525 100644
> --- a/gcc/coverage.c
> +++ b/gcc/coverage.c
> @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "ggc.h"
>  #include "coverage.h"
>  #include "langhooks.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "tree-iterator.h"
>  #include "cgraph.h"
>  #include "dumpfile.h"
> @@ -109,17 +109,11 @@ static unsigned bbg_file_stamp;
>  /* Name of the count data (gcda) file.  */
>  static char *da_file_name;
>  
> -/* Hash table of count data.  */
> -static htab_t counts_hash = NULL;
> -
>  /* The names of merge functions for counters.  */
>  static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
>  static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
>  
>  /* Forward declarations.  */
> -static hashval_t htab_counts_entry_hash (const void *);
> -static int htab_counts_entry_eq (const void *, const void *);
> -static void htab_counts_entry_del (void *);
>  static void read_counts_file (void);
>  static tree build_var (tree, tree, int);
>  static void build_fn_info_type (tree, unsigned, tree);
> @@ -149,32 +143,31 @@ get_gcov_unsigned_t (void)
>    return lang_hooks.types.type_for_mode (mode, true);
>  }
>  \f
> -static hashval_t
> -htab_counts_entry_hash (const void *of)
> +inline hashval_t
> +coverage_counts_entry_hash (const counts_entry_t *entry)
>  {
> -  const counts_entry_t *const entry = (const counts_entry_t *) of;
> -
>    return entry->ident * GCOV_COUNTERS + entry->ctr;
>  }
>  
> -static int
> -htab_counts_entry_eq (const void *of1, const void *of2)
> +inline int
> +coverage_counts_entry_eq (const counts_entry_t *entry1,
> +                          const counts_entry_t *entry2)
>  {
> -  const counts_entry_t *const entry1 = (const counts_entry_t *) of1;
> -  const counts_entry_t *const entry2 = (const counts_entry_t *) of2;
> -
>    return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
>  }
>  
> -static void
> -htab_counts_entry_del (void *of)
> +inline void
> +coverage_counts_entry_del (counts_entry_t *entry)
>  {
> -  counts_entry_t *const entry = (counts_entry_t *) of;
> -
>    free (entry->counts);
>    free (entry);
>  }
>  
> +/* Hash table of count data.  */
> +static hash_table <counts_entry_t, coverage_counts_entry_hash,
> +		   coverage_counts_entry_eq, coverage_counts_entry_del>
> +		  counts_hash;
> +
>  /* Read in the counts file, if available.  */
>  
>  static void
> @@ -214,9 +207,7 @@ read_counts_file (void)
>    tag = gcov_read_unsigned ();
>    bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
>  
> -  counts_hash = htab_create (10,
> -			     htab_counts_entry_hash, htab_counts_entry_eq,
> -			     htab_counts_entry_del);
> +  counts_hash.create (10);
>    while ((tag = gcov_read_unsigned ()))
>      {
>        gcov_unsigned_t length;
> @@ -264,8 +255,7 @@ read_counts_file (void)
>  	  elt.ident = fn_ident;
>  	  elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
>  
> -	  slot = (counts_entry_t **) htab_find_slot
> -	    (counts_hash, &elt, INSERT);
> +	  slot = counts_hash.find_slot (&elt, INSERT);
>  	  entry = *slot;
>  	  if (!entry)
>  	    {
> @@ -285,14 +275,14 @@ read_counts_file (void)
>  	      error ("checksum is (%x,%x) instead of (%x,%x)",
>  		     entry->lineno_checksum, entry->cfg_checksum,
>  		     lineno_checksum, cfg_checksum);
> -	      htab_delete (counts_hash);
> +	      counts_hash.dispose ();
>  	      break;
>  	    }
>  	  else if (entry->summary.num != n_counts)
>  	    {
>  	      error ("Profile data for function %u is corrupted", fn_ident);
>  	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
> -	      htab_delete (counts_hash);
> +	      counts_hash.dispose ();
>  	      break;
>  	    }
>  	  else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
> @@ -318,7 +308,7 @@ read_counts_file (void)
>  	{
>  	  error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted",
>  		 da_file_name);
> -	  htab_delete (counts_hash);
> +	  counts_hash.dispose ();
>  	  break;
>  	}
>      }
> @@ -336,7 +326,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
>    counts_entry_t *entry, elt;
>  
>    /* No hash table, no counts.  */
> -  if (!counts_hash)
> +  if (!counts_hash.is_created ())
>      {
>        static int warned = 0;
>  
> @@ -350,7 +340,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
>  
>    elt.ident = current_function_funcdef_no + 1;
>    elt.ctr = counter;
> -  entry = (counts_entry_t *) htab_find (counts_hash, &elt);
> +  entry = counts_hash.find (&elt);
>    if (!entry || !entry->summary.num)
>      /* The function was not emitted, or is weak and not chosen in the
>         final executable.  Silently fail, because there's nothing we
> diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
> index 9b186dd..9f602e9 100644
> --- a/gcc/tree-ssa-pre.c
> +++ b/gcc/tree-ssa-pre.c
> @@ -30,7 +30,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-inline.h"
>  #include "tree-flow.h"
>  #include "gimple.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "tree-iterator.h"
>  #include "alloc-pool.h"
>  #include "obstack.h"
> @@ -177,12 +177,11 @@ typedef struct pre_expr_d
>  #define PRE_EXPR_REFERENCE(e) (e)->u.reference
>  #define PRE_EXPR_CONSTANT(e) (e)->u.constant
>  
> -static int
> -pre_expr_eq (const void *p1, const void *p2)
> -{
> -  const struct pre_expr_d *e1 = (const struct pre_expr_d *) p1;
> -  const struct pre_expr_d *e2 = (const struct pre_expr_d *) p2;
> +/* Compare E1 and E1 for equality.  */
>  
> +inline int
> +ssa_pre_expr_eq (const struct pre_expr_d *e1, const struct pre_expr_d *e2)
> +{
>    if (e1->kind != e2->kind)
>      return false;
>  
> @@ -203,10 +202,11 @@ pre_expr_eq (const void *p1, const void *p2)
>      }
>  }
>  
> -static hashval_t
> -pre_expr_hash (const void *p1)
> +/* Hash E.  */
> +
> +inline hashval_t
> +ssa_pre_expr_hash (const struct pre_expr_d *e)
>  {
> -  const struct pre_expr_d *e = (const struct pre_expr_d *) p1;
>    switch (e->kind)
>      {
>      case CONSTANT:
> @@ -222,7 +222,6 @@ pre_expr_hash (const void *p1)
>      }
>  }
>  
> -
>  /* Next global expression id number.  */
>  static unsigned int next_expression_id;
>  
> @@ -230,7 +229,9 @@ static unsigned int next_expression_id;
>  DEF_VEC_P (pre_expr);
>  DEF_VEC_ALLOC_P (pre_expr, heap);
>  static VEC(pre_expr, heap) *expressions;
> -static htab_t expression_to_id;
> +static hash_table <pre_expr_d, ssa_pre_expr_hash, ssa_pre_expr_eq,
> +		   typed_null_remove <pre_expr_d> >
> +		  expression_to_id;
>  static VEC(unsigned, heap) *name_to_id;
>  
>  /* Allocate an expression id for EXPR.  */
> @@ -238,7 +239,7 @@ static VEC(unsigned, heap) *name_to_id;
>  static inline unsigned int
>  alloc_expression_id (pre_expr expr)
>  {
> -  void **slot;
> +  struct pre_expr_d **slot;
>    /* Make sure we won't overflow. */
>    gcc_assert (next_expression_id + 1 > next_expression_id);
>    expr->id = next_expression_id++;
> @@ -257,7 +258,7 @@ alloc_expression_id (pre_expr expr)
>      }
>    else
>      {
> -      slot = htab_find_slot (expression_to_id, expr, INSERT);
> +      slot = expression_to_id.find_slot (expr, INSERT);
>        gcc_assert (!*slot);
>        *slot = expr;
>      }
> @@ -275,7 +276,7 @@ get_expression_id (const pre_expr expr)
>  static inline unsigned int
>  lookup_expression_id (const pre_expr expr)
>  {
> -  void **slot;
> +  struct pre_expr_d **slot;
>  
>    if (expr->kind == NAME)
>      {
> @@ -286,7 +287,7 @@ lookup_expression_id (const pre_expr expr)
>      }
>    else
>      {
> -      slot = htab_find_slot (expression_to_id, expr, NO_INSERT);
> +      slot = expression_to_id.find_slot (expr, NO_INSERT);
>        if (!slot)
>  	return 0;
>        return ((pre_expr)*slot)->id;
> @@ -479,11 +480,6 @@ static bitmap need_eh_cleanup;
>  /* Set of blocks with statements that have had their AB properties changed.  */
>  static bitmap need_ab_cleanup;
>  
> -/* The phi_translate_table caches phi translations for a given
> -   expression and predecessor.  */
> -
> -static htab_t phi_translate_table;
> -
>  /* A three tuple {e, pred, v} used to cache phi translations in the
>     phi_translate_table.  */
>  
> @@ -506,21 +502,19 @@ typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
>  
>  /* Return the hash value for a phi translation table entry.  */
>  
> -static hashval_t
> -expr_pred_trans_hash (const void *p)
> +inline hashval_t
> +ssa_expr_pred_trans_hash (const expr_pred_trans_d *ve)
>  {
> -  const_expr_pred_trans_t const ve = (const_expr_pred_trans_t) p;
>    return ve->hashcode;
>  }
>  
>  /* Return true if two phi translation table entries are the same.
>     P1 and P2 should point to the expr_pred_trans_t's to be compared.*/
>  
> -static int
> -expr_pred_trans_eq (const void *p1, const void *p2)
> +inline int
> +ssa_expr_pred_trans_eq (const expr_pred_trans_d *ve1,
> +			const expr_pred_trans_d *ve2)
>  {
> -  const_expr_pred_trans_t const ve1 = (const_expr_pred_trans_t) p1;
> -  const_expr_pred_trans_t const ve2 = (const_expr_pred_trans_t) p2;
>    basic_block b1 = ve1->pred;
>    basic_block b2 = ve2->pred;
>  
> @@ -528,9 +522,17 @@ expr_pred_trans_eq (const void *p1, const void *p2)
>       be equal.  */
>    if (b1 != b2)
>      return false;
> -  return pre_expr_eq (ve1->e, ve2->e);
> +  return ssa_pre_expr_eq (ve1->e, ve2->e);
>  }
>  
> +/* The phi_translate_table caches phi translations for a given
> +   expression and predecessor.  */
> +
> +static hash_table <expr_pred_trans_d, ssa_expr_pred_trans_hash,
> +		   ssa_expr_pred_trans_eq,
> +		   typed_free_remove <expr_pred_trans_d> >
> +		  phi_translate_table;
> +
>  /* Search in the phi translation table for the translation of
>     expression E in basic block PRED.
>     Return the translated value, if found, NULL otherwise.  */
> @@ -538,18 +540,18 @@ expr_pred_trans_eq (const void *p1, const void *p2)
>  static inline pre_expr
>  phi_trans_lookup (pre_expr e, basic_block pred)
>  {
> -  void **slot;
> +  expr_pred_trans_t *slot;
>    struct expr_pred_trans_d ept;
>  
>    ept.e = e;
>    ept.pred = pred;
> -  ept.hashcode = iterative_hash_hashval_t (pre_expr_hash (e), pred->index);
> -  slot = htab_find_slot_with_hash (phi_translate_table, &ept, ept.hashcode,
> +  ept.hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e), pred->index);
> +  slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode,
>  				   NO_INSERT);
>    if (!slot)
>      return NULL;
>    else
> -    return ((expr_pred_trans_t) *slot)->v;
> +    return (*slot)->v;
>  }
>  
>  
> @@ -559,18 +561,18 @@ phi_trans_lookup (pre_expr e, basic_block pred)
>  static inline void
>  phi_trans_add (pre_expr e, pre_expr v, basic_block pred)
>  {
> -  void **slot;
> +  expr_pred_trans_t *slot;
>    expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d);
>    new_pair->e = e;
>    new_pair->pred = pred;
>    new_pair->v = v;
> -  new_pair->hashcode = iterative_hash_hashval_t (pre_expr_hash (e),
> +  new_pair->hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e),
>  						 pred->index);
>  
> -  slot = htab_find_slot_with_hash (phi_translate_table, new_pair,
> +  slot = phi_translate_table.find_slot_with_hash (new_pair,
>  				   new_pair->hashcode, INSERT);
>    free (*slot);
> -  *slot = (void *) new_pair;
> +  *slot = new_pair;
>  }
>  
>  
> @@ -1607,12 +1609,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
>  		if (double_int_fits_in_shwi_p (off))
>  		  newop.off = off.low;
>  	      }
> -	    VEC_replace (vn_reference_op_s, newoperands, j, &newop);
> +	    VEC_replace (vn_reference_op_s, newoperands, j, newop);
>  	    /* If it transforms from an SSA_NAME to an address, fold with
>  	       a preceding indirect reference.  */
>  	    if (j > 0 && op[0] && TREE_CODE (op[0]) == ADDR_EXPR
>  		&& VEC_index (vn_reference_op_s,
> -			      newoperands, j - 1)->opcode == MEM_REF)
> +			      newoperands, j - 1).opcode == MEM_REF)
>  	      vn_reference_fold_indirect (&newoperands, &j);
>  	  }
>  	if (i != VEC_length (vn_reference_op_s, operands))
> @@ -2596,8 +2598,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
>  				  unsigned int *operand, gimple_seq *stmts,
>  				  gimple domstmt)
>  {
> -  vn_reference_op_t currop = VEC_index (vn_reference_op_s, ref->operands,
> -					*operand);
> +  vn_reference_op_t currop = &VEC_index (vn_reference_op_s, ref->operands,
> +					 *operand);
>    tree genop;
>    ++*operand;
>    switch (currop->opcode)
> @@ -2674,8 +2676,8 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
>        {
>  	pre_expr op0expr, op1expr;
>  	tree genop0 = NULL_TREE, genop1 = NULL_TREE;
> -	vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands,
> -					      ++*operand);
> +	vn_reference_op_t nextop = &VEC_index (vn_reference_op_s, ref->operands,
> +					       ++*operand);
>  	tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
>  							stmts, domstmt);
>  	if (!baseop)
> @@ -3488,7 +3490,7 @@ do_regular_insertion (basic_block block, basic_block dom)
>  		    do_insertion = true;
>  		  if (first_s == NULL)
>  		    first_s = edoubleprime;
> -		  else if (!pre_expr_eq (first_s, edoubleprime))
> +		  else if (!ssa_pre_expr_eq (first_s, edoubleprime))
>  		    all_same = false;
>  		}
>  	    }
> @@ -4767,7 +4769,7 @@ init_pre (bool do_fre)
>  
>    next_expression_id = 1;
>    expressions = NULL;
> -  VEC_safe_push (pre_expr, heap, expressions, NULL);
> +  VEC_safe_push (pre_expr, heap, expressions, (pre_expr)NULL);
>    value_expressions = VEC_alloc (bitmap_set_t, heap, get_max_value_id () + 1);
>    VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
>  			 get_max_value_id() + 1);
> @@ -4790,11 +4792,8 @@ init_pre (bool do_fre)
>    calculate_dominance_info (CDI_DOMINATORS);
>  
>    bitmap_obstack_initialize (&grand_bitmap_obstack);
> -  phi_translate_table = htab_create (5110, expr_pred_trans_hash,
> -				     expr_pred_trans_eq, free);
> -  expression_to_id = htab_create (num_ssa_names * 3,
> -				  pre_expr_hash,
> -				  pre_expr_eq, NULL);
> +  phi_translate_table.create (5110);
> +  expression_to_id.create (num_ssa_names * 3);
>    bitmap_set_pool = create_alloc_pool ("Bitmap sets",
>  				       sizeof (struct bitmap_set), 30);
>    pre_expr_pool = create_alloc_pool ("pre_expr nodes",
> @@ -4826,8 +4825,8 @@ fini_pre (bool do_fre)
>    bitmap_obstack_release (&grand_bitmap_obstack);
>    free_alloc_pool (bitmap_set_pool);
>    free_alloc_pool (pre_expr_pool);
> -  htab_delete (phi_translate_table);
> -  htab_delete (expression_to_id);
> +  phi_translate_table.dispose ();
> +  expression_to_id.dispose ();
>    VEC_free (unsigned, heap, name_to_id);
>  
>    free_aux_for_blocks ();
> diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
> index a2d4633..57d9f99 100644
> --- a/gcc/tree-ssa-tail-merge.c
> +++ b/gcc/tree-ssa-tail-merge.c
> @@ -193,7 +193,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "bitmap.h"
>  #include "tree-ssa-alias.h"
>  #include "params.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "gimple-pretty-print.h"
>  #include "tree-ssa-sccvn.h"
>  #include "tree-dump.h"
> @@ -368,11 +368,10 @@ same_succ_print (FILE *file, const same_succ e)
>  
>  /* Prints same_succ VE to VFILE.  */
>  
> -static int
> -same_succ_print_traverse (void **ve, void *vfile)
> +inline int
> +ssa_same_succ_print_traverse (same_succ *pe, FILE *file)
>  {
> -  const same_succ e = *((const same_succ *)ve);
> -  FILE *file = ((FILE*)vfile);
> +  const same_succ e = *pe;
>    same_succ_print (file, e);
>    return 1;
>  }
> @@ -416,10 +415,9 @@ stmt_update_dep_bb (gimple stmt)
>  
>  /* Calculates hash value for same_succ VE.  */
>  
> -static hashval_t
> -same_succ_hash (const void *ve)
> +hashval_t
> +ssa_same_succ_hash (const_same_succ e)
>  {
> -  const_same_succ e = (const_same_succ)ve;
>    hashval_t hashval = bitmap_hash (e->succs);
>    int flags;
>    unsigned int i;
> @@ -515,11 +513,9 @@ inverse_flags (const_same_succ e1, const_same_succ e2)
>  
>  /* Compares SAME_SUCCs VE1 and VE2.  */
>  
> -static int
> -same_succ_equal (const void *ve1, const void *ve2)
> +int
> +ssa_same_succ_equal (const_same_succ e1, const_same_succ e2)
>  {
> -  const_same_succ e1 = (const_same_succ)ve1;
> -  const_same_succ e2 = (const_same_succ)ve2;
>    unsigned int i, first1, first2;
>    gimple_stmt_iterator gsi1, gsi2;
>    gimple s1, s2;
> @@ -590,17 +586,15 @@ same_succ_alloc (void)
>  
>  /* Delete same_succ VE.  */
>  
> -static void
> -same_succ_delete (void *ve)
> +inline void
> +ssa_same_succ_delete (same_succ e)
>  {
> -  same_succ e = (same_succ)ve;
> -
>    BITMAP_FREE (e->bbs);
>    BITMAP_FREE (e->succs);
>    BITMAP_FREE (e->inverse);
>    VEC_free (int, heap, e->succ_flags);
>  
> -  XDELETE (ve);
> +  XDELETE (e);
>  }
>  
>  /* Reset same_succ SAME.  */
> @@ -616,7 +610,9 @@ same_succ_reset (same_succ same)
>  
>  /* Hash table with all same_succ entries.  */
>  
> -static htab_t same_succ_htab;
> +static hash_table <struct same_succ_def, ssa_same_succ_hash,
> +		   ssa_same_succ_equal, ssa_same_succ_delete>
> +		  same_succ_htab;
>  
>  /* Array that is used to store the edge flags for a successor.  */
>  
> @@ -637,7 +633,7 @@ extern void debug_same_succ (void);
>  DEBUG_FUNCTION void
>  debug_same_succ ( void)
>  {
> -  htab_traverse (same_succ_htab, same_succ_print_traverse, stderr);
> +  same_succ_htab.traverse <FILE *, ssa_same_succ_print_traverse> (stderr);
>  }
>  
>  DEF_VEC_P (same_succ);
> @@ -696,10 +692,9 @@ find_same_succ_bb (basic_block bb, same_succ *same_p)
>    EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
>      VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
>  
> -  same->hashval = same_succ_hash (same);
> +  same->hashval = ssa_same_succ_hash (same);
>  
> -  slot = (same_succ *) htab_find_slot_with_hash (same_succ_htab, same,
> -						   same->hashval, INSERT);
> +  slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
>    if (*slot == NULL)
>      {
>        *slot = same;
> @@ -733,7 +728,7 @@ find_same_succ (void)
>  	same = same_succ_alloc ();
>      }
>  
> -  same_succ_delete (same);
> +  ssa_same_succ_delete (same);
>  }
>  
>  /* Initializes worklist administration.  */
> @@ -742,9 +737,7 @@ static void
>  init_worklist (void)
>  {
>    alloc_aux_for_blocks (sizeof (struct aux_bb_info));
> -  same_succ_htab
> -    = htab_create (n_basic_blocks, same_succ_hash, same_succ_equal,
> -		   same_succ_delete);
> +  same_succ_htab.create (n_basic_blocks);
>    same_succ_edge_flags = XCNEWVEC (int, last_basic_block);
>    deleted_bbs = BITMAP_ALLOC (NULL);
>    deleted_bb_preds = BITMAP_ALLOC (NULL);
> @@ -764,8 +757,7 @@ static void
>  delete_worklist (void)
>  {
>    free_aux_for_blocks ();
> -  htab_delete (same_succ_htab);
> -  same_succ_htab = NULL;
> +  same_succ_htab.dispose ();
>    XDELETEVEC (same_succ_edge_flags);
>    same_succ_edge_flags = NULL;
>    BITMAP_FREE (deleted_bbs);
> @@ -795,7 +787,7 @@ same_succ_flush_bb (basic_block bb)
>    same_succ same = BB_SAME_SUCC (bb);
>    BB_SAME_SUCC (bb) = NULL;
>    if (bitmap_single_bit_set_p (same->bbs))
> -    htab_remove_elt_with_hash (same_succ_htab, same, same->hashval);
> +    same_succ_htab.remove_elt_with_hash (same, same->hashval);
>    else
>      bitmap_clear_bit (same->bbs, bb->index);
>  }
> @@ -868,7 +860,7 @@ update_worklist (void)
>        if (same == NULL)
>  	same = same_succ_alloc ();
>      }
> -  same_succ_delete (same);
> +  ssa_same_succ_delete (same);
>    bitmap_clear (deleted_bb_preds);
>  }
>  
> @@ -1637,7 +1629,7 @@ tail_merge_optimize (unsigned int todo)
>  
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      fprintf (dump_file, "htab collision / search: %f\n",
> -	     htab_collisions (same_succ_htab));
> +	     same_succ_htab.collisions ());
>  
>    if (nr_bbs_removed_total > 0)
>      {
> diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
> index a0536db..3ecb303 100644
> --- a/gcc/tree-ssa-threadupdate.c
> +++ b/gcc/tree-ssa-threadupdate.c
> @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "tree-flow.h"
>  #include "dumpfile.h"
>  #include "cfgloop.h"
> +#include "hash-table.h"
>  
>  /* Given a block B, update the CFG and SSA graph to reflect redirecting
>     one or more in-edges to B to instead reach the destination of an
> @@ -126,11 +127,8 @@ struct redirection_data
>    struct el *incoming_edges;
>  };
>  
> -/* Main data structure to hold information for duplicates of BB.  */
> -static htab_t redirection_data;
> -
>  /* Data structure of information to pass to hash table traversal routines.  */
> -struct local_info
> +struct ssa_local_info_t
>  {
>    /* The current block we are working on.  */
>    basic_block bb;
> @@ -220,24 +218,32 @@ create_block_for_threading (basic_block bb, struct redirection_data *rd)
>  }
>  
>  /* Hashing and equality routines for our hash table.  */
> -static hashval_t
> -redirection_data_hash (const void *p)
> +inline hashval_t
> +ssa_redirection_data_hash (const struct redirection_data *p)
>  {
> -  edge e = ((const struct redirection_data *)p)->outgoing_edge;
> +  edge e = p->outgoing_edge;
>    return e->dest->index;
>  }
>  
> -static int
> -redirection_data_eq (const void *p1, const void *p2)
> +inline int
> +ssa_redirection_data_eq (const struct redirection_data *p1,
> +			 const struct redirection_data *p2)
>  {
> -  edge e1 = ((const struct redirection_data *)p1)->outgoing_edge;
> -  edge e2 = ((const struct redirection_data *)p2)->outgoing_edge;
> -  edge e3 = ((const struct redirection_data *)p1)->intermediate_edge;
> -  edge e4 = ((const struct redirection_data *)p2)->intermediate_edge;
> +  edge e1 = p1->outgoing_edge;
> +  edge e2 = p2->outgoing_edge;
> +  edge e3 = p1->intermediate_edge;
> +  edge e4 = p2->intermediate_edge;
>  
>    return e1 == e2 && e3 == e4;
>  }
>  
> +/* Main data structure to hold information for duplicates of BB.  */
> +
> +static hash_table <struct redirection_data, ssa_redirection_data_hash,
> +		   ssa_redirection_data_eq,
> +		   typed_free_remove<struct redirection_data> >
> +		  redirection_data;
> +
>  /* Given an outgoing edge E lookup and return its entry in our hash table.
>  
>     If INSERT is true, then we insert the entry into the hash table if
> @@ -247,7 +253,7 @@ redirection_data_eq (const void *p1, const void *p2)
>  static struct redirection_data *
>  lookup_redirection_data (edge e, enum insert_option insert)
>  {
> -  void **slot;
> +  struct redirection_data **slot;
>    struct redirection_data *elt;
>  
>   /* Build a hash table element so we can see if E is already
> @@ -259,7 +265,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
>    elt->dup_block = NULL;
>    elt->incoming_edges = NULL;
>  
> -  slot = htab_find_slot (redirection_data, elt, insert);
> +  slot = redirection_data.find_slot (elt, insert);
>  
>    /* This will only happen if INSERT is false and the entry is not
>       in the hash table.  */
> @@ -273,7 +279,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
>       INSERT is true.  */
>    if (*slot == NULL)
>      {
> -      *slot = (void *)elt;
> +      *slot = elt;
>        elt->incoming_edges = XNEW (struct el);
>        elt->incoming_edges->e = e;
>        elt->incoming_edges->next = NULL;
> @@ -287,7 +293,7 @@ lookup_redirection_data (edge e, enum insert_option insert)
>        free (elt);
>  
>        /* Get the entry stored in the hash table.  */
> -      elt = (struct redirection_data *) *slot;
> +      elt = *slot;
>  
>        /* If insertion was requested, then we need to add INCOMING_EDGE
>  	 to the list of incoming edges associated with E.  */
> @@ -375,9 +381,9 @@ create_edge_and_update_destination_phis (struct redirection_data *rd,
>  
>  /* Wire up the outgoing edges from the duplicate block and
>     update any PHIs as needed.  */
> -static void
> -fix_duplicate_block_edges (struct redirection_data *rd,
> -			   struct local_info *local_info)
> +void
> +ssa_fix_duplicate_block_edges (struct redirection_data *rd,
> +			       ssa_local_info_t *local_info)
>  {
>    /* If we were threading through an joiner block, then we want
>       to keep its control statement and redirect an outgoing edge.
> @@ -412,11 +418,11 @@ fix_duplicate_block_edges (struct redirection_data *rd,
>  }
>  /* Hash table traversal callback routine to create duplicate blocks.  */
>  
> -static int
> -create_duplicates (void **slot, void *data)
> +int
> +ssa_create_duplicates (struct redirection_data **slot,
> +		       ssa_local_info_t *local_info)
>  {
> -  struct redirection_data *rd = (struct redirection_data *) *slot;
> -  struct local_info *local_info = (struct local_info *)data;
> +  struct redirection_data *rd = *slot;
>  
>    /* Create a template block if we have not done so already.  Otherwise
>       use the template to create a new block.  */
> @@ -435,7 +441,7 @@ create_duplicates (void **slot, void *data)
>  
>        /* Go ahead and wire up outgoing edges and update PHIs for the duplicate
>  	 block.   */
> -      fix_duplicate_block_edges (rd, local_info);
> +      ssa_fix_duplicate_block_edges (rd, local_info);
>      }
>  
>    /* Keep walking the hash table.  */
> @@ -446,11 +452,11 @@ create_duplicates (void **slot, void *data)
>     block creation.  This hash table traversal callback creates the
>     outgoing edge for the template block.  */
>  
> -static int
> -fixup_template_block (void **slot, void *data)
> +inline int
> +ssa_fixup_template_block (struct redirection_data **slot,
> +			  ssa_local_info_t *local_info)
>  {
> -  struct redirection_data *rd = (struct redirection_data *) *slot;
> -  struct local_info *local_info = (struct local_info *)data;
> +  struct redirection_data *rd = *slot;
>  
>    /* If this is the template block halt the traversal after updating
>       it appropriately.
> @@ -461,7 +467,7 @@ fixup_template_block (void **slot, void *data)
>       a new outgoing edge.  In both cases we may need to update PHIs.  */
>    if (rd->dup_block && rd->dup_block == local_info->template_block)
>      {
> -      fix_duplicate_block_edges (rd, local_info);
> +      ssa_fix_duplicate_block_edges (rd, local_info);
>        return 0;
>      }
>  
> @@ -471,11 +477,11 @@ fixup_template_block (void **slot, void *data)
>  /* Hash table traversal callback to redirect each incoming edge
>     associated with this hash table element to its new destination.  */
>  
> -static int
> -redirect_edges (void **slot, void *data)
> +int
> +ssa_redirect_edges (struct redirection_data **slot,
> +		    ssa_local_info_t *local_info)
>  {
> -  struct redirection_data *rd = (struct redirection_data *) *slot;
> -  struct local_info *local_info = (struct local_info *)data;
> +  struct redirection_data *rd = *slot;
>    struct el *next, *el;
>  
>    /* Walk over all the incoming edges associated associated with this
> @@ -594,17 +600,14 @@ thread_block (basic_block bb, bool noloop_only)
>       redirect to a duplicate of BB.  */
>    edge e, e2;
>    edge_iterator ei;
> -  struct local_info local_info;
> +  ssa_local_info_t local_info;
>    struct loop *loop = bb->loop_father;
>  
>    /* To avoid scanning a linear array for the element we need we instead
>       use a hash table.  For normal code there should be no noticeable
>       difference.  However, if we have a block with a large number of
>       incoming and outgoing edges such linear searches can get expensive.  */
> -  redirection_data = htab_create (EDGE_COUNT (bb->succs),
> -				  redirection_data_hash,
> -				  redirection_data_eq,
> -				  free);
> +  redirection_data.create (EDGE_COUNT (bb->succs));
>  
>    /* If we thread the latch of the loop to its exit, the loop ceases to
>       exist.  Make sure we do not restrict ourselves in order to preserve
> @@ -678,24 +681,26 @@ thread_block (basic_block bb, bool noloop_only)
>    local_info.template_block = NULL;
>    local_info.bb = bb;
>    local_info.jumps_threaded = false;
> -  htab_traverse (redirection_data, create_duplicates, &local_info);
> +  redirection_data.traverse <ssa_local_info_t *, ssa_create_duplicates>
> +			    (&local_info);
>  
>    /* The template does not have an outgoing edge.  Create that outgoing
>       edge and update PHI nodes as the edge's target as necessary.
>  
>       We do this after creating all the duplicates to avoid creating
>       unnecessary edges.  */
> -  htab_traverse (redirection_data, fixup_template_block, &local_info);
> +  redirection_data.traverse <ssa_local_info_t *, ssa_fixup_template_block>
> +			    (&local_info);
>  
>    /* The hash table traversals above created the duplicate blocks (and the
>       statements within the duplicate blocks).  This loop creates PHI nodes for
>       the duplicated blocks and redirects the incoming edges into BB to reach
>       the duplicates of BB.  */
> -  htab_traverse (redirection_data, redirect_edges, &local_info);
> +  redirection_data.traverse <ssa_local_info_t *, ssa_redirect_edges>
> +			    (&local_info);
>  
>    /* Done with this block.  Clear REDIRECTION_DATA.  */
> -  htab_delete (redirection_data);
> -  redirection_data = NULL;
> +  redirection_data.dispose ();
>  
>    if (noloop_only
>        && bb == bb->loop_father->header)
> diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c
> index 8244f0c..d0973f4 100644
> --- a/libcpp/identifiers.c
> +++ b/libcpp/identifiers.c
> @@ -28,12 +28,12 @@ along with this program; see the file COPYING3.  If not see
>  #include "cpplib.h"
>  #include "internal.h"
>  
> -static hashnode alloc_node (hash_table *);
> +static hashnode alloc_node (cpp_hash_table *);
>  
>  /* Return an identifier node for hashtable.c.  Used by cpplib except
>     when integrated with the C front ends.  */
>  static hashnode
> -alloc_node (hash_table *table)
> +alloc_node (cpp_hash_table *table)
>  {
>    cpp_hashnode *node;
>  
> @@ -45,7 +45,7 @@ alloc_node (hash_table *table)
>  /* Set up the identifier hash table.  Use TABLE if non-null, otherwise
>     create our own.  */
>  void
> -_cpp_init_hashtable (cpp_reader *pfile, hash_table *table)
> +_cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table)
>  {
>    struct spec_nodes *s;
>  
> diff --git a/libcpp/include/symtab.h b/libcpp/include/symtab.h
> index 4107a6f..30d7645 100644
> --- a/libcpp/include/symtab.h
> +++ b/libcpp/include/symtab.h
> @@ -38,7 +38,7 @@ struct GTY(()) ht_identifier {
>  #define HT_LEN(NODE) ((NODE)->len)
>  #define HT_STR(NODE) ((NODE)->str)
>  
> -typedef struct ht hash_table;
> +typedef struct ht cpp_hash_table;
>  typedef struct ht_identifier *hashnode;
>  
>  enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC};
> @@ -51,7 +51,7 @@ struct ht
>  
>    hashnode *entries;
>    /* Call back, allocate a node.  */
> -  hashnode (*alloc_node) (hash_table *);
> +  hashnode (*alloc_node) (cpp_hash_table *);
>    /* Call back, allocate something that hangs off a node like a cpp_macro.  
>       NULL means use the usual allocator.  */
>    void * (*alloc_subobject) (size_t);
> @@ -71,14 +71,14 @@ struct ht
>  };
>  
>  /* Initialize the hashtable with 2 ^ order entries.  */
> -extern hash_table *ht_create (unsigned int order);
> +extern cpp_hash_table *ht_create (unsigned int order);
>  
>  /* Frees all memory associated with a hash table.  */
> -extern void ht_destroy (hash_table *);
> +extern void ht_destroy (cpp_hash_table *);
>  
> -extern hashnode ht_lookup (hash_table *, const unsigned char *,
> +extern hashnode ht_lookup (cpp_hash_table *, const unsigned char *,
>  			   size_t, enum ht_lookup_option);
> -extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
> +extern hashnode ht_lookup_with_hash (cpp_hash_table *, const unsigned char *,
>                                       size_t, unsigned int,
>                                       enum ht_lookup_option);
>  #define HT_HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
> @@ -88,17 +88,17 @@ extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
>     TABLE->PFILE, the node, and a PTR, and the callback sequence stops
>     if the callback returns zero.  */
>  typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
> -extern void ht_forall (hash_table *, ht_cb, const void *);
> +extern void ht_forall (cpp_hash_table *, ht_cb, const void *);
>  
>  /* For all nodes in TABLE, call the callback.  If the callback returns
>     a nonzero value, the node is removed from the table.  */
> -extern void ht_purge (hash_table *, ht_cb, const void *);
> +extern void ht_purge (cpp_hash_table *, ht_cb, const void *);
>  
>  /* Restore the hash table.  */
> -extern void ht_load (hash_table *ht, hashnode *entries,
> +extern void ht_load (cpp_hash_table *ht, hashnode *entries,
>  		     unsigned int nslots, unsigned int nelements, bool own);
>  
>  /* Dump allocation statistics to stderr.  */
> -extern void ht_dump_statistics (hash_table *);
> +extern void ht_dump_statistics (cpp_hash_table *);
>  
>  #endif /* LIBCPP_SYMTAB_H */
> diff --git a/libcpp/init.c b/libcpp/init.c
> index 7752fea..040ab34 100644
> --- a/libcpp/init.c
> +++ b/libcpp/init.c
> @@ -149,7 +149,7 @@ init_library (void)
>  
>  /* Initialize a cpp_reader structure.  */
>  cpp_reader *
> -cpp_create_reader (enum c_lang lang, hash_table *table,
> +cpp_create_reader (enum c_lang lang, cpp_hash_table *table,
>  		   struct line_maps *line_table)
>  {
>    cpp_reader *pfile;
> diff --git a/libcpp/internal.h b/libcpp/internal.h
> index 37aac82..79dd54f 100644
> --- a/libcpp/internal.h
> +++ b/libcpp/internal.h
> @@ -619,7 +619,7 @@ extern void _cpp_push_token_context (cpp_reader *, cpp_hashnode *,
>  extern void _cpp_backup_tokens_direct (cpp_reader *, unsigned int);
>  
>  /* In identifiers.c */
> -extern void _cpp_init_hashtable (cpp_reader *, hash_table *);
> +extern void _cpp_init_hashtable (cpp_reader *, cpp_hash_table *);
>  extern void _cpp_destroy_hashtable (cpp_reader *);
>  
>  /* In files.c */
> diff --git a/libcpp/symtab.c b/libcpp/symtab.c
> index 48a5338..a3537a0 100644
> --- a/libcpp/symtab.c
> +++ b/libcpp/symtab.c
> @@ -31,7 +31,7 @@ along with this program; see the file COPYING3.  If not see
>     existing entry with a potential new one.  */
>  
>  static unsigned int calc_hash (const unsigned char *, size_t);
> -static void ht_expand (hash_table *);
> +static void ht_expand (cpp_hash_table *);
>  static double approx_sqrt (double);
>  
>  /* A deleted entry.  */
> @@ -53,13 +53,13 @@ calc_hash (const unsigned char *str, size_t len)
>  
>  /* Initialize an identifier hashtable.  */
>  
> -hash_table *
> +cpp_hash_table *
>  ht_create (unsigned int order)
>  {
>    unsigned int nslots = 1 << order;
> -  hash_table *table;
> +  cpp_hash_table *table;
>  
> -  table = XCNEW (hash_table);
> +  table = XCNEW (cpp_hash_table);
>  
>    /* Strings need no alignment.  */
>    _obstack_begin (&table->stack, 0, 0,
> @@ -77,7 +77,7 @@ ht_create (unsigned int order)
>  /* Frees all memory associated with a hash table.  */
>  
>  void
> -ht_destroy (hash_table *table)
> +ht_destroy (cpp_hash_table *table)
>  {
>    obstack_free (&table->stack, NULL);
>    if (table->entries_owned)
> @@ -91,7 +91,7 @@ ht_destroy (hash_table *table)
>     returns NULL.  Otherwise insert and returns a new entry.  A new
>     string is allocated.  */
>  hashnode
> -ht_lookup (hash_table *table, const unsigned char *str, size_t len,
> +ht_lookup (cpp_hash_table *table, const unsigned char *str, size_t len,
>  	   enum ht_lookup_option insert)
>  {
>    return ht_lookup_with_hash (table, str, len, calc_hash (str, len),
> @@ -99,7 +99,7 @@ ht_lookup (hash_table *table, const unsigned char *str, size_t len,
>  }
>  
>  hashnode
> -ht_lookup_with_hash (hash_table *table, const unsigned char *str,
> +ht_lookup_with_hash (cpp_hash_table *table, const unsigned char *str,
>  		     size_t len, unsigned int hash,
>  		     enum ht_lookup_option insert)
>  {
> @@ -182,7 +182,7 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
>  /* Double the size of a hash table, re-hashing existing entries.  */
>  
>  static void
> -ht_expand (hash_table *table)
> +ht_expand (cpp_hash_table *table)
>  {
>    hashnode *nentries, *p, *limit;
>    unsigned int size, sizemask;
> @@ -224,7 +224,7 @@ ht_expand (hash_table *table)
>  /* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
>     the node, and V.  */
>  void
> -ht_forall (hash_table *table, ht_cb cb, const void *v)
> +ht_forall (cpp_hash_table *table, ht_cb cb, const void *v)
>  {
>    hashnode *p, *limit;
>  
> @@ -242,7 +242,7 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
>  /* Like ht_forall, but a nonzero return from the callback means that
>     the entry should be removed from the table.  */
>  void
> -ht_purge (hash_table *table, ht_cb cb, const void *v)
> +ht_purge (cpp_hash_table *table, ht_cb cb, const void *v)
>  {
>    hashnode *p, *limit;
>  
> @@ -259,7 +259,7 @@ ht_purge (hash_table *table, ht_cb cb, const void *v)
>  
>  /* Restore the hash table.  */
>  void
> -ht_load (hash_table *ht, hashnode *entries,
> +ht_load (cpp_hash_table *ht, hashnode *entries,
>  	 unsigned int nslots, unsigned int nelements,
>  	 bool own)
>  {
> @@ -274,7 +274,7 @@ ht_load (hash_table *ht, hashnode *entries,
>  /* Dump allocation statistics to stderr.  */
>  
>  void
> -ht_dump_statistics (hash_table *table)
> +ht_dump_statistics (cpp_hash_table *table)
>  {
>    size_t nelts, nids, overhead, headers;
>    size_t total_bytes, longest, deleted = 0;
> diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
> index 83ed653..4332398 100644
> --- a/gcc/tree-ssa-ccp.c
> +++ b/gcc/tree-ssa-ccp.c
> @@ -130,6 +130,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "dbgcnt.h"
>  #include "gimple-fold.h"
>  #include "params.h"
> +#include "hash-table.h"
>  
>  
>  /* Possible lattice values.  */
> @@ -1688,11 +1689,17 @@ evaluate_stmt (gimple stmt)
>    return val;
>  }
>  
> +typedef hash_table <gimple_statement_d, typed_pointer_hash<gimple_statement_d>,
> +		    typed_pointer_equal<gimple_statement_d>,
> +		    typed_null_remove<gimple_statement_d> >
> +		   gimple_htab;
> +
>  /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
>     each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
>  
>  static void
> -insert_clobber_before_stack_restore (tree saved_val, tree var, htab_t *visited)
> +insert_clobber_before_stack_restore (tree saved_val, tree var,
> +				     gimple_htab *visited)
>  {
>    gimple stmt, clobber_stmt;
>    tree clobber;
> @@ -1712,10 +1719,10 @@ insert_clobber_before_stack_restore (tree saved_val, tree var, htab_t *visited)
>        }
>      else if (gimple_code (stmt) == GIMPLE_PHI)
>        {
> -	if (*visited == NULL)
> -	  *visited = htab_create (10, htab_hash_pointer, htab_eq_pointer, NULL);
> +	if (!visited->is_created ())
> +	  visited->create (10);
>  
> -	slot = (gimple *)htab_find_slot (*visited, stmt, INSERT);
> +	slot = visited->find_slot (stmt, INSERT);
>  	if (*slot != NULL)
>  	  continue;
>  
> @@ -1758,7 +1765,7 @@ insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
>  {
>    gimple stmt;
>    tree saved_val;
> -  htab_t visited = NULL;
> +  gimple_htab visited;
>  
>    for (; !gsi_end_p (i); gsi_prev_dom_bb_nondebug (&i))
>      {
> @@ -1775,8 +1782,8 @@ insert_clobbers_for_var (gimple_stmt_iterator i, tree var)
>        break;
>      }
>  
> -  if (visited != NULL)
> -    htab_delete (visited);
> +  if (visited.is_created ())
> +    visited.dispose ();
>  }
>  
>  /* Detects a __builtin_alloca_with_align with constant size argument.  Declares
> diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c
> index b8b1a51..399e7fc 100644
> --- a/gcc/tree-ssa-coalesce.c
> +++ b/gcc/tree-ssa-coalesce.c
> @@ -29,7 +29,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "bitmap.h"
>  #include "dumpfile.h"
>  #include "tree-flow.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>  #include "tree-ssa-live.h"
>  #include "diagnostic-core.h"
>  
> @@ -1258,22 +1258,19 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl,
>      }
>  }
>  
> -/* Returns a hash code for P.  */
> +/* Returns a hash code for N.  */
>  
> -static hashval_t
> -hash_ssa_name_by_var (const void *p)
> +inline hashval_t
> +hash_ssa_name_by_var (const_tree n)
>  {
> -  const_tree n = (const_tree) p;
>    return (hashval_t) htab_hash_pointer (SSA_NAME_VAR (n));
>  }
>  
> -/* Returns nonzero if P1 and P2 are equal.  */
> +/* Returns nonzero if N1 and N2 are equal.  */
>  
> -static int
> -eq_ssa_name_by_var (const void *p1, const void *p2)
> +inline int
> +eq_ssa_name_by_var (const_tree n1, const_tree n2)
>  {
> -  const_tree n1 = (const_tree) p1;
> -  const_tree n2 = (const_tree) p2;
>    return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
>  }
>  
> @@ -1289,7 +1286,9 @@ coalesce_ssa_name (void)
>    bitmap used_in_copies = BITMAP_ALLOC (NULL);
>    var_map map;
>    unsigned int i;
> -  static htab_t ssa_name_hash;
> +  static hash_table <tree_node, hash_ssa_name_by_var, eq_ssa_name_by_var,
> +		     typed_null_remove<tree_node> >
> +		    ssa_name_hash;
>  
>    cl = create_coalesce_list ();
>    map = create_outofssa_var_map (cl, used_in_copies);
> @@ -1298,8 +1297,7 @@ coalesce_ssa_name (void)
>       so debug info remains undisturbed.  */
>    if (!optimize)
>      {
> -      ssa_name_hash = htab_create (10, hash_ssa_name_by_var,
> -      				   eq_ssa_name_by_var, NULL);
> +      ssa_name_hash.create (10);
>        for (i = 1; i < num_ssa_names; i++)
>  	{
>  	  tree a = ssa_name (i);
> @@ -1309,7 +1307,7 @@ coalesce_ssa_name (void)
>  	      && !DECL_IGNORED_P (SSA_NAME_VAR (a))
>  	      && (!has_zero_uses (a) || !SSA_NAME_IS_DEFAULT_DEF (a)))
>  	    {
> -	      tree *slot = (tree *) htab_find_slot (ssa_name_hash, a, INSERT);
> +	      tree *slot = ssa_name_hash.find_slot (a, INSERT);
>  
>  	      if (!*slot)
>  		*slot = a;
> @@ -1322,7 +1320,7 @@ coalesce_ssa_name (void)
>  		}
>  	    }
>  	}
> -      htab_delete (ssa_name_hash);
> +      ssa_name_hash.dispose ();
>      }
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      dump_var_map (dump_file, map);
> diff --git a/gcc/hash-table.c
> ===================================================================
> --- gcc/hash-table.c	(revision 0)
> +++ gcc/hash-table.c	(revision 0)
> @@ -0,0 +1,190 @@
> +/* A type-safe hash table template.
> +   Copyright (C) 2012
> +   Free Software Foundation, Inc.
> +   Contributed by Lawrence Crowl <crowl@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +
> +/* This file implements a typed hash table.
> +   The implementation borrows from libiberty's hashtab.  */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "hash-table.h"
> +
> +
> +/* Table of primes and multiplicative inverses.
> +
> +   Note that these are not minimally reduced inverses.  Unlike when generating
> +   code to divide by a constant, we want to be able to use the same algorithm
> +   all the time.  All of these inverses (are implied to) have bit 32 set.
> +
> +   For the record, here's the function that computed the table; it's a 
> +   vastly simplified version of the function of the same name from gcc.  */
> +
> +#if 0
> +unsigned int
> +ceil_log2 (unsigned int x)
> +{
> +  int i;
> +  for (i = 31; i >= 0 ; --i)
> +    if (x > (1u << i))
> +      return i+1;
> +  abort ();
> +}
> +
> +unsigned int
> +choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp)
> +{
> +  unsigned long long mhigh;
> +  double nx;
> +  int lgup, post_shift;
> +  int pow, pow2;
> +  int n = 32, precision = 32;
> +
> +  lgup = ceil_log2 (d);
> +  pow = n + lgup;
> +  pow2 = n + lgup - precision;
> +
> +  nx = ldexp (1.0, pow) + ldexp (1.0, pow2);
> +  mhigh = nx / d;
> +
> +  *shiftp = lgup - 1;
> +  *mlp = mhigh;
> +  return mhigh >> 32;
> +}
> +#endif
> +
> +struct prime_ent const prime_tab[] = {
> +  {          7, 0x24924925, 0x9999999b, 2 },
> +  {         13, 0x3b13b13c, 0x745d1747, 3 },
> +  {         31, 0x08421085, 0x1a7b9612, 4 },
> +  {         61, 0x0c9714fc, 0x15b1e5f8, 5 },
> +  {        127, 0x02040811, 0x0624dd30, 6 },
> +  {        251, 0x05197f7e, 0x073260a5, 7 },
> +  {        509, 0x01824366, 0x02864fc8, 8 },
> +  {       1021, 0x00c0906d, 0x014191f7, 9 },
> +  {       2039, 0x0121456f, 0x0161e69e, 10 },
> +  {       4093, 0x00300902, 0x00501908, 11 },
> +  {       8191, 0x00080041, 0x00180241, 12 },
> +  {      16381, 0x000c0091, 0x00140191, 13 },
> +  {      32749, 0x002605a5, 0x002a06e6, 14 },
> +  {      65521, 0x000f00e2, 0x00110122, 15 },
> +  {     131071, 0x00008001, 0x00018003, 16 },
> +  {     262139, 0x00014002, 0x0001c004, 17 },
> +  {     524287, 0x00002001, 0x00006001, 18 },
> +  {    1048573, 0x00003001, 0x00005001, 19 },
> +  {    2097143, 0x00004801, 0x00005801, 20 },
> +  {    4194301, 0x00000c01, 0x00001401, 21 },
> +  {    8388593, 0x00001e01, 0x00002201, 22 },
> +  {   16777213, 0x00000301, 0x00000501, 23 },
> +  {   33554393, 0x00001381, 0x00001481, 24 },
> +  {   67108859, 0x00000141, 0x000001c1, 25 },
> +  {  134217689, 0x000004e1, 0x00000521, 26 },
> +  {  268435399, 0x00000391, 0x000003b1, 27 },
> +  {  536870909, 0x00000019, 0x00000029, 28 },
> +  { 1073741789, 0x0000008d, 0x00000095, 29 },
> +  { 2147483647, 0x00000003, 0x00000007, 30 },
> +  /* Avoid "decimal constant so large it is unsigned" for 4294967291.  */
> +  { 0xfffffffb, 0x00000006, 0x00000008, 31 }
> +};
> +
> +/* The following function returns an index into the above table of the
> +   nearest prime number which is greater than N, and near a power of two. */
> +
> +unsigned int
> +hash_table_higher_prime_index (unsigned long n)
> +{
> +  unsigned int low = 0;
> +  unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
> +
> +  while (low != high)
> +    {
> +      unsigned int mid = low + (high - low) / 2;
> +      if (n > prime_tab[mid].prime)
> +	low = mid + 1;
> +      else
> +	high = mid;
> +    }
> +
> +  /* If we've run out of primes, abort.  */
> +  if (n > prime_tab[low].prime)
> +    {
> +      fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
> +      abort ();
> +    }
> +
> +  return low;
> +}
> +
> +/* Return X % Y using multiplicative inverse values INV and SHIFT.
> +
> +   The multiplicative inverses computed above are for 32-bit types,
> +   and requires that we be able to compute a highpart multiply.
> +
> +   FIX: I am not at all convinced that
> +     3 loads, 2 multiplications, 3 shifts, and 3 additions
> +   will be faster than
> +     1 load and 1 modulus
> +   on modern systems running a compiler.  */
> +
> +#ifdef UNSIGNED_64BIT_TYPE
> +static inline hashval_t
> +mul_mod (hashval_t x, hashval_t y, hashval_t inv, int shift)
> +{
> +  __extension__ typedef UNSIGNED_64BIT_TYPE ull;
> +   hashval_t t1, t2, t3, t4, q, r;
> +
> +   t1 = ((ull)x * inv) >> 32;
> +   t2 = x - t1;
> +   t3 = t2 >> 1;
> +   t4 = t1 + t3;
> +   q  = t4 >> shift;
> +   r  = x - (q * y);
> +
> +   return r;
> +}
> +#endif
> +
> +/* Compute the primary table index for HASH given current prime index.  */
> +
> +hashval_t
> +hash_table_mod1 (hashval_t hash, unsigned int index)
> +{
> +  const struct prime_ent *p = &prime_tab[index];
> +#ifdef UNSIGNED_64BIT_TYPE
> +  if (sizeof (hashval_t) * CHAR_BIT <= 32)
> +    return mul_mod (hash, p->prime, p->inv, p->shift);
> +#endif
> +  return hash % p->prime;
> +}
> +
> +
> +/* Compute the secondary table index for HASH given current prime index.  */
> +
> +hashval_t
> +hash_table_mod2 (hashval_t hash, unsigned int index)
> +{
> +  const struct prime_ent *p = &prime_tab[index];
> +#ifdef UNSIGNED_64BIT_TYPE
> +  if (sizeof (hashval_t) * CHAR_BIT <= 32)
> +    return 1 + mul_mod (hash, p->prime - 2, p->inv_m2, p->shift);
> +#endif
> +  return 1 + hash % (p->prime - 2);
> +}
> diff --git a/gcc/hash-table.h
> ===================================================================
> --- gcc/hash-table.h	(revision 0)
> +++ gcc/hash-table.h	(revision 0)
> @@ -0,0 +1,783 @@
> +/* A type-safe hash table template.
> +   Copyright (C) 2012
> +   Free Software Foundation, Inc.
> +   Contributed by Lawrence Crowl <crowl@google.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +
> +/* This file implements a typed hash table.
> +   The implementation borrows from libiberty's hashtab.  */
> +
> +
> +#ifndef TYPED_HASHTAB_H
> +#define TYPED_HASHTAB_H
> +
> +#include "hashtab.h"
> +
> +
> +/* The ordinary memory allocator.  */
> +/* FIXME (crowl): This allocator may be extracted for wider sharing later.  */
> +
> +template <typename Type>
> +struct xcallocator
> +{
> +  static Type *control_alloc (size_t count);
> +  static Type *data_alloc (size_t count);
> +  static void control_free (Type *memory);
> +  static void data_free (Type *memory);
> +};
> +
> +
> +/* Allocate memory for COUNT control blocks.  */
> +
> +template <typename Type>
> +inline Type *
> +xcallocator <Type>::control_alloc (size_t count)
> +{
> +  return static_cast <Type *> (xcalloc (count, sizeof (Type)));
> +}
> +
> +
> +/* Allocate memory for COUNT data blocks.  */ 
> +
> +template <typename Type>
> +inline Type *
> +xcallocator <Type>::data_alloc (size_t count)
> +{
> +  return static_cast <Type *> (xcalloc (count, sizeof (Type)));
> +}
> +
> +
> +/* Free memory for control blocks.  */
> +
> +template <typename Type>
> +inline void
> +xcallocator <Type>::control_free (Type *memory)
> +{
> +  return ::free (memory);
> +}
> +  
> +
> +/* Free memory for data blocks.  */
> +
> +template <typename Type>
> +inline void
> +xcallocator <Type>::data_free (Type *memory)
> +{
> +  return ::free (memory);
> +}
> +
> +
> +/* A common function for hashing a CANDIDATE typed pointer.  */
> +
> +template <typename Element>
> +inline hashval_t
> +typed_pointer_hash (const Element *candidate)
> +{
> +  /* This is a really poor hash function, but it is what the current code uses,
> +     so I am reusing it to avoid an additional axis in testing.  */
> +  return (hashval_t) ((intptr_t)candidate >> 3);
> +}
> +
> +
> +/* A common function for comparing an EXISTING and CANDIDATE typed pointers
> +   for equality. */
> +
> +template <typename Element>
> +inline int
> +typed_pointer_equal (const Element *existing, const Element * candidate)
> +{
> +  return existing == candidate;
> +}
> +
> +
> +/* A common function for doing nothing on removing a RETIRED slot.  */
> +
> +template <typename Element>
> +inline void
> +typed_null_remove (Element *retired ATTRIBUTE_UNUSED)
> +{
> +}
> +
> +
> +/* A common function for using free on removing a RETIRED slot.  */
> +
> +template <typename Element>
> +inline void
> +typed_free_remove (Element *retired)
> +{
> +  free (retired);
> +}
> +
> +
> +/* Table of primes and their inversion information.  */
> +
> +struct prime_ent
> +{
> +  hashval_t prime;
> +  hashval_t inv;
> +  hashval_t inv_m2;     /* inverse of prime-2 */
> +  hashval_t shift;
> +};
> +
> +extern struct prime_ent const prime_tab[];
> +
> +
> +/* Functions for computing hash table indexes.  */
> +
> +extern unsigned int hash_table_higher_prime_index (unsigned long n);
> +extern hashval_t hash_table_mod1 (hashval_t hash, unsigned int index);
> +extern hashval_t hash_table_mod2 (hashval_t hash, unsigned int index);
> +
> +
> +/* Internal implementation type.  */
> +
> +template <typename Element>
> +struct hash_table_control
> +{
> +  /* Table itself.  */
> +  Element **entries;
> +
> +  /* Current size (in entries) of the hash table.  */
> +  size_t size;
> +
> +  /* Current number of elements including also deleted elements.  */
> +  size_t n_elements;
> +
> +  /* Current number of deleted elements in the table.  */
> +  size_t n_deleted;
> +
> +  /* The following member is used for debugging. Its value is number
> +     of all calls of `htab_find_slot' for the hash table. */
> +  unsigned int searches;
> +
> +  /* The following member is used for debugging.  Its value is number
> +     of collisions fixed for time of work with the hash table. */
> +  unsigned int collisions;
> +
> +  /* Current size (in entries) of the hash table, as an index into the
> +     table of primes.  */
> +  unsigned int size_prime_index;
> +};
> +
> +
> +/* User-facing hash table type.
> +
> +   The table stores elements of type Element.
> +
> +   It hashes elements with the Hash function.
> +     The table currently works with relatively weak hash functions.
> +     Use typed_pointer_hash <Element> when hashing pointers instead of objects.
> +
> +   It compares elements with the Equal function.
> +     Two elements with the same hash may not be equal.
> +     Use typed_pointer_equal <Element> when hashing pointers instead of objects.
> +
> +   It removes elements with the Remove function.
> +     This feature is useful for freeing memory.
> +     Use typed_null_remove <Element> when not freeing objects.
> +     Use typed_free_remove <Element> when doing a simple object free.
> +
> +   Use the Allocator template to allocate and free memory.
> +     The default is xcallocator.
> +
> +*/
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator = xcallocator>
> +class hash_table
> +{
> +
> +private:
> +
> +  hash_table_control <Element> *htab;
> +
> +  Element **find_empty_slot_for_expand (hashval_t hash);
> +  void expand ();
> +
> +public:
> +
> +  hash_table ();
> +  void create (size_t initial_slots);
> +  bool is_created ();
> +  void dispose ();
> +  Element *find (Element *comparable);
> +  Element *find_with_hash (Element *comparable, hashval_t hash);
> +  Element **find_slot (Element *comparable, enum insert_option insert);
> +  Element **find_slot_with_hash (Element *comparable, hashval_t hash,
> +				 enum insert_option insert);
> +  void empty ();
> +  void clear_slot (Element **slot);
> +  void remove_elt (Element *comparable);
> +  void remove_elt_with_hash (Element *comparable, hashval_t hash);
> +  size_t size();
> +  size_t elements();
> +  double collisions();
> +
> +  template <typename Argument,
> +	    int (*Callback) (Element **slot, Argument argument)>
> +  void traverse_noresize (Argument argument);
> +
> +  template <typename Argument,
> +	    int (*Callback) (Element **slot, Argument argument)>
> +  void traverse (Argument argument);
> +};
> +
> +
> +/* Construct the hash table.  The only useful operation next is create.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline
> +hash_table <Element, Hash, Equal, Remove, Allocator>::hash_table ()
> +: htab (NULL)
> +{
> +}
> +
> +
> +/* See if the table has been created, as opposed to constructed.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline bool
> +hash_table <Element, Hash, Equal, Remove, Allocator>::is_created ()
> +{
> +  return htab != NULL;
> +}
> +
> +
> +/* Like find_with_hash, but compute the hash value from the element.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline Element *
> +hash_table <Element, Hash, Equal, Remove, Allocator>::find (Element *comparable)
> +{
> +  return find_with_hash (comparable, Hash (comparable));
> +}
> +
> +
> +/* Like find_slot_with_hash, but compute the hash value from the element.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline Element **
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_slot (Element *comparable, enum insert_option insert)
> +{
> +  return find_slot_with_hash (comparable, Hash (comparable), insert);
> +}
> +
> +
> +/* Like remove_elt_with_hash, but compute the hash value from the element.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::remove_elt (Element *comparable)
> +{
> +  remove_elt_with_hash (comparable, Hash (comparable));
> +}
> +
> +
> +/* Return the current size of this hash table.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline size_t
> +hash_table <Element, Hash, Equal, Remove, Allocator>::size()
> +{
> +  return htab->size;
> +}
> +
> +
> +/* Return the current number of elements in this hash table. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline size_t
> +hash_table <Element, Hash, Equal, Remove, Allocator>::elements()
> +{
> +  return htab->n_elements - htab->n_deleted;
> +}
> +
> +
> +  /* Return the fraction of fixed collisions during all work with given
> +     hash table. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +inline double
> +hash_table <Element, Hash, Equal, Remove, Allocator>::collisions()
> +{
> +  if (htab->searches == 0)
> +    return 0.0;
> +
> +  return static_cast <double> (htab->collisions) / htab->searches;
> +}
> +
> +
> +/* Create a hash table with at least the given number of INITIAL_SLOTS.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::create (size_t size)
> +{
> +  unsigned int size_prime_index;
> +
> +  size_prime_index = hash_table_higher_prime_index (size);
> +  size = prime_tab[size_prime_index].prime;
> +
> +  htab = Allocator <hash_table_control <Element> > ::control_alloc (1);
> +  gcc_assert (htab != NULL);
> +  htab->entries = Allocator <Element*> ::data_alloc (size);
> +  gcc_assert (htab->entries != NULL);
> +  htab->size = size;
> +  htab->size_prime_index = size_prime_index;
> +}
> +
> +
> +/* Dispose of a hash table.  Free all memory and return this hash table to
> +   the non-created state.  Naturally the hash table must already exist.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::dispose ()
> +{
> +  size_t size = htab->size;
> +  Element **entries = htab->entries;
> +
> +  for (int i = size - 1; i >= 0; i--)
> +    if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
> +      Remove (entries[i]);
> +
> +  Allocator <Element *> ::data_free (entries);
> +  Allocator <hash_table_control <Element> > ::control_free (htab);
> +  htab = NULL;
> +}
> +
> +
> +/* Similar to find_slot, but without several unwanted side effects:
> +    - Does not call Equal when it finds an existing entry.
> +    - Does not change the count of elements/searches/collisions in the
> +      hash table.
> +   This function also assumes there are no deleted entries in the table.
> +   HASH is the hash value for the element to be inserted.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +Element **
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_empty_slot_for_expand (hashval_t hash)
> +{
> +  hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
> +  size_t size = htab->size;
> +  Element **slot = htab->entries + index;
> +  hashval_t hash2;
> +
> +  if (*slot == HTAB_EMPTY_ENTRY)
> +    return slot;
> +  else if (*slot == HTAB_DELETED_ENTRY)
> +    abort ();
> +
> +  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> +  for (;;)
> +    {
> +      index += hash2;
> +      if (index >= size)
> +        index -= size;
> +
> +      slot = htab->entries + index;
> +      if (*slot == HTAB_EMPTY_ENTRY)
> +        return slot;
> +      else if (*slot == HTAB_DELETED_ENTRY)
> +        abort ();
> +    }
> +}
> +
> +
> +/* The following function changes size of memory allocated for the
> +   entries and repeatedly inserts the table elements.  The occupancy
> +   of the table after the call will be about 50%.  Naturally the hash
> +   table must already exist.  Remember also that the place of the
> +   table entries is changed.  If memory allocation fails, this function
> +   will abort.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::expand ()
> +{
> +  Element **oentries;
> +  Element **olimit;
> +  Element **p;
> +  Element **nentries;
> +  size_t nsize, osize, elts;
> +  unsigned int oindex, nindex;
> +
> +  oentries = htab->entries;
> +  oindex = htab->size_prime_index;
> +  osize = htab->size;
> +  olimit = oentries + osize;
> +  elts = elements ();
> +
> +  /* Resize only when table after removal of unused elements is either
> +     too full or too empty.  */
> +  if (elts * 2 > osize || (elts * 8 < osize && osize > 32))
> +    {
> +      nindex = hash_table_higher_prime_index (elts * 2);
> +      nsize = prime_tab[nindex].prime;
> +    }
> +  else
> +    {
> +      nindex = oindex;
> +      nsize = osize;
> +    }
> +
> +  nentries = Allocator <Element *> ::data_alloc (nsize);
> +  gcc_assert (nentries != NULL);
> +  htab->entries = nentries;
> +  htab->size = nsize;
> +  htab->size_prime_index = nindex;
> +  htab->n_elements -= htab->n_deleted;
> +  htab->n_deleted = 0;
> +
> +  p = oentries;
> +  do
> +    {
> +      Element *x = *p;
> +
> +      if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
> +        {
> +          Element **q = find_empty_slot_for_expand (Hash (x));
> +
> +          *q = x;
> +        }
> +
> +      p++;
> +    }
> +  while (p < olimit);
> +
> +  Allocator <Element *> ::data_free (oentries);
> +}
> +
> +
> +/* This function searches for a hash table entry equal to the given
> +   COMPARABLE element starting with the given HASH value.  It cannot
> +   be used to insert or delete an element. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +Element *
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_with_hash (Element *comparable, hashval_t hash)
> +{
> +  hashval_t index, hash2;
> +  size_t size;
> +  Element *entry;
> +
> +  htab->searches++;
> +  size = htab->size;
> +  index = hash_table_mod1 (hash, htab->size_prime_index);
> +
> +  entry = htab->entries[index];
> +  if (entry == HTAB_EMPTY_ENTRY
> +      || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
> +    return entry;
> +
> +  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> +  for (;;)
> +    {
> +      htab->collisions++;
> +      index += hash2;
> +      if (index >= size)
> +        index -= size;
> +
> +      entry = htab->entries[index];
> +      if (entry == HTAB_EMPTY_ENTRY
> +          || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
> +        return entry;
> +    }
> +}
> +
> +
> +/* This function searches for a hash table slot containing an entry
> +   equal to the given COMPARABLE element and starting with the given
> +   HASH.  To delete an entry, call this with insert=NO_INSERT, then
> +   call clear_slot on the slot returned (possibly after doing some
> +   checks).  To insert an entry, call this with insert=INSERT, then
> +   write the value you want into the returned slot.  When inserting an
> +   entry, NULL may be returned if memory allocation fails. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +Element **
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::find_slot_with_hash (Element *comparable, hashval_t hash,
> +		       enum insert_option insert)
> +{
> +  Element **first_deleted_slot;
> +  hashval_t index, hash2;
> +  size_t size;
> +  Element *entry;
> +
> +  size = htab->size;
> +  if (insert == INSERT && size * 3 <= htab->n_elements * 4)
> +    {
> +      expand ();
> +      size = htab->size;
> +    }
> +
> +  index = hash_table_mod1 (hash, htab->size_prime_index);
> +
> +  htab->searches++;
> +  first_deleted_slot = NULL;
> +
> +  entry = htab->entries[index];
> +  if (entry == HTAB_EMPTY_ENTRY)
> +    goto empty_entry;
> +  else if (entry == HTAB_DELETED_ENTRY)
> +    first_deleted_slot = &htab->entries[index];
> +  else if (Equal (entry, comparable))
> +    return &htab->entries[index];
> +      
> +  hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> +  for (;;)
> +    {
> +      htab->collisions++;
> +      index += hash2;
> +      if (index >= size)
> +	index -= size;
> +      
> +      entry = htab->entries[index];
> +      if (entry == HTAB_EMPTY_ENTRY)
> +	goto empty_entry;
> +      else if (entry == HTAB_DELETED_ENTRY)
> +	{
> +	  if (!first_deleted_slot)
> +	    first_deleted_slot = &htab->entries[index];
> +	}
> +      else if (Equal (entry, comparable))
> +	return &htab->entries[index];
> +    }
> +
> + empty_entry:
> +  if (insert == NO_INSERT)
> +    return NULL;
> +
> +  if (first_deleted_slot)
> +    {
> +      htab->n_deleted--;
> +      *first_deleted_slot = static_cast <Element *> (HTAB_EMPTY_ENTRY);
> +      return first_deleted_slot;
> +    }
> +
> +  htab->n_elements++;
> +  return &htab->entries[index];
> +}
> +
> +
> +/* This function clears all entries in the given hash table.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>::empty ()
> +{
> +  size_t size = htab_size (htab);
> +  Element **entries = htab->entries;
> +  int i;
> +
> +  for (i = size - 1; i >= 0; i--)
> +    if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
> +      Remove (entries[i]);
> +
> +  /* Instead of clearing megabyte, downsize the table.  */
> +  if (size > 1024*1024 / sizeof (PTR))
> +    {
> +      int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
> +      int nsize = prime_tab[nindex].prime;
> +
> +      Allocator <Element *> ::data_free (htab->entries);
> +      htab->entries = Allocator <Element *> ::data_alloc (nsize);
> +      htab->size = nsize;
> +      htab->size_prime_index = nindex;
> +    }
> +  else
> +    memset (entries, 0, size * sizeof (Element *));
> +  htab->n_deleted = 0;
> +  htab->n_elements = 0;
> +}
> +
> +
> +/* This function clears a specified SLOT in a hash table.  It is
> +   useful when you've already done the lookup and don't want to do it
> +   again. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::clear_slot (Element **slot)
> +{
> +  if (slot < htab->entries || slot >= htab->entries + htab->size
> +      || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
> +    abort ();
> +
> +  Remove (*slot);
> +
> +  *slot = HTAB_DELETED_ENTRY;
> +  htab->n_deleted++;
> +}
> +
> +
> +/* This function deletes an element with the given COMPARABLE value
> +   from hash table starting with the given HASH.  If there is no
> +   matching element in the hash table, this function does nothing. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::remove_elt_with_hash (Element *comparable, hashval_t hash)
> +{
> +  Element **slot;
> +
> +  slot = find_slot_with_hash (comparable, hash, NO_INSERT);
> +  if (*slot == HTAB_EMPTY_ENTRY)
> +    return;
> +
> +  Remove (*slot);
> +
> +  *slot = static_cast <Element *> (HTAB_DELETED_ENTRY);
> +  htab->n_deleted++;
> +}
> +
> +
> +/* This function scans over the entire hash table calling CALLBACK for
> +   each live entry.  If CALLBACK returns false, the iteration stops.
> +   ARGUMENT is passed as CALLBACK's second argument. */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +template <typename Argument,
> +	  int (*Callback) (Element **slot, Argument argument)>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::traverse_noresize (Argument argument)
> +{
> +  Element **slot;
> +  Element **limit;
> +
> +  slot = htab->entries;
> +  limit = slot + htab->size;
> +
> +  do
> +    {
> +      Element *x = *slot;
> +
> +      if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
> +        if (! Callback (slot, argument))
> +          break;
> +    }
> +  while (++slot < limit);
> +}
> +
> +
> +/* Like traverse_noresize, but does resize the table when it is too empty
> +   to improve effectivity of subsequent calls.  */
> +
> +template <typename Element,
> +	  hashval_t (*Hash) (const Element *candidate),
> +	  int (*Equal) (const Element *existing, const Element * candidate),
> +	  void (*Remove) (Element *retired),
> +	  template <typename Type> class Allocator>
> +template <typename Argument,
> +	  int (*Callback) (Element **slot, Argument argument)>
> +void
> +hash_table <Element, Hash, Equal, Remove, Allocator>
> +::traverse (Argument argument)
> +{
> +  size_t size = htab->size;
> +  if (elements () * 8 < size && size > 32)
> +    expand ();
> +
> +  traverse_noresize <Argument, Callback> (argument);
> +}
> +
> +#endif /* TYPED_HASHTAB_H */
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 13:00 ` Richard Guenther
@ 2012-08-15 13:41   ` Richard Guenther
  2012-08-15 14:05     ` Michael Matz
  2012-08-15 21:52   ` Lawrence Crowl
  1 sibling, 1 reply; 29+ messages in thread
From: Richard Guenther @ 2012-08-15 13:41 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches, Richard Henderson, crowl

On Wed, 15 Aug 2012, Richard Guenther wrote:

> On Sun, 12 Aug 2012, Diego Novillo wrote:
> 
> > This implements a new C++ hash table.
> > 
> > See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for
> > details.
> > 
> > Diego.
> 
> Now as we see the result I'd have prefered a more C++-way instead
> of making the conversion simple ...
> 
> Like
> 
> template <typename Element>
> class hash_table
> {
> ...
> };
> 
> template <typename Element>
> class pointer_hash
> {
>   hashval_t hash ();
>   int equal (const Element *);
>   ~Element ();
>   Element e;
> };
> 
> and
> 
> /* Hash table with all same_succ entries.  */
> 
> static hash_table <pointer_hash <struct same_succ_def> > same_succ_htab;
> 
> The existing way is simply too ugly ... so, why did you not invent
> a "nice" C++ way?

Like the following, only the coverage.c use is converted.  I've
never seen template function arguments anywhere and having to repeat
them all over the place is really really ugly (yes, even if only in
the implementation).

This goes with static member functions and not wrapping any data.
It goes away with the requirement of having externally visible
global functions for the hash/compare functions as well (which was
ugly anyway).

Comments?

Thanks,
Richard.

> diffstat ~/p
 coverage.c   |   43 +++++-----
 hash-table.h |  234 
+++++++++++++++++++++--------------------------------------
 2 files changed, 108 insertions(+), 169 deletions(-)


Index: gcc/hash-table.h
===================================================================
--- gcc/hash-table.h	(revision 190410)
+++ gcc/hash-table.h	(working copy)
@@ -199,45 +199,42 @@ struct hash_table_control
 */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator = xcallocator>
 class hash_table
 {
+public:
+  typedef typename Element::Element_t Element_t;
 
 private:
+  hash_table_control <Element_t> *htab;
 
-  hash_table_control <Element> *htab;
-
-  Element **find_empty_slot_for_expand (hashval_t hash);
+  Element_t **find_empty_slot_for_expand (hashval_t hash);
   void expand ();
 
 public:
-
   hash_table ();
   void create (size_t initial_slots);
   bool is_created ();
   void dispose ();
-  Element *find (Element *comparable);
-  Element *find_with_hash (Element *comparable, hashval_t hash);
-  Element **find_slot (Element *comparable, enum insert_option insert);
-  Element **find_slot_with_hash (Element *comparable, hashval_t hash,
-				 enum insert_option insert);
+  Element_t *find (Element_t *comparable);
+  Element_t *find_with_hash (Element_t *comparable, hashval_t hash);
+  Element_t **find_slot (Element_t *comparable, enum insert_option insert);
+  Element_t **find_slot_with_hash (Element_t *comparable, hashval_t hash,
+				   enum insert_option insert);
   void empty ();
-  void clear_slot (Element **slot);
-  void remove_elt (Element *comparable);
-  void remove_elt_with_hash (Element *comparable, hashval_t hash);
+  void clear_slot (Element_t **slot);
+  void remove_elt (Element_t *comparable);
+  void remove_elt_with_hash (Element_t *comparable, hashval_t hash);
   size_t size();
   size_t elements();
   double collisions();
 
   template <typename Argument,
-	    int (*Callback) (Element **slot, Argument argument)>
+	    int (*Callback) (Element_t **slot, Argument argument)>
   void traverse_noresize (Argument argument);
 
   template <typename Argument,
-	    int (*Callback) (Element **slot, Argument argument)>
+	    int (*Callback) (Element_t **slot, Argument argument)>
   void traverse (Argument argument);
 };
 
@@ -245,12 +242,9 @@ public:
 /* Construct the hash table.  The only useful operation next is create.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 inline
-hash_table <Element, Hash, Equal, Remove, Allocator>::hash_table ()
+hash_table <Element, Allocator>::hash_table ()
 : htab (NULL)
 {
 }
@@ -259,12 +253,9 @@ hash_table <Element, Hash, Equal, Remove
 /* See if the table has been created, as opposed to constructed.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 inline bool
-hash_table <Element, Hash, Equal, Remove, Allocator>::is_created ()
+hash_table <Element, Allocator>::is_created ()
 {
   return htab != NULL;
 }
@@ -273,56 +264,44 @@ hash_table <Element, Hash, Equal, Remove
 /* Like find_with_hash, but compute the hash value from the element.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
-inline Element *
-hash_table <Element, Hash, Equal, Remove, Allocator>::find (Element *comparable)
+inline typename Element::Element_t *
+hash_table <Element, Allocator>::find (Element_t *comparable)
 {
-  return find_with_hash (comparable, Hash (comparable));
+  return find_with_hash (comparable, Element::Hash (comparable));
 }
 
 
 /* Like find_slot_with_hash, but compute the hash value from the element.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
-	  template <typename Type> class Allocator>
-inline Element **
-hash_table <Element, Hash, Equal, Remove, Allocator>
-::find_slot (Element *comparable, enum insert_option insert)
+	  template <typename Type> class Allocator>
+inline typename Element::Element_t **
+hash_table <Element, Allocator>
+::find_slot (Element_t *comparable, enum insert_option insert)
 {
-  return find_slot_with_hash (comparable, Hash (comparable), insert);
+  return find_slot_with_hash (comparable, Element::Hash (comparable), insert);
 }
 
 
 /* Like remove_elt_with_hash, but compute the hash value from the element.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 inline void
-hash_table <Element, Hash, Equal, Remove, Allocator>
-::remove_elt (Element *comparable)
+hash_table <Element, Allocator>
+::remove_elt (Element_t *comparable)
 {
-  remove_elt_with_hash (comparable, Hash (comparable));
+  remove_elt_with_hash (comparable, Element::Hash (comparable));
 }
 
 
 /* Return the current size of this hash table.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 inline size_t
-hash_table <Element, Hash, Equal, Remove, Allocator>::size()
+hash_table <Element, Allocator>::size()
 {
   return htab->size;
 }
@@ -331,12 +310,9 @@ hash_table <Element, Hash, Equal, Remove
 /* Return the current number of elements in this hash table. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 inline size_t
-hash_table <Element, Hash, Equal, Remove, Allocator>::elements()
+hash_table <Element, Allocator>::elements()
 {
   return htab->n_elements - htab->n_deleted;
 }
@@ -346,12 +322,9 @@ hash_table <Element, Hash, Equal, Remove
      hash table. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 inline double
-hash_table <Element, Hash, Equal, Remove, Allocator>::collisions()
+hash_table <Element, Allocator>::collisions()
 {
   if (htab->searches == 0)
     return 0.0;
@@ -363,21 +336,18 @@ hash_table <Element, Hash, Equal, Remove
 /* Create a hash table with at least the given number of INITIAL_SLOTS.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>::create (size_t size)
+hash_table <Element, Allocator>::create (size_t size)
 {
   unsigned int size_prime_index;
 
   size_prime_index = hash_table_higher_prime_index (size);
   size = prime_tab[size_prime_index].prime;
 
-  htab = Allocator <hash_table_control <Element> > ::control_alloc (1);
+  htab = Allocator <hash_table_control <Element_t> > ::control_alloc (1);
   gcc_assert (htab != NULL);
-  htab->entries = Allocator <Element*> ::data_alloc (size);
+  htab->entries = Allocator <Element_t*> ::data_alloc (size);
   gcc_assert (htab->entries != NULL);
   htab->size = size;
   htab->size_prime_index = size_prime_index;
@@ -388,22 +358,19 @@ hash_table <Element, Hash, Equal, Remove
    the non-created state.  Naturally the hash table must already exist.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>::dispose ()
+hash_table <Element, Allocator>::dispose ()
 {
   size_t size = htab->size;
-  Element **entries = htab->entries;
+  Element_t **entries = htab->entries;
 
   for (int i = size - 1; i >= 0; i--)
     if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
-      Remove (entries[i]);
+      Element::Remove (entries[i]);
 
-  Allocator <Element *> ::data_free (entries);
-  Allocator <hash_table_control <Element> > ::control_free (htab);
+  Allocator <Element_t *> ::data_free (entries);
+  Allocator <hash_table_control <Element_t> > ::control_free (htab);
   htab = NULL;
 }
 
@@ -416,17 +383,14 @@ hash_table <Element, Hash, Equal, Remove
    HASH is the hash value for the element to be inserted.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
-Element **
-hash_table <Element, Hash, Equal, Remove, Allocator>
+typename Element::Element_t **
+hash_table <Element, Allocator>
 ::find_empty_slot_for_expand (hashval_t hash)
 {
   hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
   size_t size = htab->size;
-  Element **slot = htab->entries + index;
+  Element_t **slot = htab->entries + index;
   hashval_t hash2;
 
   if (*slot == HTAB_EMPTY_ENTRY)
@@ -458,17 +422,14 @@ hash_table <Element, Hash, Equal, Remove
    will abort.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>::expand ()
+hash_table <Element, Allocator>::expand ()
 {
-  Element **oentries;
-  Element **olimit;
-  Element **p;
-  Element **nentries;
+  Element_t **oentries;
+  Element_t **olimit;
+  Element_t **p;
+  Element_t **nentries;
   size_t nsize, osize, elts;
   unsigned int oindex, nindex;
 
@@ -491,7 +452,7 @@ hash_table <Element, Hash, Equal, Remove
       nsize = osize;
     }
 
-  nentries = Allocator <Element *> ::data_alloc (nsize);
+  nentries = Allocator <Element_t *> ::data_alloc (nsize);
   gcc_assert (nentries != NULL);
   htab->entries = nentries;
   htab->size = nsize;
@@ -502,11 +463,11 @@ hash_table <Element, Hash, Equal, Remove
   p = oentries;
   do
     {
-      Element *x = *p;
+      Element_t *x = *p;
 
       if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
         {
-          Element **q = find_empty_slot_for_expand (Hash (x));
+          Element_t **q = find_empty_slot_for_expand (Element::Hash (x));
 
           *q = x;
         }
@@ -515,7 +476,7 @@ hash_table <Element, Hash, Equal, Remove
     }
   while (p < olimit);
 
-  Allocator <Element *> ::data_free (oentries);
+  Allocator <Element_t *> ::data_free (oentries);
 }
 
 
@@ -524,17 +485,14 @@ hash_table <Element, Hash, Equal, Remove
    be used to insert or delete an element. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
-	  template <typename Type> class Allocator>
-Element *
-hash_table <Element, Hash, Equal, Remove, Allocator>
-::find_with_hash (Element *comparable, hashval_t hash)
+	  template <typename Type> class Allocator>
+typename Element::Element_t *
+hash_table <Element, Allocator>
+::find_with_hash (Element_t *comparable, hashval_t hash)
 {
   hashval_t index, hash2;
   size_t size;
-  Element *entry;
+  Element_t *entry;
 
   htab->searches++;
   size = htab->size;
@@ -542,7 +500,7 @@ hash_table <Element, Hash, Equal, Remove
 
   entry = htab->entries[index];
   if (entry == HTAB_EMPTY_ENTRY
-      || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
+      || (entry != HTAB_DELETED_ENTRY && Element::Equal (entry, comparable)))
     return entry;
 
   hash2 = hash_table_mod2 (hash, htab->size_prime_index);
@@ -555,7 +513,7 @@ hash_table <Element, Hash, Equal, Remove
 
       entry = htab->entries[index];
       if (entry == HTAB_EMPTY_ENTRY
-          || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
+          || (entry != HTAB_DELETED_ENTRY && Element::Equal (entry, comparable)))
         return entry;
     }
 }
@@ -570,19 +528,16 @@ hash_table <Element, Hash, Equal, Remove
    entry, NULL may be returned if memory allocation fails. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
-	  template <typename Type> class Allocator>
-Element **
-hash_table <Element, Hash, Equal, Remove, Allocator>
-::find_slot_with_hash (Element *comparable, hashval_t hash,
+	  template <typename Type> class Allocator>
+typename Element::Element_t **
+hash_table <Element, Allocator>
+::find_slot_with_hash (Element_t *comparable, hashval_t hash,
 		       enum insert_option insert)
 {
-  Element **first_deleted_slot;
+  Element_t **first_deleted_slot;
   hashval_t index, hash2;
   size_t size;
-  Element *entry;
+  Element_t *entry;
 
   size = htab->size;
   if (insert == INSERT && size * 3 <= htab->n_elements * 4)
@@ -601,7 +556,7 @@ hash_table <Element, Hash, Equal, Remove
     goto empty_entry;
   else if (entry == HTAB_DELETED_ENTRY)
     first_deleted_slot = &htab->entries[index];
-  else if (Equal (entry, comparable))
+  else if (Element::Equal (entry, comparable))
     return &htab->entries[index];
       
   hash2 = hash_table_mod2 (hash, htab->size_prime_index);
@@ -620,7 +575,7 @@ hash_table <Element, Hash, Equal, Remove
 	  if (!first_deleted_slot)
 	    first_deleted_slot = &htab->entries[index];
 	}
-      else if (Equal (entry, comparable))
+      else if (Element::Equal (entry, comparable))
 	return &htab->entries[index];
     }
 
@@ -631,7 +586,7 @@ hash_table <Element, Hash, Equal, Remove
   if (first_deleted_slot)
     {
       htab->n_deleted--;
-      *first_deleted_slot = static_cast <Element *> (HTAB_EMPTY_ENTRY);
+      *first_deleted_slot = static_cast <Element_t *> (HTAB_EMPTY_ENTRY);
       return first_deleted_slot;
     }
 
@@ -643,20 +598,17 @@ hash_table <Element, Hash, Equal, Remove
 /* This function clears all entries in the given hash table.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>::empty ()
+hash_table <Element, Allocator>::empty ()
 {
   size_t size = htab_size (htab);
-  Element **entries = htab->entries;
+  Element_t **entries = htab->entries;
   int i;
 
   for (i = size - 1; i >= 0; i--)
     if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
-      Remove (entries[i]);
+      Element::Remove (entries[i]);
 
   /* Instead of clearing megabyte, downsize the table.  */
   if (size > 1024*1024 / sizeof (PTR))
@@ -664,13 +616,13 @@ hash_table <Element, Hash, Equal, Remove
       int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
       int nsize = prime_tab[nindex].prime;
 
-      Allocator <Element *> ::data_free (htab->entries);
-      htab->entries = Allocator <Element *> ::data_alloc (nsize);
+      Allocator <Element_t *> ::data_free (htab->entries);
+      htab->entries = Allocator <Element_t *> ::data_alloc (nsize);
       htab->size = nsize;
       htab->size_prime_index = nindex;
     }
   else
-    memset (entries, 0, size * sizeof (Element *));
+    memset (entries, 0, size * sizeof (Element_t *));
   htab->n_deleted = 0;
   htab->n_elements = 0;
 }
@@ -681,19 +633,16 @@ hash_table <Element, Hash, Equal, Remove
    again. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>
-::clear_slot (Element **slot)
+hash_table <Element, Allocator>
+::clear_slot (Element_t **slot)
 {
   if (slot < htab->entries || slot >= htab->entries + htab->size
       || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
     abort ();
 
-  Remove (*slot);
+  Element::Remove (*slot);
 
   *slot = HTAB_DELETED_ENTRY;
   htab->n_deleted++;
@@ -705,23 +654,20 @@ hash_table <Element, Hash, Equal, Remove
    matching element in the hash table, this function does nothing. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>
-::remove_elt_with_hash (Element *comparable, hashval_t hash)
+hash_table <Element, Allocator>
+::remove_elt_with_hash (Element_t *comparable, hashval_t hash)
 {
-  Element **slot;
+  Element_t **slot;
 
   slot = find_slot_with_hash (comparable, hash, NO_INSERT);
   if (*slot == HTAB_EMPTY_ENTRY)
     return;
 
-  Remove (*slot);
+  Element::Remove (*slot);
 
-  *slot = static_cast <Element *> (HTAB_DELETED_ENTRY);
+  *slot = static_cast <Element_t *> (HTAB_DELETED_ENTRY);
   htab->n_deleted++;
 }
 
@@ -731,25 +677,22 @@ hash_table <Element, Hash, Equal, Remove
    ARGUMENT is passed as CALLBACK's second argument. */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 template <typename Argument,
-	  int (*Callback) (Element **slot, Argument argument)>
+	  int (*Callback) (typename Element::Element_t **slot, Argument argument)>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>
+hash_table <Element, Allocator>
 ::traverse_noresize (Argument argument)
 {
-  Element **slot;
-  Element **limit;
+  Element_t **slot;
+  Element_t **limit;
 
   slot = htab->entries;
   limit = slot + htab->size;
 
   do
     {
-      Element *x = *slot;
+      Element_t *x = *slot;
 
       if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
         if (! Callback (slot, argument))
@@ -763,14 +706,11 @@ hash_table <Element, Hash, Equal, Remove
    to improve effectivity of subsequent calls.  */
 
 template <typename Element,
-	  hashval_t (*Hash) (const Element *candidate),
-	  int (*Equal) (const Element *existing, const Element * candidate),
-	  void (*Remove) (Element *retired),
 	  template <typename Type> class Allocator>
 template <typename Argument,
-	  int (*Callback) (Element **slot, Argument argument)>
+	  int (*Callback) (typename Element::Element_t **slot, Argument argument)>
 void
-hash_table <Element, Hash, Equal, Remove, Allocator>
+hash_table <Element, Allocator>
 ::traverse (Argument argument)
 {
   size_t size = htab->size;
Index: gcc/coverage.c
===================================================================
--- gcc/coverage.c	(revision 190410)
+++ gcc/coverage.c	(working copy)
@@ -143,30 +143,29 @@ get_gcov_unsigned_t (void)
   return lang_hooks.types.type_for_mode (mode, true);
 }
 \f
-inline hashval_t
-coverage_counts_entry_hash (const counts_entry_t *entry)
-{
-  return entry->ident * GCOV_COUNTERS + entry->ctr;
-}
-
-inline int
-coverage_counts_entry_eq (const counts_entry_t *entry1,
-                          const counts_entry_t *entry2)
-{
-  return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
-}
-
-inline void
-coverage_counts_entry_del (counts_entry_t *entry)
-{
-  free (entry->counts);
-  free (entry);
-}
+class coverage_hash {
+public:
+    typedef counts_entry_t Element_t;
+    static inline int Equal (const counts_entry_t *entry1,
+			     const counts_entry_t *entry2)
+      {
+	return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
+      }
+    static inline hashval_t
+    Hash (const counts_entry_t *entry)
+      {
+	return entry->ident * GCOV_COUNTERS + entry->ctr;
+      }
+    static inline void
+    Remove (counts_entry_t *entry)
+      {
+	free (entry->counts);
+	free (entry);
+      }
+};
 
 /* Hash table of count data.  */
-static hash_table <counts_entry_t, coverage_counts_entry_hash,
-		   coverage_counts_entry_eq, coverage_counts_entry_del>
-		  counts_hash;
+static hash_table <coverage_hash> counts_hash;
 
 /* Read in the counts file, if available.  */
 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 13:41   ` Richard Guenther
@ 2012-08-15 14:05     ` Michael Matz
  2012-08-15 14:32       ` Richard Guenther
  0 siblings, 1 reply; 29+ messages in thread
From: Michael Matz @ 2012-08-15 14:05 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Diego Novillo, gcc-patches, Richard Henderson, crowl

Hi,

On Wed, 15 Aug 2012, Richard Guenther wrote:

> Like the following, only the coverage.c use is converted.  I've never 
> seen template function arguments anywhere and having to repeat them all 
> over the place is really really ugly (yes, even if only in the 
> implementation).
> 
> This goes with static member functions and not wrapping any data. It 
> goes away with the requirement of having externally visible global 
> functions for the hash/compare functions as well (which was ugly 
> anyway).
> 
> Comments?

Well, it looks nicer than what's there currently.  As the element 
functions now are scoped and normal member functions, they should be named 
with lower case characters of course.  I do like that the hash table would 
then only have one real template argument; the Allocator, well, no better 
idea comes to my mind.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 14:05     ` Michael Matz
@ 2012-08-15 14:32       ` Richard Guenther
  2012-08-15 16:17         ` Richard Henderson
  2012-08-15 21:57         ` Lawrence Crowl
  0 siblings, 2 replies; 29+ messages in thread
From: Richard Guenther @ 2012-08-15 14:32 UTC (permalink / raw)
  To: Michael Matz; +Cc: Diego Novillo, gcc-patches, Richard Henderson, crowl

On Wed, 15 Aug 2012, Michael Matz wrote:

> Hi,
> 
> On Wed, 15 Aug 2012, Richard Guenther wrote:
> 
> > Like the following, only the coverage.c use is converted.  I've never 
> > seen template function arguments anywhere and having to repeat them all 
> > over the place is really really ugly (yes, even if only in the 
> > implementation).
> > 
> > This goes with static member functions and not wrapping any data. It 
> > goes away with the requirement of having externally visible global 
> > functions for the hash/compare functions as well (which was ugly 
> > anyway).
> > 
> > Comments?
> 
> Well, it looks nicer than what's there currently.  As the element 
> functions now are scoped and normal member functions, they should be named 
> with lower case characters of course.  I do like that the hash table would 
> then only have one real template argument; the Allocator, well, no better 
> idea comes to my mind.

Yeah.  Updated patch below, all users converted.  I probably missed
to revert some of the globalizations of hash/compare fns.

Comments?
Richard.

Index: gcc/hash-table.h
===================================================================
*** gcc/hash-table.h.orig	2012-08-15 15:39:34.000000000 +0200
--- gcc/hash-table.h	2012-08-15 16:17:06.613628039 +0200
*************** xcallocator <Type>::data_free (Type *mem
*** 83,127 ****
  }
  
  
- /* A common function for hashing a CANDIDATE typed pointer.  */
- 
  template <typename Element>
! inline hashval_t
! typed_pointer_hash (const Element *candidate)
  {
!   /* This is a really poor hash function, but it is what the current code uses,
!      so I am reusing it to avoid an additional axis in testing.  */
!   return (hashval_t) ((intptr_t)candidate >> 3);
! }
  
  
- /* A common function for comparing an EXISTING and CANDIDATE typed pointers
-    for equality. */
  
  template <typename Element>
! inline int
! typed_pointer_equal (const Element *existing, const Element * candidate)
  {
!   return existing == candidate;
! }
  
  
! /* A common function for doing nothing on removing a RETIRED slot.  */
  
  template <typename Element>
! inline void
! typed_null_remove (Element *retired ATTRIBUTE_UNUSED)
  {
  }
  
- 
- /* A common function for using free on removing a RETIRED slot.  */
- 
  template <typename Element>
! inline void
! typed_free_remove (Element *retired)
  {
!   free (retired);
  }
  
  
--- 83,132 ----
  }
  
  
  template <typename Element>
! class typed_free_remove
  {
! public:
!   static inline void remove (Element *p) { free (p); }
! };
  
+ template <typename Element>
+ class typed_noop_remove
+ {
+ public:
+   static inline void remove (Element *) {}
+ };
  
  
+ /* Pointer hash.  */
  template <typename Element>
! class pointer_hash : public typed_noop_remove <Element>
  {
! public:
!   typedef Element Element_t;
  
+   static inline hashval_t
+   hash (const Element_t *);
  
!   static inline int
!   equal (const Element_t *existing, const Element_t * candidate);
! };
  
  template <typename Element>
! inline hashval_t
! pointer_hash<Element>::hash (const Element_t *candidate)
  {
+   /* This is a really poor hash function, but it is what the current code uses,
+      so I am reusing it to avoid an additional axis in testing.  */
+   return (hashval_t) ((intptr_t)candidate >> 3);
  }
  
  template <typename Element>
! inline int
! pointer_hash<Element>::equal (const Element_t *existing,
! 			      const Element_t *candidate)
  {
!   return existing == candidate;
  }
  
  
*************** struct hash_table_control
*** 180,194 ****
  
     The table stores elements of type Element.
  
!    It hashes elements with the Hash function.
       The table currently works with relatively weak hash functions.
       Use typed_pointer_hash <Element> when hashing pointers instead of objects.
  
!    It compares elements with the Equal function.
       Two elements with the same hash may not be equal.
       Use typed_pointer_equal <Element> when hashing pointers instead of objects.
  
!    It removes elements with the Remove function.
       This feature is useful for freeing memory.
       Use typed_null_remove <Element> when not freeing objects.
       Use typed_free_remove <Element> when doing a simple object free.
--- 185,199 ----
  
     The table stores elements of type Element.
  
!    It hashes elements with the hash function.
       The table currently works with relatively weak hash functions.
       Use typed_pointer_hash <Element> when hashing pointers instead of objects.
  
!    It compares elements with the equal function.
       Two elements with the same hash may not be equal.
       Use typed_pointer_equal <Element> when hashing pointers instead of objects.
  
!    It removes elements with the remove function.
       This feature is useful for freeing memory.
       Use typed_null_remove <Element> when not freeing objects.
       Use typed_free_remove <Element> when doing a simple object free.
*************** struct hash_table_control
*** 199,243 ****
  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator = xcallocator>
  class hash_table
  {
  
  private:
  
!   hash_table_control <Element> *htab;
! 
!   Element **find_empty_slot_for_expand (hashval_t hash);
    void expand ();
  
  public:
- 
    hash_table ();
    void create (size_t initial_slots);
    bool is_created ();
    void dispose ();
!   Element *find (Element *comparable);
!   Element *find_with_hash (Element *comparable, hashval_t hash);
!   Element **find_slot (Element *comparable, enum insert_option insert);
!   Element **find_slot_with_hash (Element *comparable, hashval_t hash,
! 				 enum insert_option insert);
    void empty ();
!   void clear_slot (Element **slot);
!   void remove_elt (Element *comparable);
!   void remove_elt_with_hash (Element *comparable, hashval_t hash);
    size_t size();
    size_t elements();
    double collisions();
  
    template <typename Argument,
! 	    int (*Callback) (Element **slot, Argument argument)>
    void traverse_noresize (Argument argument);
  
    template <typename Argument,
! 	    int (*Callback) (Element **slot, Argument argument)>
    void traverse (Argument argument);
  };
  
--- 204,245 ----
  */
  
  template <typename Element,
  	  template <typename Type> class Allocator = xcallocator>
  class hash_table
  {
+ public:
+   typedef typename Element::Element_t Element_t;
  
  private:
+   hash_table_control <Element_t> *htab;
  
!   Element_t **find_empty_slot_for_expand (hashval_t hash);
    void expand ();
  
  public:
    hash_table ();
    void create (size_t initial_slots);
    bool is_created ();
    void dispose ();
!   Element_t *find (Element_t *comparable);
!   Element_t *find_with_hash (Element_t *comparable, hashval_t hash);
!   Element_t **find_slot (Element_t *comparable, enum insert_option insert);
!   Element_t **find_slot_with_hash (Element_t *comparable, hashval_t hash,
! 				   enum insert_option insert);
    void empty ();
!   void clear_slot (Element_t **slot);
!   void remove_elt (Element_t *comparable);
!   void remove_elt_with_hash (Element_t *comparable, hashval_t hash);
    size_t size();
    size_t elements();
    double collisions();
  
    template <typename Argument,
! 	    int (*Callback) (Element_t **slot, Argument argument)>
    void traverse_noresize (Argument argument);
  
    template <typename Argument,
! 	    int (*Callback) (Element_t **slot, Argument argument)>
    void traverse (Argument argument);
  };
  
*************** public:
*** 245,256 ****
  /* Construct the hash table.  The only useful operation next is create.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline
! hash_table <Element, Hash, Equal, Remove, Allocator>::hash_table ()
  : htab (NULL)
  {
  }
--- 247,255 ----
  /* Construct the hash table.  The only useful operation next is create.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  inline
! hash_table <Element, Allocator>::hash_table ()
  : htab (NULL)
  {
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 259,270 ****
  /* See if the table has been created, as opposed to constructed.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline bool
! hash_table <Element, Hash, Equal, Remove, Allocator>::is_created ()
  {
    return htab != NULL;
  }
--- 258,266 ----
  /* See if the table has been created, as opposed to constructed.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  inline bool
! hash_table <Element, Allocator>::is_created ()
  {
    return htab != NULL;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 273,328 ****
  /* Like find_with_hash, but compute the hash value from the element.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
! inline Element *
! hash_table <Element, Hash, Equal, Remove, Allocator>::find (Element *comparable)
  {
!   return find_with_hash (comparable, Hash (comparable));
  }
  
  
  /* Like find_slot_with_hash, but compute the hash value from the element.  */
  
  template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
! 	  template <typename Type> class Allocator>
! inline Element **
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::find_slot (Element *comparable, enum insert_option insert)
  {
!   return find_slot_with_hash (comparable, Hash (comparable), insert);
  }
  
  
  /* Like remove_elt_with_hash, but compute the hash value from the element.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline void
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::remove_elt (Element *comparable)
  {
!   remove_elt_with_hash (comparable, Hash (comparable));
  }
  
  
  /* Return the current size of this hash table.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Element, Hash, Equal, Remove, Allocator>::size()
  {
    return htab->size;
  }
--- 269,312 ----
  /* Like find_with_hash, but compute the hash value from the element.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
! inline typename Element::Element_t *
! hash_table <Element, Allocator>::find (Element_t *comparable)
  {
!   return find_with_hash (comparable, Element::hash (comparable));
  }
  
  
  /* Like find_slot_with_hash, but compute the hash value from the element.  */
  
  template <typename Element,
! 	  template <typename Type> class Allocator>
! inline typename Element::Element_t **
! hash_table <Element, Allocator>
! ::find_slot (Element_t *comparable, enum insert_option insert)
  {
!   return find_slot_with_hash (comparable, Element::hash (comparable), insert);
  }
  
  
  /* Like remove_elt_with_hash, but compute the hash value from the element.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  inline void
! hash_table <Element, Allocator>
! ::remove_elt (Element_t *comparable)
  {
!   remove_elt_with_hash (comparable, Element::hash (comparable));
  }
  
  
  /* Return the current size of this hash table.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Element, Allocator>::size()
  {
    return htab->size;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 331,342 ****
  /* Return the current number of elements in this hash table. */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Element, Hash, Equal, Remove, Allocator>::elements()
  {
    return htab->n_elements - htab->n_deleted;
  }
--- 315,323 ----
  /* Return the current number of elements in this hash table. */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Element, Allocator>::elements()
  {
    return htab->n_elements - htab->n_deleted;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 346,357 ****
       hash table. */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline double
! hash_table <Element, Hash, Equal, Remove, Allocator>::collisions()
  {
    if (htab->searches == 0)
      return 0.0;
--- 327,335 ----
       hash table. */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  inline double
! hash_table <Element, Allocator>::collisions()
  {
    if (htab->searches == 0)
      return 0.0;
*************** hash_table <Element, Hash, Equal, Remove
*** 363,383 ****
  /* Create a hash table with at least the given number of INITIAL_SLOTS.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::create (size_t size)
  {
    unsigned int size_prime_index;
  
    size_prime_index = hash_table_higher_prime_index (size);
    size = prime_tab[size_prime_index].prime;
  
!   htab = Allocator <hash_table_control <Element> > ::control_alloc (1);
    gcc_assert (htab != NULL);
!   htab->entries = Allocator <Element*> ::data_alloc (size);
    gcc_assert (htab->entries != NULL);
    htab->size = size;
    htab->size_prime_index = size_prime_index;
--- 341,358 ----
  /* Create a hash table with at least the given number of INITIAL_SLOTS.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Allocator>::create (size_t size)
  {
    unsigned int size_prime_index;
  
    size_prime_index = hash_table_higher_prime_index (size);
    size = prime_tab[size_prime_index].prime;
  
!   htab = Allocator <hash_table_control <Element_t> > ::control_alloc (1);
    gcc_assert (htab != NULL);
!   htab->entries = Allocator <Element_t*> ::data_alloc (size);
    gcc_assert (htab->entries != NULL);
    htab->size = size;
    htab->size_prime_index = size_prime_index;
*************** hash_table <Element, Hash, Equal, Remove
*** 388,432 ****
     the non-created state.  Naturally the hash table must already exist.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::dispose ()
  {
    size_t size = htab->size;
!   Element **entries = htab->entries;
  
    for (int i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Remove (entries[i]);
  
!   Allocator <Element *> ::data_free (entries);
!   Allocator <hash_table_control <Element> > ::control_free (htab);
    htab = NULL;
  }
  
  
  /* Similar to find_slot, but without several unwanted side effects:
!     - Does not call Equal when it finds an existing entry.
      - Does not change the count of elements/searches/collisions in the
        hash table.
     This function also assumes there are no deleted entries in the table.
     HASH is the hash value for the element to be inserted.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
! Element **
! hash_table <Element, Hash, Equal, Remove, Allocator>
  ::find_empty_slot_for_expand (hashval_t hash)
  {
    hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
    size_t size = htab->size;
!   Element **slot = htab->entries + index;
    hashval_t hash2;
  
    if (*slot == HTAB_EMPTY_ENTRY)
--- 363,401 ----
     the non-created state.  Naturally the hash table must already exist.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Allocator>::dispose ()
  {
    size_t size = htab->size;
!   Element_t **entries = htab->entries;
  
    for (int i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Element::remove (entries[i]);
  
!   Allocator <Element_t *> ::data_free (entries);
!   Allocator <hash_table_control <Element_t> > ::control_free (htab);
    htab = NULL;
  }
  
  
  /* Similar to find_slot, but without several unwanted side effects:
!     - Does not call equal when it finds an existing entry.
      - Does not change the count of elements/searches/collisions in the
        hash table.
     This function also assumes there are no deleted entries in the table.
     HASH is the hash value for the element to be inserted.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
! typename Element::Element_t **
! hash_table <Element, Allocator>
  ::find_empty_slot_for_expand (hashval_t hash)
  {
    hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
    size_t size = htab->size;
!   Element_t **slot = htab->entries + index;
    hashval_t hash2;
  
    if (*slot == HTAB_EMPTY_ENTRY)
*************** hash_table <Element, Hash, Equal, Remove
*** 458,474 ****
     will abort.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::expand ()
  {
!   Element **oentries;
!   Element **olimit;
!   Element **p;
!   Element **nentries;
    size_t nsize, osize, elts;
    unsigned int oindex, nindex;
  
--- 427,440 ----
     will abort.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Allocator>::expand ()
  {
!   Element_t **oentries;
!   Element_t **olimit;
!   Element_t **p;
!   Element_t **nentries;
    size_t nsize, osize, elts;
    unsigned int oindex, nindex;
  
*************** hash_table <Element, Hash, Equal, Remove
*** 491,497 ****
        nsize = osize;
      }
  
!   nentries = Allocator <Element *> ::data_alloc (nsize);
    gcc_assert (nentries != NULL);
    htab->entries = nentries;
    htab->size = nsize;
--- 457,463 ----
        nsize = osize;
      }
  
!   nentries = Allocator <Element_t *> ::data_alloc (nsize);
    gcc_assert (nentries != NULL);
    htab->entries = nentries;
    htab->size = nsize;
*************** hash_table <Element, Hash, Equal, Remove
*** 502,512 ****
    p = oentries;
    do
      {
!       Element *x = *p;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          {
!           Element **q = find_empty_slot_for_expand (Hash (x));
  
            *q = x;
          }
--- 468,478 ----
    p = oentries;
    do
      {
!       Element_t *x = *p;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          {
!           Element_t **q = find_empty_slot_for_expand (Element::hash (x));
  
            *q = x;
          }
*************** hash_table <Element, Hash, Equal, Remove
*** 515,521 ****
      }
    while (p < olimit);
  
!   Allocator <Element *> ::data_free (oentries);
  }
  
  
--- 481,487 ----
      }
    while (p < olimit);
  
!   Allocator <Element_t *> ::data_free (oentries);
  }
  
  
*************** hash_table <Element, Hash, Equal, Remove
*** 524,540 ****
     be used to insert or delete an element. */
  
  template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
! 	  template <typename Type> class Allocator>
! Element *
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::find_with_hash (Element *comparable, hashval_t hash)
  {
    hashval_t index, hash2;
    size_t size;
!   Element *entry;
  
    htab->searches++;
    size = htab->size;
--- 490,503 ----
     be used to insert or delete an element. */
  
  template <typename Element,
! 	  template <typename Type> class Allocator>
! typename Element::Element_t *
! hash_table <Element, Allocator>
! ::find_with_hash (Element_t *comparable, hashval_t hash)
  {
    hashval_t index, hash2;
    size_t size;
!   Element_t *entry;
  
    htab->searches++;
    size = htab->size;
*************** hash_table <Element, Hash, Equal, Remove
*** 542,548 ****
  
    entry = htab->entries[index];
    if (entry == HTAB_EMPTY_ENTRY
!       || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
      return entry;
  
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
--- 505,511 ----
  
    entry = htab->entries[index];
    if (entry == HTAB_EMPTY_ENTRY
!       || (entry != HTAB_DELETED_ENTRY && Element::equal (entry, comparable)))
      return entry;
  
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
*************** hash_table <Element, Hash, Equal, Remove
*** 555,561 ****
  
        entry = htab->entries[index];
        if (entry == HTAB_EMPTY_ENTRY
!           || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
          return entry;
      }
  }
--- 518,524 ----
  
        entry = htab->entries[index];
        if (entry == HTAB_EMPTY_ENTRY
!           || (entry != HTAB_DELETED_ENTRY && Element::equal (entry, comparable)))
          return entry;
      }
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 570,588 ****
     entry, NULL may be returned if memory allocation fails. */
  
  template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
! 	  template <typename Type> class Allocator>
! Element **
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::find_slot_with_hash (Element *comparable, hashval_t hash,
  		       enum insert_option insert)
  {
!   Element **first_deleted_slot;
    hashval_t index, hash2;
    size_t size;
!   Element *entry;
  
    size = htab->size;
    if (insert == INSERT && size * 3 <= htab->n_elements * 4)
--- 533,548 ----
     entry, NULL may be returned if memory allocation fails. */
  
  template <typename Element,
! 	  template <typename Type> class Allocator>
! typename Element::Element_t **
! hash_table <Element, Allocator>
! ::find_slot_with_hash (Element_t *comparable, hashval_t hash,
  		       enum insert_option insert)
  {
!   Element_t **first_deleted_slot;
    hashval_t index, hash2;
    size_t size;
!   Element_t *entry;
  
    size = htab->size;
    if (insert == INSERT && size * 3 <= htab->n_elements * 4)
*************** hash_table <Element, Hash, Equal, Remove
*** 601,607 ****
      goto empty_entry;
    else if (entry == HTAB_DELETED_ENTRY)
      first_deleted_slot = &htab->entries[index];
!   else if (Equal (entry, comparable))
      return &htab->entries[index];
        
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
--- 561,567 ----
      goto empty_entry;
    else if (entry == HTAB_DELETED_ENTRY)
      first_deleted_slot = &htab->entries[index];
!   else if (Element::equal (entry, comparable))
      return &htab->entries[index];
        
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
*************** hash_table <Element, Hash, Equal, Remove
*** 620,626 ****
  	  if (!first_deleted_slot)
  	    first_deleted_slot = &htab->entries[index];
  	}
!       else if (Equal (entry, comparable))
  	return &htab->entries[index];
      }
  
--- 580,586 ----
  	  if (!first_deleted_slot)
  	    first_deleted_slot = &htab->entries[index];
  	}
!       else if (Element::equal (entry, comparable))
  	return &htab->entries[index];
      }
  
*************** hash_table <Element, Hash, Equal, Remove
*** 631,637 ****
    if (first_deleted_slot)
      {
        htab->n_deleted--;
!       *first_deleted_slot = static_cast <Element *> (HTAB_EMPTY_ENTRY);
        return first_deleted_slot;
      }
  
--- 591,597 ----
    if (first_deleted_slot)
      {
        htab->n_deleted--;
!       *first_deleted_slot = static_cast <Element_t *> (HTAB_EMPTY_ENTRY);
        return first_deleted_slot;
      }
  
*************** hash_table <Element, Hash, Equal, Remove
*** 643,662 ****
  /* This function clears all entries in the given hash table.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::empty ()
  {
    size_t size = htab_size (htab);
!   Element **entries = htab->entries;
    int i;
  
    for (i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Remove (entries[i]);
  
    /* Instead of clearing megabyte, downsize the table.  */
    if (size > 1024*1024 / sizeof (PTR))
--- 603,619 ----
  /* This function clears all entries in the given hash table.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Allocator>::empty ()
  {
    size_t size = htab_size (htab);
!   Element_t **entries = htab->entries;
    int i;
  
    for (i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Element::remove (entries[i]);
  
    /* Instead of clearing megabyte, downsize the table.  */
    if (size > 1024*1024 / sizeof (PTR))
*************** hash_table <Element, Hash, Equal, Remove
*** 664,676 ****
        int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
        int nsize = prime_tab[nindex].prime;
  
!       Allocator <Element *> ::data_free (htab->entries);
!       htab->entries = Allocator <Element *> ::data_alloc (nsize);
        htab->size = nsize;
        htab->size_prime_index = nindex;
      }
    else
!     memset (entries, 0, size * sizeof (Element *));
    htab->n_deleted = 0;
    htab->n_elements = 0;
  }
--- 621,633 ----
        int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
        int nsize = prime_tab[nindex].prime;
  
!       Allocator <Element_t *> ::data_free (htab->entries);
!       htab->entries = Allocator <Element_t *> ::data_alloc (nsize);
        htab->size = nsize;
        htab->size_prime_index = nindex;
      }
    else
!     memset (entries, 0, size * sizeof (Element_t *));
    htab->n_deleted = 0;
    htab->n_elements = 0;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 681,699 ****
     again. */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::clear_slot (Element **slot)
  {
    if (slot < htab->entries || slot >= htab->entries + htab->size
        || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
      abort ();
  
!   Remove (*slot);
  
    *slot = HTAB_DELETED_ENTRY;
    htab->n_deleted++;
--- 638,653 ----
     again. */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Allocator>
! ::clear_slot (Element_t **slot)
  {
    if (slot < htab->entries || slot >= htab->entries + htab->size
        || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
      abort ();
  
!   Element::remove (*slot);
  
    *slot = HTAB_DELETED_ENTRY;
    htab->n_deleted++;
*************** hash_table <Element, Hash, Equal, Remove
*** 705,727 ****
     matching element in the hash table, this function does nothing. */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::remove_elt_with_hash (Element *comparable, hashval_t hash)
  {
!   Element **slot;
  
    slot = find_slot_with_hash (comparable, hash, NO_INSERT);
    if (*slot == HTAB_EMPTY_ENTRY)
      return;
  
!   Remove (*slot);
  
!   *slot = static_cast <Element *> (HTAB_DELETED_ENTRY);
    htab->n_deleted++;
  }
  
--- 659,678 ----
     matching element in the hash table, this function does nothing. */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Allocator>
! ::remove_elt_with_hash (Element_t *comparable, hashval_t hash)
  {
!   Element_t **slot;
  
    slot = find_slot_with_hash (comparable, hash, NO_INSERT);
    if (*slot == HTAB_EMPTY_ENTRY)
      return;
  
!   Element::remove (*slot);
  
!   *slot = static_cast <Element_t *> (HTAB_DELETED_ENTRY);
    htab->n_deleted++;
  }
  
*************** hash_table <Element, Hash, Equal, Remove
*** 731,755 ****
     ARGUMENT is passed as CALLBACK's second argument. */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (Element **slot, Argument argument)>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
  ::traverse_noresize (Argument argument)
  {
!   Element **slot;
!   Element **limit;
  
    slot = htab->entries;
    limit = slot + htab->size;
  
    do
      {
!       Element *x = *slot;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          if (! Callback (slot, argument))
--- 682,703 ----
     ARGUMENT is passed as CALLBACK's second argument. */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (typename Element::Element_t **slot, Argument argument)>
  void
! hash_table <Element, Allocator>
  ::traverse_noresize (Argument argument)
  {
!   Element_t **slot;
!   Element_t **limit;
  
    slot = htab->entries;
    limit = slot + htab->size;
  
    do
      {
!       Element_t *x = *slot;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          if (! Callback (slot, argument))
*************** hash_table <Element, Hash, Equal, Remove
*** 763,776 ****
     to improve effectivity of subsequent calls.  */
  
  template <typename Element,
- 	  hashval_t (*Hash) (const Element *candidate),
- 	  int (*Equal) (const Element *existing, const Element * candidate),
- 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (Element **slot, Argument argument)>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
  ::traverse (Argument argument)
  {
    size_t size = htab->size;
--- 711,721 ----
     to improve effectivity of subsequent calls.  */
  
  template <typename Element,
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (typename Element::Element_t **slot, Argument argument)>
  void
! hash_table <Element, Allocator>
  ::traverse (Argument argument)
  {
    size_t size = htab->size;
Index: gcc/coverage.c
===================================================================
*** gcc/coverage.c.orig	2012-08-15 15:39:34.000000000 +0200
--- gcc/coverage.c	2012-08-15 16:12:58.471636654 +0200
*************** get_gcov_unsigned_t (void)
*** 143,172 ****
    return lang_hooks.types.type_for_mode (mode, true);
  }
  \f
! inline hashval_t
! coverage_counts_entry_hash (const counts_entry_t *entry)
! {
!   return entry->ident * GCOV_COUNTERS + entry->ctr;
! }
! 
! inline int
! coverage_counts_entry_eq (const counts_entry_t *entry1,
!                           const counts_entry_t *entry2)
! {
!   return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
! }
! 
! inline void
! coverage_counts_entry_del (counts_entry_t *entry)
! {
!   free (entry->counts);
!   free (entry);
! }
  
  /* Hash table of count data.  */
! static hash_table <counts_entry_t, coverage_counts_entry_hash,
! 		   coverage_counts_entry_eq, coverage_counts_entry_del>
! 		  counts_hash;
  
  /* Read in the counts file, if available.  */
  
--- 143,172 ----
    return lang_hooks.types.type_for_mode (mode, true);
  }
  \f
! /* Hash functions for counts_entry.  */
! class counts_entry_hash {
! public:
!   typedef counts_entry_t Element_t;
!   static inline int equal (const counts_entry_t *entry1,
! 			   const counts_entry_t *entry2)
!   {
!     return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
!   }
!   static inline hashval_t
!   hash (const counts_entry_t *entry)
!   {
!     return entry->ident * GCOV_COUNTERS + entry->ctr;
!   }
!   static inline void
!   remove (counts_entry_t *entry)
!   {
!     free (entry->counts);
!     free (entry);
!   }
! };
  
  /* Hash table of count data.  */
! static hash_table <counts_entry_hash> counts_hash;
  
  /* Read in the counts file, if available.  */
  
Index: gcc/tree-ssa-ccp.c
===================================================================
*** gcc/tree-ssa-ccp.c.orig	2012-08-15 10:20:31.000000000 +0200
--- gcc/tree-ssa-ccp.c	2012-08-15 15:45:45.896693215 +0200
*************** evaluate_stmt (gimple stmt)
*** 1688,1697 ****
    return val;
  }
  
! typedef hash_table <gimple_statement_d, typed_pointer_hash<gimple_statement_d>,
! 		    typed_pointer_equal<gimple_statement_d>,
! 		    typed_null_remove<gimple_statement_d> >
! 		   gimple_htab;
  
  /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
     each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
--- 1688,1694 ----
    return val;
  }
  
! typedef hash_table <pointer_hash <gimple_statement_d> > gimple_htab;
  
  /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
     each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
Index: gcc/tree-ssa-coalesce.c
===================================================================
*** gcc/tree-ssa-coalesce.c.orig	2012-08-15 10:20:33.000000000 +0200
--- gcc/tree-ssa-coalesce.c	2012-08-15 16:14:56.051632549 +0200
*************** coalesce_partitions (var_map map, ssa_co
*** 1258,1278 ****
      }
  }
  
! /* Returns a hash code for N.  */
! 
! inline hashval_t
! hash_ssa_name_by_var (const_tree n)
! {
!   return (hashval_t) htab_hash_pointer (SSA_NAME_VAR (n));
! }
! 
! /* Returns nonzero if N1 and N2 are equal.  */
! 
! inline int
! eq_ssa_name_by_var (const_tree n1, const_tree n2)
! {
!   return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
! }
  
  /* Reduce the number of copies by coalescing variables in the function.  Return
     a partition map with the resulting coalesces.  */
--- 1258,1276 ----
      }
  }
  
! /* SSA_NAME_VAR hash.  */
! class ssa_name_var_hash : public typed_noop_remove <union tree_node> {
! public:
!   typedef union tree_node Element_t;
!   static inline hashval_t hash (const_tree n)
!   {
!     return DECL_UID (SSA_NAME_VAR (n));
!   }
!   static inline int equal (const_tree n1, const_tree n2)
!   {
!     return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
!   }
! };
  
  /* Reduce the number of copies by coalescing variables in the function.  Return
     a partition map with the resulting coalesces.  */
*************** coalesce_ssa_name (void)
*** 1286,1294 ****
    bitmap used_in_copies = BITMAP_ALLOC (NULL);
    var_map map;
    unsigned int i;
!   static hash_table <tree_node, hash_ssa_name_by_var, eq_ssa_name_by_var,
! 		     typed_null_remove<tree_node> >
! 		    ssa_name_hash;
  
    cl = create_coalesce_list ();
    map = create_outofssa_var_map (cl, used_in_copies);
--- 1284,1290 ----
    bitmap used_in_copies = BITMAP_ALLOC (NULL);
    var_map map;
    unsigned int i;
!   static hash_table <ssa_name_var_hash> ssa_name_hash;
  
    cl = create_coalesce_list ();
    map = create_outofssa_var_map (cl, used_in_copies);
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig	2012-08-15 10:20:33.000000000 +0200
--- gcc/tree-ssa-pre.c	2012-08-15 16:16:11.339629977 +0200
*************** static unsigned int next_expression_id;
*** 229,237 ****
  DEF_VEC_P (pre_expr);
  DEF_VEC_ALLOC_P (pre_expr, heap);
  static VEC(pre_expr, heap) *expressions;
! static hash_table <pre_expr_d, ssa_pre_expr_hash, ssa_pre_expr_eq,
! 		   typed_null_remove <pre_expr_d> >
! 		  expression_to_id;
  static VEC(unsigned, heap) *name_to_id;
  
  /* Allocate an expression id for EXPR.  */
--- 229,247 ----
  DEF_VEC_P (pre_expr);
  DEF_VEC_ALLOC_P (pre_expr, heap);
  static VEC(pre_expr, heap) *expressions;
! struct pre_expr_hash : public typed_noop_remove <pre_expr_d> {
!   typedef pre_expr_d Element_t;
!   static inline hashval_t hash (const struct pre_expr_d *e)
!   {
!     return ssa_pre_expr_hash (e);
!   }
!   static inline int equal (const struct pre_expr_d *e1,
! 			   const struct pre_expr_d *e2)
!   {
!     return ssa_pre_expr_eq (e1, e2);
!   }
! };
! static hash_table <pre_expr_hash> expression_to_id;
  static VEC(unsigned, heap) *name_to_id;
  
  /* Allocate an expression id for EXPR.  */
*************** typedef struct expr_pred_trans_d
*** 500,537 ****
  } *expr_pred_trans_t;
  typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
  
- /* Return the hash value for a phi translation table entry.  */
- 
- inline hashval_t
- ssa_expr_pred_trans_hash (const expr_pred_trans_d *ve)
- {
-   return ve->hashcode;
- }
- 
- /* Return true if two phi translation table entries are the same.
-    P1 and P2 should point to the expr_pred_trans_t's to be compared.*/
- 
- inline int
- ssa_expr_pred_trans_eq (const expr_pred_trans_d *ve1,
- 			const expr_pred_trans_d *ve2)
- {
-   basic_block b1 = ve1->pred;
-   basic_block b2 = ve2->pred;
- 
-   /* If they are not translations for the same basic block, they can't
-      be equal.  */
-   if (b1 != b2)
-     return false;
-   return ssa_pre_expr_eq (ve1->e, ve2->e);
- }
- 
  /* The phi_translate_table caches phi translations for a given
     expression and predecessor.  */
! 
! static hash_table <expr_pred_trans_d, ssa_expr_pred_trans_hash,
! 		   ssa_expr_pred_trans_eq,
! 		   typed_free_remove <expr_pred_trans_d> >
! 		  phi_translate_table;
  
  /* Search in the phi translation table for the translation of
     expression E in basic block PRED.
--- 510,537 ----
  } *expr_pred_trans_t;
  typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
  
  /* The phi_translate_table caches phi translations for a given
     expression and predecessor.  */
! struct expr_pred_trans_hash : public typed_free_remove<expr_pred_trans_d>
! {
!   typedef expr_pred_trans_d Element_t;
!   static inline hashval_t hash (const Element_t *e)
!   {
!     return e->hashcode;
!   }
!   static inline int equal (const Element_t *ve1, const Element_t *ve2)
!   {
!     basic_block b1 = ve1->pred;
!     basic_block b2 = ve2->pred;
! 
!     /* If they are not translations for the same basic block, they can't
!        be equal.  */
!     if (b1 != b2)
!       return false;
!     return ssa_pre_expr_eq (ve1->e, ve2->e);
!   }
! };
! static hash_table <expr_pred_trans_hash> phi_translate_table;
  
  /* Search in the phi translation table for the translation of
     expression E in basic block PRED.
Index: gcc/tree-ssa-tail-merge.c
===================================================================
*** gcc/tree-ssa-tail-merge.c.orig	2012-08-15 10:20:26.000000000 +0200
--- gcc/tree-ssa-tail-merge.c	2012-08-15 16:24:46.219612235 +0200
*************** stmt_update_dep_bb (gimple stmt)
*** 415,422 ****
  
  /* Calculates hash value for same_succ VE.  */
  
! hashval_t
! ssa_same_succ_hash (const_same_succ e)
  {
    hashval_t hashval = bitmap_hash (e->succs);
    int flags;
--- 415,422 ----
  
  /* Calculates hash value for same_succ VE.  */
  
! static hashval_t
! same_succ_hash (const_same_succ e)
  {
    hashval_t hashval = bitmap_hash (e->succs);
    int flags;
*************** inverse_flags (const_same_succ e1, const
*** 511,520 ****
    return (f1a & mask) == (f2a & mask) && (f1b & mask) == (f2b & mask);
  }
  
  /* Compares SAME_SUCCs VE1 and VE2.  */
  
  int
! ssa_same_succ_equal (const_same_succ e1, const_same_succ e2)
  {
    unsigned int i, first1, first2;
    gimple_stmt_iterator gsi1, gsi2;
--- 511,572 ----
    return (f1a & mask) == (f2a & mask) && (f1b & mask) == (f2b & mask);
  }
  
+ /* Alloc and init a new SAME_SUCC.  */
+ 
+ static same_succ
+ same_succ_alloc (void)
+ {
+   same_succ same = XNEW (struct same_succ_def);
+ 
+   same->bbs = BITMAP_ALLOC (NULL);
+   same->succs = BITMAP_ALLOC (NULL);
+   same->inverse = BITMAP_ALLOC (NULL);
+   same->succ_flags = VEC_alloc (int, heap, 10);
+   same->in_worklist = false;
+ 
+   return same;
+ }
+ 
+ /* Delete same_succ VE.  */
+ 
+ static inline void
+ same_succ_delete (same_succ e)
+ {
+   BITMAP_FREE (e->bbs);
+   BITMAP_FREE (e->succs);
+   BITMAP_FREE (e->inverse);
+   VEC_free (int, heap, e->succ_flags);
+ 
+   XDELETE (e);
+ }
+ 
+ /* Reset same_succ SAME.  */
+ 
+ static void
+ same_succ_reset (same_succ same)
+ {
+   bitmap_clear (same->bbs);
+   bitmap_clear (same->succs);
+   bitmap_clear (same->inverse);
+   VEC_truncate (int, same->succ_flags, 0);
+ }
+ 
+ /* Hash table with all same_succ entries.  */
+ 
+ struct same_succ_hashtable {
+   typedef same_succ_def Element_t;
+   static inline hashval_t hash (const same_succ_def *e) { return e->hashval; }
+   static int equal (const_same_succ, const_same_succ);
+   static inline void remove (Element_t *e1)
+   {
+     same_succ_delete (e1);
+   }
+ };
+ 
  /* Compares SAME_SUCCs VE1 and VE2.  */
  
  int
! same_succ_hashtable::equal (const_same_succ e1, const_same_succ e2)
  {
    unsigned int i, first1, first2;
    gimple_stmt_iterator gsi1, gsi2;
*************** ssa_same_succ_equal (const_same_succ e1,
*** 568,618 ****
    return 1;
  }
  
! /* Alloc and init a new SAME_SUCC.  */
! 
! static same_succ
! same_succ_alloc (void)
! {
!   same_succ same = XNEW (struct same_succ_def);
! 
!   same->bbs = BITMAP_ALLOC (NULL);
!   same->succs = BITMAP_ALLOC (NULL);
!   same->inverse = BITMAP_ALLOC (NULL);
!   same->succ_flags = VEC_alloc (int, heap, 10);
!   same->in_worklist = false;
! 
!   return same;
! }
! 
! /* Delete same_succ VE.  */
! 
! inline void
! ssa_same_succ_delete (same_succ e)
! {
!   BITMAP_FREE (e->bbs);
!   BITMAP_FREE (e->succs);
!   BITMAP_FREE (e->inverse);
!   VEC_free (int, heap, e->succ_flags);
! 
!   XDELETE (e);
! }
! 
! /* Reset same_succ SAME.  */
! 
! static void
! same_succ_reset (same_succ same)
! {
!   bitmap_clear (same->bbs);
!   bitmap_clear (same->succs);
!   bitmap_clear (same->inverse);
!   VEC_truncate (int, same->succ_flags, 0);
! }
! 
! /* Hash table with all same_succ entries.  */
! 
! static hash_table <struct same_succ_def, ssa_same_succ_hash,
! 		   ssa_same_succ_equal, ssa_same_succ_delete>
! 		  same_succ_htab;
  
  /* Array that is used to store the edge flags for a successor.  */
  
--- 620,626 ----
    return 1;
  }
  
! static hash_table <same_succ_hashtable> same_succ_htab;
  
  /* Array that is used to store the edge flags for a successor.  */
  
*************** find_same_succ_bb (basic_block bb, same_
*** 692,698 ****
    EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
      VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
  
!   same->hashval = ssa_same_succ_hash (same);
  
    slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
    if (*slot == NULL)
--- 700,706 ----
    EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
      VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
  
!   same->hashval = same_succ_hash (same);
  
    slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
    if (*slot == NULL)
*************** find_same_succ (void)
*** 728,734 ****
  	same = same_succ_alloc ();
      }
  
!   ssa_same_succ_delete (same);
  }
  
  /* Initializes worklist administration.  */
--- 736,742 ----
  	same = same_succ_alloc ();
      }
  
!   same_succ_delete (same);
  }
  
  /* Initializes worklist administration.  */
*************** update_worklist (void)
*** 860,866 ****
        if (same == NULL)
  	same = same_succ_alloc ();
      }
!   ssa_same_succ_delete (same);
    bitmap_clear (deleted_bb_preds);
  }
  
--- 868,874 ----
        if (same == NULL)
  	same = same_succ_alloc ();
      }
!   same_succ_delete (same);
    bitmap_clear (deleted_bb_preds);
  }
  
Index: gcc/tree-ssa-threadupdate.c
===================================================================
*** gcc/tree-ssa-threadupdate.c.orig	2012-08-15 10:20:26.000000000 +0200
--- gcc/tree-ssa-threadupdate.c	2012-08-15 16:27:19.144606857 +0200
*************** create_block_for_threading (basic_block
*** 218,248 ****
  }
  
  /* Hashing and equality routines for our hash table.  */
- inline hashval_t
- ssa_redirection_data_hash (const struct redirection_data *p)
- {
-   edge e = p->outgoing_edge;
-   return e->dest->index;
- }
  
! inline int
! ssa_redirection_data_eq (const struct redirection_data *p1,
! 			 const struct redirection_data *p2)
  {
!   edge e1 = p1->outgoing_edge;
!   edge e2 = p2->outgoing_edge;
!   edge e3 = p1->intermediate_edge;
!   edge e4 = p2->intermediate_edge;
! 
!   return e1 == e2 && e3 == e4;
! }
  
  /* Main data structure to hold information for duplicates of BB.  */
  
! static hash_table <struct redirection_data, ssa_redirection_data_hash,
! 		   ssa_redirection_data_eq,
! 		   typed_free_remove<struct redirection_data> >
! 		  redirection_data;
  
  /* Given an outgoing edge E lookup and return its entry in our hash table.
  
--- 218,251 ----
  }
  
  /* Hashing and equality routines for our hash table.  */
  
! struct ssa_redirection_data_hash
!   : public typed_free_remove<struct redirection_data>
  {
!   typedef redirection_data Element_t;
!   static inline hashval_t
!   hash (const struct redirection_data *p)
!   {
!     edge e = p->outgoing_edge;
!     return e->dest->index;
!   }
! 
!   static inline int
!   equal (const struct redirection_data *p1,
!          const struct redirection_data *p2)
!   {
!     edge e1 = p1->outgoing_edge;
!     edge e2 = p2->outgoing_edge;
!     edge e3 = p1->intermediate_edge;
!     edge e4 = p2->intermediate_edge;
! 
!     return e1 == e2 && e3 == e4;
!   }
! };
  
  /* Main data structure to hold information for duplicates of BB.  */
  
! static hash_table <ssa_redirection_data_hash> redirection_data;
  
  /* Given an outgoing edge E lookup and return its entry in our hash table.
  

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 14:32       ` Richard Guenther
@ 2012-08-15 16:17         ` Richard Henderson
  2012-08-15 21:58           ` Lawrence Crowl
  2012-09-25 23:19           ` Lawrence Crowl
  2012-08-15 21:57         ` Lawrence Crowl
  1 sibling, 2 replies; 29+ messages in thread
From: Richard Henderson @ 2012-08-15 16:17 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Michael Matz, Diego Novillo, gcc-patches, crowl

On 2012-08-15 07:29, Richard Guenther wrote:
> +   typedef typename Element::Element_t Element_t;

Can we use something less ugly than Element_t?
Such as

  typedef typename Element::T T;

?  Given that this name is scoped anyway...

r~

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 13:00 ` Richard Guenther
  2012-08-15 13:41   ` Richard Guenther
@ 2012-08-15 21:52   ` Lawrence Crowl
  1 sibling, 0 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-08-15 21:52 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Diego Novillo, gcc-patches, Richard Henderson

On 8/15/12, Richard Guenther <rguenther@suse.de> wrote:
> On Sun, 12 Aug 2012, Diego Novillo wrote:
> > This implements a new C++ hash table.
> >
> > See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for
> > details.
>
> Now as we see the result I'd have prefered a more C++-way instead
> of making the conversion simple ...
>
> Like
>
> template <typename Element>
> class hash_table
> {
> ...
> };
>
> template <typename Element>
> class pointer_hash
> {
>   hashval_t hash ();
>   int equal (const Element *);
>   ~Element ();
>   Element e;
> };
>
> and
>
> /* Hash table with all same_succ entries.  */
>
> static hash_table <pointer_hash <struct same_succ_def> > same_succ_htab;
>
> The existing way is simply too ugly ... so, why did you not invent
> a "nice" C++ way?  (please consider reverting the hashtable patch)

We are trying to balance several factors.  Sometimes we're going
to pick multiple steps rather than a single step.  In some cases,
as here, the intent was to make the client code changes minimal and
unsurprising while still getting the type safety and efficiency.
Other times, it may be a minor technical issue.  In particular,
I prefer to avoid steps that might cause very poor matching of
lines in the diff.  Others may choose differently.  Together we
will learn where the tradeoffs lie.

More in a later response.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 14:32       ` Richard Guenther
  2012-08-15 16:17         ` Richard Henderson
@ 2012-08-15 21:57         ` Lawrence Crowl
  1 sibling, 0 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-08-15 21:57 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Michael Matz, Diego Novillo, gcc-patches, Richard Henderson

On 8/15/12, Richard Guenther <rguenther@suse.de> wrote:
> On Wed, 15 Aug 2012, Michael Matz wrote:
> > On Wed, 15 Aug 2012, Richard Guenther wrote:
> > > Like the following, only the coverage.c use is converted.
> > > I've never seen template function arguments anywhere and
> > > having to repeat them all
> > >
> > > over the place is really really ugly (yes, even if only in
> > > the implementation).
> > >
> > > This goes with static member functions and not wrapping any
> > > data. It goes away with the requirement of having externally
> > > visible global functions for the hash/compare functions as well
> > > (which was ugly anyway).
> >
> > Well, it looks nicer than what's there currently.  As the
> > element functions now are scoped and normal member functions,
> > they should be named with lower case characters of course.  I do
> > like that the hash table would then only have one real template
> > argument; the Allocator, well, no better idea comes to my mind.
>
> Yeah.  Updated patch below, all users converted.  I probably
> missed to revert some of the globalizations of hash/compare fns.

Your conversion is a better abstraction, and something I'd wanted
to get to eventually, so I support your conversion.

BTW, the conding conventions say to put member function definitions
out of line.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 16:17         ` Richard Henderson
@ 2012-08-15 21:58           ` Lawrence Crowl
  2012-08-15 22:26             ` Ian Lance Taylor
  2012-08-16  9:22             ` Richard Guenther
  2012-09-25 23:19           ` Lawrence Crowl
  1 sibling, 2 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-08-15 21:58 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Richard Guenther, Michael Matz, Diego Novillo, gcc-patches

On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
> On 2012-08-15 07:29, Richard Guenther wrote:
>> +   typedef typename Element::Element_t Element_t;
>
> Can we use something less ugly than Element_t?
> Such as
>
>   typedef typename Element::T T;
>
> ?  Given that this name is scoped anyway...

I do not much like _t names either.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 21:58           ` Lawrence Crowl
@ 2012-08-15 22:26             ` Ian Lance Taylor
  2012-08-16  9:22             ` Richard Guenther
  1 sibling, 0 replies; 29+ messages in thread
From: Ian Lance Taylor @ 2012-08-15 22:26 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Richard Henderson, Richard Guenther, Michael Matz, Diego Novillo,
	gcc-patches

On Wed, Aug 15, 2012 at 2:58 PM, Lawrence Crowl <crowl@google.com> wrote:
>
> I do not much like _t names either.

Also, names ending in _t are reserved by POSIX if you #include
<sys/types.h>.  Though that may only apply to global names, not to
types defined in classes or namespaces.

Ian

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 21:58           ` Lawrence Crowl
  2012-08-15 22:26             ` Ian Lance Taylor
@ 2012-08-16  9:22             ` Richard Guenther
  2012-08-16 14:56               ` Paolo Carlini
  2012-08-16 19:02               ` Lawrence Crowl
  1 sibling, 2 replies; 29+ messages in thread
From: Richard Guenther @ 2012-08-16  9:22 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Richard Henderson, Michael Matz, Diego Novillo, gcc-patches

On Wed, 15 Aug 2012, Lawrence Crowl wrote:

> On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
> > On 2012-08-15 07:29, Richard Guenther wrote:
> >> +   typedef typename Element::Element_t Element_t;
> >
> > Can we use something less ugly than Element_t?
> > Such as
> >
> >   typedef typename Element::T T;
> >
> > ?  Given that this name is scoped anyway...
> 
> I do not much like _t names either.

The following is what I'm testing now, it also integrates the
hashtable support functions and typedef within the existing local
data types which is IMHO cleaner.  (it also shows we can do with
a janitorial cleanup replacing typedef struct foo_d {} foo; with
struct foo {}; and the likes)

Bootstrap and regtest ongoing on x86_64-unknown-linux-gnu, ok?

Thanks,
Richard.

2012-08-16  Richard Guenther  <rguenther@suse.de>

	* hash-table.h (class hash_table): Use a descriptor template
	argument instead of decomposed element type and support
	functions.
	(struct pointer_hash): New generic typed pointer-hash.
	(struct typed_free_remove, struct typed_noop_remove): Generic
	hash_table support pieces.
	* coverage.c (struct counts_entry): Add hash_table support
	members.
	* tree-ssa-ccp.c (gimple_htab): Use pointer_hash.
	* tree-ssa-coalesce.c (struct ssa_name_var_hash): New generic
	SSA name by SSA_NAME_VAR hash.
	(coalesce_ssa_name): Use it.
	* tree-ssa-pre.c (struct pre_expr_d): Add hash_table support.
	(expression_to_id): Adjust.
	(struct expr_pred_trans_d): Add hash_table support.
	(phi_translate_table): Adjust.
	(phi_trans_lookup): Likewise.
	(phi_trans_add): Likewise.
	(do_regular_insertion): Likewise.
	* tree-ssa-tail-merge.c (struct same_succ_def): Add hash_table
	support.
	(same_succ_htab): Adjust.
	(find_same_succ_bb): Likewise.
	(find_same_succ): Likewise.
	(update_worklist): Likewise.
	* tree-ssa-threadupdate.c (struct redirection_data): Add hash_table
	support.
	(redirection_data): Adjust.

Index: gcc/hash-table.h
===================================================================
*** gcc/hash-table.h.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/hash-table.h	2012-08-16 11:08:36.311277498 +0200
*************** xcallocator <Type>::data_free (Type *mem
*** 83,127 ****
  }
  
  
! /* A common function for hashing a CANDIDATE typed pointer.  */
  
  template <typename Element>
! inline hashval_t
! typed_pointer_hash (const Element *candidate)
  {
!   /* This is a really poor hash function, but it is what the current code uses,
!      so I am reusing it to avoid an additional axis in testing.  */
!   return (hashval_t) ((intptr_t)candidate >> 3);
! }
! 
  
! /* A common function for comparing an EXISTING and CANDIDATE typed pointers
!    for equality. */
  
  template <typename Element>
! inline int
! typed_pointer_equal (const Element *existing, const Element * candidate)
  {
!   return existing == candidate;
! }
  
  
! /* A common function for doing nothing on removing a RETIRED slot.  */
  
  template <typename Element>
! inline void
! typed_null_remove (Element *retired ATTRIBUTE_UNUSED)
  {
! }
  
  
! /* A common function for using free on removing a RETIRED slot.  */
  
  template <typename Element>
! inline void
! typed_free_remove (Element *retired)
  {
!   free (retired);
  }
  
  
--- 83,134 ----
  }
  
  
! /* Remove method dispatching to free.  */
  
  template <typename Element>
! struct typed_free_remove
  {
!   static inline void remove (Element *p) { free (p); }
! };
  
! /* No-op remove method.  */
  
  template <typename Element>
! struct typed_noop_remove
  {
!   static inline void remove (Element *) {}
! };
  
  
! /* Pointer hash with a no-op remove method.  */
  
  template <typename Element>
! struct pointer_hash : typed_noop_remove <Element>
  {
!   typedef Element T;
  
+   static inline hashval_t
+   hash (const T *);
  
!   static inline int
!   equal (const T *existing, const T * candidate);
! };
  
  template <typename Element>
! inline hashval_t
! pointer_hash<Element>::hash (const T *candidate)
  {
!   /* This is a really poor hash function, but it is what the current code uses,
!      so I am reusing it to avoid an additional axis in testing.  */
!   return (hashval_t) ((intptr_t)candidate >> 3);
! }
! 
! template <typename Element>
! inline int
! pointer_hash<Element>::equal (const T *existing,
! 			      const T *candidate)
! {
!   return existing == candidate;
  }
  
  
*************** extern hashval_t hash_table_mod2 (hashva
*** 147,157 ****
  
  /* Internal implementation type.  */
  
! template <typename Element>
  struct hash_table_control
  {
    /* Table itself.  */
!   Element **entries;
  
    /* Current size (in entries) of the hash table.  */
    size_t size;
--- 154,164 ----
  
  /* Internal implementation type.  */
  
! template <typename T>
  struct hash_table_control
  {
    /* Table itself.  */
!   T **entries;
  
    /* Current size (in entries) of the hash table.  */
    size_t size;
*************** struct hash_table_control
*** 180,194 ****
  
     The table stores elements of type Element.
  
!    It hashes elements with the Hash function.
       The table currently works with relatively weak hash functions.
       Use typed_pointer_hash <Element> when hashing pointers instead of objects.
  
!    It compares elements with the Equal function.
       Two elements with the same hash may not be equal.
       Use typed_pointer_equal <Element> when hashing pointers instead of objects.
  
!    It removes elements with the Remove function.
       This feature is useful for freeing memory.
       Use typed_null_remove <Element> when not freeing objects.
       Use typed_free_remove <Element> when doing a simple object free.
--- 187,201 ----
  
     The table stores elements of type Element.
  
!    It hashes elements with the hash function.
       The table currently works with relatively weak hash functions.
       Use typed_pointer_hash <Element> when hashing pointers instead of objects.
  
!    It compares elements with the equal function.
       Two elements with the same hash may not be equal.
       Use typed_pointer_equal <Element> when hashing pointers instead of objects.
  
!    It removes elements with the remove function.
       This feature is useful for freeing memory.
       Use typed_null_remove <Element> when not freeing objects.
       Use typed_free_remove <Element> when doing a simple object free.
*************** struct hash_table_control
*** 198,256 ****
  
  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator = xcallocator>
  class hash_table
  {
  
  private:
  
!   hash_table_control <Element> *htab;
! 
!   Element **find_empty_slot_for_expand (hashval_t hash);
    void expand ();
  
  public:
- 
    hash_table ();
    void create (size_t initial_slots);
    bool is_created ();
    void dispose ();
!   Element *find (Element *comparable);
!   Element *find_with_hash (Element *comparable, hashval_t hash);
!   Element **find_slot (Element *comparable, enum insert_option insert);
!   Element **find_slot_with_hash (Element *comparable, hashval_t hash,
! 				 enum insert_option insert);
    void empty ();
!   void clear_slot (Element **slot);
!   void remove_elt (Element *comparable);
!   void remove_elt_with_hash (Element *comparable, hashval_t hash);
    size_t size();
    size_t elements();
    double collisions();
  
    template <typename Argument,
! 	    int (*Callback) (Element **slot, Argument argument)>
    void traverse_noresize (Argument argument);
  
    template <typename Argument,
! 	    int (*Callback) (Element **slot, Argument argument)>
    void traverse (Argument argument);
  };
  
  
  /* Construct the hash table.  The only useful operation next is create.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline
! hash_table <Element, Hash, Equal, Remove, Allocator>::hash_table ()
  : htab (NULL)
  {
  }
--- 205,257 ----
  
  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator = xcallocator>
  class hash_table
  {
+ public:
+   typedef typename Descr::T T;
  
  private:
+   hash_table_control <T> *htab;
  
!   T **find_empty_slot_for_expand (hashval_t hash);
    void expand ();
  
  public:
    hash_table ();
    void create (size_t initial_slots);
    bool is_created ();
    void dispose ();
!   T *find (T *comparable);
!   T *find_with_hash (T *comparable, hashval_t hash);
!   T **find_slot (T *comparable, enum insert_option insert);
!   T **find_slot_with_hash (T *comparable, hashval_t hash,
! 				   enum insert_option insert);
    void empty ();
!   void clear_slot (T **slot);
!   void remove_elt (T *comparable);
!   void remove_elt_with_hash (T *comparable, hashval_t hash);
    size_t size();
    size_t elements();
    double collisions();
  
    template <typename Argument,
! 	    int (*Callback) (T **slot, Argument argument)>
    void traverse_noresize (Argument argument);
  
    template <typename Argument,
! 	    int (*Callback) (T **slot, Argument argument)>
    void traverse (Argument argument);
  };
  
  
  /* Construct the hash table.  The only useful operation next is create.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  inline
! hash_table <Descr, Allocator>::hash_table ()
  : htab (NULL)
  {
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 258,270 ****
  
  /* See if the table has been created, as opposed to constructed.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline bool
! hash_table <Element, Hash, Equal, Remove, Allocator>::is_created ()
  {
    return htab != NULL;
  }
--- 259,268 ----
  
  /* See if the table has been created, as opposed to constructed.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  inline bool
! hash_table <Descr, Allocator>::is_created ()
  {
    return htab != NULL;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 272,328 ****
  
  /* Like find_with_hash, but compute the hash value from the element.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
! inline Element *
! hash_table <Element, Hash, Equal, Remove, Allocator>::find (Element *comparable)
  {
!   return find_with_hash (comparable, Hash (comparable));
  }
  
  
  /* Like find_slot_with_hash, but compute the hash value from the element.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
! 	  template <typename Type> class Allocator>
! inline Element **
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::find_slot (Element *comparable, enum insert_option insert)
  {
!   return find_slot_with_hash (comparable, Hash (comparable), insert);
  }
  
  
  /* Like remove_elt_with_hash, but compute the hash value from the element.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline void
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::remove_elt (Element *comparable)
  {
!   remove_elt_with_hash (comparable, Hash (comparable));
  }
  
  
  /* Return the current size of this hash table.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Element, Hash, Equal, Remove, Allocator>::size()
  {
    return htab->size;
  }
--- 270,314 ----
  
  /* Like find_with_hash, but compute the hash value from the element.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
! inline typename Descr::T *
! hash_table <Descr, Allocator>::find (T *comparable)
  {
!   return find_with_hash (comparable, Descr::hash (comparable));
  }
  
  
  /* Like find_slot_with_hash, but compute the hash value from the element.  */
  
! template <typename Descr,
! 	  template <typename Type> class Allocator>
! inline typename Descr::T **
! hash_table <Descr, Allocator>
! ::find_slot (T *comparable, enum insert_option insert)
  {
!   return find_slot_with_hash (comparable, Descr::hash (comparable), insert);
  }
  
  
  /* Like remove_elt_with_hash, but compute the hash value from the element.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  inline void
! hash_table <Descr, Allocator>
! ::remove_elt (T *comparable)
  {
!   remove_elt_with_hash (comparable, Descr::hash (comparable));
  }
  
  
  /* Return the current size of this hash table.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Descr, Allocator>::size()
  {
    return htab->size;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 330,342 ****
  
  /* Return the current number of elements in this hash table. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Element, Hash, Equal, Remove, Allocator>::elements()
  {
    return htab->n_elements - htab->n_deleted;
  }
--- 316,325 ----
  
  /* Return the current number of elements in this hash table. */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  inline size_t
! hash_table <Descr, Allocator>::elements()
  {
    return htab->n_elements - htab->n_deleted;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 345,357 ****
    /* Return the fraction of fixed collisions during all work with given
       hash table. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  inline double
! hash_table <Element, Hash, Equal, Remove, Allocator>::collisions()
  {
    if (htab->searches == 0)
      return 0.0;
--- 328,337 ----
    /* Return the fraction of fixed collisions during all work with given
       hash table. */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  inline double
! hash_table <Descr, Allocator>::collisions()
  {
    if (htab->searches == 0)
      return 0.0;
*************** hash_table <Element, Hash, Equal, Remove
*** 362,383 ****
  
  /* Create a hash table with at least the given number of INITIAL_SLOTS.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::create (size_t size)
  {
    unsigned int size_prime_index;
  
    size_prime_index = hash_table_higher_prime_index (size);
    size = prime_tab[size_prime_index].prime;
  
!   htab = Allocator <hash_table_control <Element> > ::control_alloc (1);
    gcc_assert (htab != NULL);
!   htab->entries = Allocator <Element*> ::data_alloc (size);
    gcc_assert (htab->entries != NULL);
    htab->size = size;
    htab->size_prime_index = size_prime_index;
--- 342,360 ----
  
  /* Create a hash table with at least the given number of INITIAL_SLOTS.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  void
! hash_table <Descr, Allocator>::create (size_t size)
  {
    unsigned int size_prime_index;
  
    size_prime_index = hash_table_higher_prime_index (size);
    size = prime_tab[size_prime_index].prime;
  
!   htab = Allocator <hash_table_control <T> > ::control_alloc (1);
    gcc_assert (htab != NULL);
!   htab->entries = Allocator <T*> ::data_alloc (size);
    gcc_assert (htab->entries != NULL);
    htab->size = size;
    htab->size_prime_index = size_prime_index;
*************** hash_table <Element, Hash, Equal, Remove
*** 387,432 ****
  /* Dispose of a hash table.  Free all memory and return this hash table to
     the non-created state.  Naturally the hash table must already exist.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::dispose ()
  {
    size_t size = htab->size;
!   Element **entries = htab->entries;
  
    for (int i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Remove (entries[i]);
  
!   Allocator <Element *> ::data_free (entries);
!   Allocator <hash_table_control <Element> > ::control_free (htab);
    htab = NULL;
  }
  
  
  /* Similar to find_slot, but without several unwanted side effects:
!     - Does not call Equal when it finds an existing entry.
      - Does not change the count of elements/searches/collisions in the
        hash table.
     This function also assumes there are no deleted entries in the table.
     HASH is the hash value for the element to be inserted.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
! Element **
! hash_table <Element, Hash, Equal, Remove, Allocator>
  ::find_empty_slot_for_expand (hashval_t hash)
  {
    hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
    size_t size = htab->size;
!   Element **slot = htab->entries + index;
    hashval_t hash2;
  
    if (*slot == HTAB_EMPTY_ENTRY)
--- 364,403 ----
  /* Dispose of a hash table.  Free all memory and return this hash table to
     the non-created state.  Naturally the hash table must already exist.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  void
! hash_table <Descr, Allocator>::dispose ()
  {
    size_t size = htab->size;
!   T **entries = htab->entries;
  
    for (int i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Descr::remove (entries[i]);
  
!   Allocator <T *> ::data_free (entries);
!   Allocator <hash_table_control <T> > ::control_free (htab);
    htab = NULL;
  }
  
  
  /* Similar to find_slot, but without several unwanted side effects:
!     - Does not call equal when it finds an existing entry.
      - Does not change the count of elements/searches/collisions in the
        hash table.
     This function also assumes there are no deleted entries in the table.
     HASH is the hash value for the element to be inserted.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
! typename Descr::T **
! hash_table <Descr, Allocator>
  ::find_empty_slot_for_expand (hashval_t hash)
  {
    hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
    size_t size = htab->size;
!   T **slot = htab->entries + index;
    hashval_t hash2;
  
    if (*slot == HTAB_EMPTY_ENTRY)
*************** hash_table <Element, Hash, Equal, Remove
*** 457,474 ****
     table entries is changed.  If memory allocation fails, this function
     will abort.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::expand ()
  {
!   Element **oentries;
!   Element **olimit;
!   Element **p;
!   Element **nentries;
    size_t nsize, osize, elts;
    unsigned int oindex, nindex;
  
--- 428,442 ----
     table entries is changed.  If memory allocation fails, this function
     will abort.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  void
! hash_table <Descr, Allocator>::expand ()
  {
!   T **oentries;
!   T **olimit;
!   T **p;
!   T **nentries;
    size_t nsize, osize, elts;
    unsigned int oindex, nindex;
  
*************** hash_table <Element, Hash, Equal, Remove
*** 491,497 ****
        nsize = osize;
      }
  
!   nentries = Allocator <Element *> ::data_alloc (nsize);
    gcc_assert (nentries != NULL);
    htab->entries = nentries;
    htab->size = nsize;
--- 459,465 ----
        nsize = osize;
      }
  
!   nentries = Allocator <T *> ::data_alloc (nsize);
    gcc_assert (nentries != NULL);
    htab->entries = nentries;
    htab->size = nsize;
*************** hash_table <Element, Hash, Equal, Remove
*** 502,512 ****
    p = oentries;
    do
      {
!       Element *x = *p;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          {
!           Element **q = find_empty_slot_for_expand (Hash (x));
  
            *q = x;
          }
--- 470,480 ----
    p = oentries;
    do
      {
!       T *x = *p;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          {
!           T **q = find_empty_slot_for_expand (Descr::hash (x));
  
            *q = x;
          }
*************** hash_table <Element, Hash, Equal, Remove
*** 515,521 ****
      }
    while (p < olimit);
  
!   Allocator <Element *> ::data_free (oentries);
  }
  
  
--- 483,489 ----
      }
    while (p < olimit);
  
!   Allocator <T *> ::data_free (oentries);
  }
  
  
*************** hash_table <Element, Hash, Equal, Remove
*** 523,540 ****
     COMPARABLE element starting with the given HASH value.  It cannot
     be used to insert or delete an element. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
! 	  template <typename Type> class Allocator>
! Element *
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::find_with_hash (Element *comparable, hashval_t hash)
  {
    hashval_t index, hash2;
    size_t size;
!   Element *entry;
  
    htab->searches++;
    size = htab->size;
--- 491,505 ----
     COMPARABLE element starting with the given HASH value.  It cannot
     be used to insert or delete an element. */
  
! template <typename Descr,
! 	  template <typename Type> class Allocator>
! typename Descr::T *
! hash_table <Descr, Allocator>
! ::find_with_hash (T *comparable, hashval_t hash)
  {
    hashval_t index, hash2;
    size_t size;
!   T *entry;
  
    htab->searches++;
    size = htab->size;
*************** hash_table <Element, Hash, Equal, Remove
*** 542,548 ****
  
    entry = htab->entries[index];
    if (entry == HTAB_EMPTY_ENTRY
!       || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
      return entry;
  
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
--- 507,513 ----
  
    entry = htab->entries[index];
    if (entry == HTAB_EMPTY_ENTRY
!       || (entry != HTAB_DELETED_ENTRY && Descr::equal (entry, comparable)))
      return entry;
  
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
*************** hash_table <Element, Hash, Equal, Remove
*** 555,561 ****
  
        entry = htab->entries[index];
        if (entry == HTAB_EMPTY_ENTRY
!           || (entry != HTAB_DELETED_ENTRY && Equal (entry, comparable)))
          return entry;
      }
  }
--- 520,526 ----
  
        entry = htab->entries[index];
        if (entry == HTAB_EMPTY_ENTRY
!           || (entry != HTAB_DELETED_ENTRY && Descr::equal (entry, comparable)))
          return entry;
      }
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 569,588 ****
     write the value you want into the returned slot.  When inserting an
     entry, NULL may be returned if memory allocation fails. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
! 	  template <typename Type> class Allocator>
! Element **
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::find_slot_with_hash (Element *comparable, hashval_t hash,
  		       enum insert_option insert)
  {
!   Element **first_deleted_slot;
    hashval_t index, hash2;
    size_t size;
!   Element *entry;
  
    size = htab->size;
    if (insert == INSERT && size * 3 <= htab->n_elements * 4)
--- 534,550 ----
     write the value you want into the returned slot.  When inserting an
     entry, NULL may be returned if memory allocation fails. */
  
! template <typename Descr,
! 	  template <typename Type> class Allocator>
! typename Descr::T **
! hash_table <Descr, Allocator>
! ::find_slot_with_hash (T *comparable, hashval_t hash,
  		       enum insert_option insert)
  {
!   T **first_deleted_slot;
    hashval_t index, hash2;
    size_t size;
!   T *entry;
  
    size = htab->size;
    if (insert == INSERT && size * 3 <= htab->n_elements * 4)
*************** hash_table <Element, Hash, Equal, Remove
*** 601,607 ****
      goto empty_entry;
    else if (entry == HTAB_DELETED_ENTRY)
      first_deleted_slot = &htab->entries[index];
!   else if (Equal (entry, comparable))
      return &htab->entries[index];
        
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
--- 563,569 ----
      goto empty_entry;
    else if (entry == HTAB_DELETED_ENTRY)
      first_deleted_slot = &htab->entries[index];
!   else if (Descr::equal (entry, comparable))
      return &htab->entries[index];
        
    hash2 = hash_table_mod2 (hash, htab->size_prime_index);
*************** hash_table <Element, Hash, Equal, Remove
*** 620,626 ****
  	  if (!first_deleted_slot)
  	    first_deleted_slot = &htab->entries[index];
  	}
!       else if (Equal (entry, comparable))
  	return &htab->entries[index];
      }
  
--- 582,588 ----
  	  if (!first_deleted_slot)
  	    first_deleted_slot = &htab->entries[index];
  	}
!       else if (Descr::equal (entry, comparable))
  	return &htab->entries[index];
      }
  
*************** hash_table <Element, Hash, Equal, Remove
*** 631,637 ****
    if (first_deleted_slot)
      {
        htab->n_deleted--;
!       *first_deleted_slot = static_cast <Element *> (HTAB_EMPTY_ENTRY);
        return first_deleted_slot;
      }
  
--- 593,599 ----
    if (first_deleted_slot)
      {
        htab->n_deleted--;
!       *first_deleted_slot = static_cast <T *> (HTAB_EMPTY_ENTRY);
        return first_deleted_slot;
      }
  
*************** hash_table <Element, Hash, Equal, Remove
*** 642,662 ****
  
  /* This function clears all entries in the given hash table.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>::empty ()
  {
    size_t size = htab_size (htab);
!   Element **entries = htab->entries;
    int i;
  
    for (i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Remove (entries[i]);
  
    /* Instead of clearing megabyte, downsize the table.  */
    if (size > 1024*1024 / sizeof (PTR))
--- 604,621 ----
  
  /* This function clears all entries in the given hash table.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  void
! hash_table <Descr, Allocator>::empty ()
  {
    size_t size = htab_size (htab);
!   T **entries = htab->entries;
    int i;
  
    for (i = size - 1; i >= 0; i--)
      if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
!       Descr::remove (entries[i]);
  
    /* Instead of clearing megabyte, downsize the table.  */
    if (size > 1024*1024 / sizeof (PTR))
*************** hash_table <Element, Hash, Equal, Remove
*** 664,676 ****
        int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
        int nsize = prime_tab[nindex].prime;
  
!       Allocator <Element *> ::data_free (htab->entries);
!       htab->entries = Allocator <Element *> ::data_alloc (nsize);
        htab->size = nsize;
        htab->size_prime_index = nindex;
      }
    else
!     memset (entries, 0, size * sizeof (Element *));
    htab->n_deleted = 0;
    htab->n_elements = 0;
  }
--- 623,635 ----
        int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
        int nsize = prime_tab[nindex].prime;
  
!       Allocator <T *> ::data_free (htab->entries);
!       htab->entries = Allocator <T *> ::data_alloc (nsize);
        htab->size = nsize;
        htab->size_prime_index = nindex;
      }
    else
!     memset (entries, 0, size * sizeof (T *));
    htab->n_deleted = 0;
    htab->n_elements = 0;
  }
*************** hash_table <Element, Hash, Equal, Remove
*** 680,699 ****
     useful when you've already done the lookup and don't want to do it
     again. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::clear_slot (Element **slot)
  {
    if (slot < htab->entries || slot >= htab->entries + htab->size
        || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
      abort ();
  
!   Remove (*slot);
  
    *slot = HTAB_DELETED_ENTRY;
    htab->n_deleted++;
--- 639,655 ----
     useful when you've already done the lookup and don't want to do it
     again. */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  void
! hash_table <Descr, Allocator>
! ::clear_slot (T **slot)
  {
    if (slot < htab->entries || slot >= htab->entries + htab->size
        || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
      abort ();
  
!   Descr::remove (*slot);
  
    *slot = HTAB_DELETED_ENTRY;
    htab->n_deleted++;
*************** hash_table <Element, Hash, Equal, Remove
*** 704,727 ****
     from hash table starting with the given HASH.  If there is no
     matching element in the hash table, this function does nothing. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
! ::remove_elt_with_hash (Element *comparable, hashval_t hash)
  {
!   Element **slot;
  
    slot = find_slot_with_hash (comparable, hash, NO_INSERT);
    if (*slot == HTAB_EMPTY_ENTRY)
      return;
  
!   Remove (*slot);
  
!   *slot = static_cast <Element *> (HTAB_DELETED_ENTRY);
    htab->n_deleted++;
  }
  
--- 660,680 ----
     from hash table starting with the given HASH.  If there is no
     matching element in the hash table, this function does nothing. */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  void
! hash_table <Descr, Allocator>
! ::remove_elt_with_hash (T *comparable, hashval_t hash)
  {
!   T **slot;
  
    slot = find_slot_with_hash (comparable, hash, NO_INSERT);
    if (*slot == HTAB_EMPTY_ENTRY)
      return;
  
!   Descr::remove (*slot);
  
!   *slot = static_cast <T *> (HTAB_DELETED_ENTRY);
    htab->n_deleted++;
  }
  
*************** hash_table <Element, Hash, Equal, Remove
*** 730,755 ****
     each live entry.  If CALLBACK returns false, the iteration stops.
     ARGUMENT is passed as CALLBACK's second argument. */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (Element **slot, Argument argument)>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
  ::traverse_noresize (Argument argument)
  {
!   Element **slot;
!   Element **limit;
  
    slot = htab->entries;
    limit = slot + htab->size;
  
    do
      {
!       Element *x = *slot;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          if (! Callback (slot, argument))
--- 683,705 ----
     each live entry.  If CALLBACK returns false, the iteration stops.
     ARGUMENT is passed as CALLBACK's second argument. */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (typename Descr::T **slot, Argument argument)>
  void
! hash_table <Descr, Allocator>
  ::traverse_noresize (Argument argument)
  {
!   T **slot;
!   T **limit;
  
    slot = htab->entries;
    limit = slot + htab->size;
  
    do
      {
!       T *x = *slot;
  
        if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
          if (! Callback (slot, argument))
*************** hash_table <Element, Hash, Equal, Remove
*** 762,776 ****
  /* Like traverse_noresize, but does resize the table when it is too empty
     to improve effectivity of subsequent calls.  */
  
! template <typename Element,
! 	  hashval_t (*Hash) (const Element *candidate),
! 	  int (*Equal) (const Element *existing, const Element * candidate),
! 	  void (*Remove) (Element *retired),
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (Element **slot, Argument argument)>
  void
! hash_table <Element, Hash, Equal, Remove, Allocator>
  ::traverse (Argument argument)
  {
    size_t size = htab->size;
--- 712,723 ----
  /* Like traverse_noresize, but does resize the table when it is too empty
     to improve effectivity of subsequent calls.  */
  
! template <typename Descr,
  	  template <typename Type> class Allocator>
  template <typename Argument,
! 	  int (*Callback) (typename Descr::T **slot, Argument argument)>
  void
! hash_table <Descr, Allocator>
  ::traverse (Argument argument)
  {
    size_t size = htab->size;
Index: gcc/coverage.c
===================================================================
*** gcc/coverage.c.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/coverage.c	2012-08-16 10:54:30.986306770 +0200
*************** typedef struct counts_entry
*** 77,82 ****
--- 77,88 ----
    unsigned cfg_checksum;
    gcov_type *counts;
    struct gcov_ctr_summary summary;
+ 
+   /* hash_table support.  */
+   typedef counts_entry T;
+   static inline hashval_t hash (const counts_entry *);
+   static int equal (const counts_entry *, const counts_entry *);
+   static void remove (counts_entry *);
  } counts_entry_t;
  
  static GTY(()) struct coverage_data *functions_head = 0;
*************** get_gcov_unsigned_t (void)
*** 144,172 ****
  }
  \f
  inline hashval_t
! coverage_counts_entry_hash (const counts_entry_t *entry)
  {
    return entry->ident * GCOV_COUNTERS + entry->ctr;
  }
  
  inline int
! coverage_counts_entry_eq (const counts_entry_t *entry1,
!                           const counts_entry_t *entry2)
  {
    return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
  }
  
  inline void
! coverage_counts_entry_del (counts_entry_t *entry)
  {
    free (entry->counts);
    free (entry);
  }
  
  /* Hash table of count data.  */
! static hash_table <counts_entry_t, coverage_counts_entry_hash,
! 		   coverage_counts_entry_eq, coverage_counts_entry_del>
! 		  counts_hash;
  
  /* Read in the counts file, if available.  */
  
--- 150,176 ----
  }
  \f
  inline hashval_t
! counts_entry::hash (const counts_entry_t *entry)
  {
    return entry->ident * GCOV_COUNTERS + entry->ctr;
  }
  
  inline int
! counts_entry::equal (const counts_entry_t *entry1,
! 		     const counts_entry_t *entry2)
  {
    return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
  }
  
  inline void
! counts_entry::remove (counts_entry_t *entry)
  {
    free (entry->counts);
    free (entry);
  }
  
  /* Hash table of count data.  */
! static hash_table <counts_entry> counts_hash;
  
  /* Read in the counts file, if available.  */
  
Index: gcc/tree-ssa-ccp.c
===================================================================
*** gcc/tree-ssa-ccp.c.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/tree-ssa-ccp.c	2012-08-16 10:34:56.175347440 +0200
*************** evaluate_stmt (gimple stmt)
*** 1688,1697 ****
    return val;
  }
  
! typedef hash_table <gimple_statement_d, typed_pointer_hash<gimple_statement_d>,
! 		    typed_pointer_equal<gimple_statement_d>,
! 		    typed_null_remove<gimple_statement_d> >
! 		   gimple_htab;
  
  /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
     each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
--- 1688,1694 ----
    return val;
  }
  
! typedef hash_table <pointer_hash <gimple_statement_d> > gimple_htab;
  
  /* Given a BUILT_IN_STACK_SAVE value SAVED_VAL, insert a clobber of VAR before
     each matching BUILT_IN_STACK_RESTORE.  Mark visited phis in VISITED.  */
Index: gcc/tree-ssa-coalesce.c
===================================================================
*** gcc/tree-ssa-coalesce.c.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/tree-ssa-coalesce.c	2012-08-16 11:08:50.857277018 +0200
*************** coalesce_partitions (var_map map, ssa_co
*** 1258,1279 ****
      }
  }
  
! /* Returns a hash code for N.  */
  
  inline hashval_t
! hash_ssa_name_by_var (const_tree n)
  {
!   return (hashval_t) htab_hash_pointer (SSA_NAME_VAR (n));
  }
  
- /* Returns nonzero if N1 and N2 are equal.  */
- 
  inline int
! eq_ssa_name_by_var (const_tree n1, const_tree n2)
  {
    return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
  }
  
  /* Reduce the number of copies by coalescing variables in the function.  Return
     a partition map with the resulting coalesces.  */
  
--- 1258,1286 ----
      }
  }
  
! 
! /* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR.  */
! 
! struct ssa_name_var_hash : typed_noop_remove <union tree_node>
! {
!   typedef union tree_node T;
!   static inline hashval_t hash (const_tree);
!   static inline int equal (const_tree, const_tree);
! };
  
  inline hashval_t
! ssa_name_var_hash::hash (const_tree n)
  {
!   return DECL_UID (SSA_NAME_VAR (n));
  }
  
  inline int
! ssa_name_var_hash::equal (const_tree n1, const_tree n2)
  {
    return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
  }
  
+ 
  /* Reduce the number of copies by coalescing variables in the function.  Return
     a partition map with the resulting coalesces.  */
  
*************** coalesce_ssa_name (void)
*** 1286,1294 ****
    bitmap used_in_copies = BITMAP_ALLOC (NULL);
    var_map map;
    unsigned int i;
!   static hash_table <tree_node, hash_ssa_name_by_var, eq_ssa_name_by_var,
! 		     typed_null_remove<tree_node> >
! 		    ssa_name_hash;
  
    cl = create_coalesce_list ();
    map = create_outofssa_var_map (cl, used_in_copies);
--- 1293,1299 ----
    bitmap used_in_copies = BITMAP_ALLOC (NULL);
    var_map map;
    unsigned int i;
!   static hash_table <ssa_name_var_hash> ssa_name_hash;
  
    cl = create_coalesce_list ();
    map = create_outofssa_var_map (cl, used_in_copies);
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/tree-ssa-pre.c	2012-08-16 11:09:12.132276244 +0200
*************** typedef union pre_expr_union_d
*** 165,175 ****
    vn_reference_t reference;
  } pre_expr_union;
  
! typedef struct pre_expr_d
  {
    enum pre_expr_kind kind;
    unsigned int id;
    pre_expr_union u;
  } *pre_expr;
  
  #define PRE_EXPR_NAME(e) (e)->u.name
--- 165,180 ----
    vn_reference_t reference;
  } pre_expr_union;
  
! typedef struct pre_expr_d : typed_noop_remove <pre_expr_d>
  {
    enum pre_expr_kind kind;
    unsigned int id;
    pre_expr_union u;
+ 
+   /* hash_table support.  */
+   typedef pre_expr_d T;
+   static inline hashval_t hash (const pre_expr_d *);
+   static inline int equal (const pre_expr_d *, const pre_expr_d *);
  } *pre_expr;
  
  #define PRE_EXPR_NAME(e) (e)->u.name
*************** typedef struct pre_expr_d
*** 180,186 ****
  /* Compare E1 and E1 for equality.  */
  
  inline int
! ssa_pre_expr_eq (const struct pre_expr_d *e1, const struct pre_expr_d *e2)
  {
    if (e1->kind != e2->kind)
      return false;
--- 185,191 ----
  /* Compare E1 and E1 for equality.  */
  
  inline int
! pre_expr_d::equal (const struct pre_expr_d *e1, const struct pre_expr_d *e2)
  {
    if (e1->kind != e2->kind)
      return false;
*************** ssa_pre_expr_eq (const struct pre_expr_d
*** 205,211 ****
  /* Hash E.  */
  
  inline hashval_t
! ssa_pre_expr_hash (const struct pre_expr_d *e)
  {
    switch (e->kind)
      {
--- 210,216 ----
  /* Hash E.  */
  
  inline hashval_t
! pre_expr_d::hash (const struct pre_expr_d *e)
  {
    switch (e->kind)
      {
*************** static unsigned int next_expression_id;
*** 229,237 ****
  DEF_VEC_P (pre_expr);
  DEF_VEC_ALLOC_P (pre_expr, heap);
  static VEC(pre_expr, heap) *expressions;
! static hash_table <pre_expr_d, ssa_pre_expr_hash, ssa_pre_expr_eq,
! 		   typed_null_remove <pre_expr_d> >
! 		  expression_to_id;
  static VEC(unsigned, heap) *name_to_id;
  
  /* Allocate an expression id for EXPR.  */
--- 234,240 ----
  DEF_VEC_P (pre_expr);
  DEF_VEC_ALLOC_P (pre_expr, heap);
  static VEC(pre_expr, heap) *expressions;
! static hash_table <pre_expr_d> expression_to_id;
  static VEC(unsigned, heap) *name_to_id;
  
  /* Allocate an expression id for EXPR.  */
*************** static bitmap need_ab_cleanup;
*** 483,489 ****
  /* A three tuple {e, pred, v} used to cache phi translations in the
     phi_translate_table.  */
  
! typedef struct expr_pred_trans_d
  {
    /* The expression.  */
    pre_expr e;
--- 486,492 ----
  /* A three tuple {e, pred, v} used to cache phi translations in the
     phi_translate_table.  */
  
! typedef struct expr_pred_trans_d : typed_free_remove<expr_pred_trans_d>
  {
    /* The expression.  */
    pre_expr e;
*************** typedef struct expr_pred_trans_d
*** 497,519 ****
    /* The hashcode for the expression, pred pair. This is cached for
       speed reasons.  */
    hashval_t hashcode;
  } *expr_pred_trans_t;
  typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
  
- /* Return the hash value for a phi translation table entry.  */
- 
  inline hashval_t
! ssa_expr_pred_trans_hash (const expr_pred_trans_d *ve)
  {
!   return ve->hashcode;
  }
  
- /* Return true if two phi translation table entries are the same.
-    P1 and P2 should point to the expr_pred_trans_t's to be compared.*/
- 
  inline int
! ssa_expr_pred_trans_eq (const expr_pred_trans_d *ve1,
! 			const expr_pred_trans_d *ve2)
  {
    basic_block b1 = ve1->pred;
    basic_block b2 = ve2->pred;
--- 500,522 ----
    /* The hashcode for the expression, pred pair. This is cached for
       speed reasons.  */
    hashval_t hashcode;
+ 
+   /* hash_table support.  */
+   typedef expr_pred_trans_d T;
+   static inline hashval_t hash (const expr_pred_trans_d *);
+   static inline int equal (const expr_pred_trans_d *, const expr_pred_trans_d *);
  } *expr_pred_trans_t;
  typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
  
  inline hashval_t
! expr_pred_trans_d::hash (const expr_pred_trans_d *e)
  {
!   return e->hashcode;
  }
  
  inline int
! expr_pred_trans_d::equal (const expr_pred_trans_d *ve1,
! 			  const expr_pred_trans_d *ve2)
  {
    basic_block b1 = ve1->pred;
    basic_block b2 = ve2->pred;
*************** ssa_expr_pred_trans_eq (const expr_pred_
*** 522,537 ****
       be equal.  */
    if (b1 != b2)
      return false;
!   return ssa_pre_expr_eq (ve1->e, ve2->e);
  }
  
  /* The phi_translate_table caches phi translations for a given
     expression and predecessor.  */
! 
! static hash_table <expr_pred_trans_d, ssa_expr_pred_trans_hash,
! 		   ssa_expr_pred_trans_eq,
! 		   typed_free_remove <expr_pred_trans_d> >
! 		  phi_translate_table;
  
  /* Search in the phi translation table for the translation of
     expression E in basic block PRED.
--- 525,536 ----
       be equal.  */
    if (b1 != b2)
      return false;
!   return pre_expr_d::equal (ve1->e, ve2->e);
  }
  
  /* The phi_translate_table caches phi translations for a given
     expression and predecessor.  */
! static hash_table <expr_pred_trans_d> phi_translate_table;
  
  /* Search in the phi translation table for the translation of
     expression E in basic block PRED.
*************** phi_trans_lookup (pre_expr e, basic_bloc
*** 545,551 ****
  
    ept.e = e;
    ept.pred = pred;
!   ept.hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e), pred->index);
    slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode,
  				   NO_INSERT);
    if (!slot)
--- 544,550 ----
  
    ept.e = e;
    ept.pred = pred;
!   ept.hashcode = iterative_hash_hashval_t (pre_expr_d::hash (e), pred->index);
    slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode,
  				   NO_INSERT);
    if (!slot)
*************** phi_trans_add (pre_expr e, pre_expr v, b
*** 566,572 ****
    new_pair->e = e;
    new_pair->pred = pred;
    new_pair->v = v;
!   new_pair->hashcode = iterative_hash_hashval_t (ssa_pre_expr_hash (e),
  						 pred->index);
  
    slot = phi_translate_table.find_slot_with_hash (new_pair,
--- 565,571 ----
    new_pair->e = e;
    new_pair->pred = pred;
    new_pair->v = v;
!   new_pair->hashcode = iterative_hash_hashval_t (pre_expr_d::hash (e),
  						 pred->index);
  
    slot = phi_translate_table.find_slot_with_hash (new_pair,
*************** do_regular_insertion (basic_block block,
*** 3495,3501 ****
  		    do_insertion = true;
  		  if (first_s == NULL)
  		    first_s = edoubleprime;
! 		  else if (!ssa_pre_expr_eq (first_s, edoubleprime))
  		    all_same = false;
  		}
  	    }
--- 3494,3500 ----
  		    do_insertion = true;
  		  if (first_s == NULL)
  		    first_s = edoubleprime;
! 		  else if (!pre_expr_d::equal (first_s, edoubleprime))
  		    all_same = false;
  		}
  	    }
Index: gcc/tree-ssa-tail-merge.c
===================================================================
*** gcc/tree-ssa-tail-merge.c.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/tree-ssa-tail-merge.c	2012-08-16 10:50:44.530314595 +0200
*************** struct same_succ_def
*** 224,233 ****
--- 224,247 ----
    bool in_worklist;
    /* The hash value of the struct.  */
    hashval_t hashval;
+ 
+   /* hash_table support.  */
+   typedef same_succ_def T;
+   static inline hashval_t hash (const same_succ_def *);
+   static int equal (const same_succ_def *, const same_succ_def *);
+   static void remove (same_succ_def *);
  };
  typedef struct same_succ_def *same_succ;
  typedef const struct same_succ_def *const_same_succ;
  
+ /* hash routine for hash_table support, returns hashval of E.  */
+ 
+ inline hashval_t
+ same_succ_def::hash (const same_succ_def *e)
+ {
+   return e->hashval;
+ }
+ 
  /* A group of bbs where 1 bb from bbs can replace the other bbs.  */
  
  struct bb_cluster_def
*************** stmt_update_dep_bb (gimple stmt)
*** 415,422 ****
  
  /* Calculates hash value for same_succ VE.  */
  
! hashval_t
! ssa_same_succ_hash (const_same_succ e)
  {
    hashval_t hashval = bitmap_hash (e->succs);
    int flags;
--- 429,436 ----
  
  /* Calculates hash value for same_succ VE.  */
  
! static hashval_t
! same_succ_hash (const_same_succ e)
  {
    hashval_t hashval = bitmap_hash (e->succs);
    int flags;
*************** inverse_flags (const_same_succ e1, const
*** 511,520 ****
    return (f1a & mask) == (f2a & mask) && (f1b & mask) == (f2b & mask);
  }
  
! /* Compares SAME_SUCCs VE1 and VE2.  */
  
  int
! ssa_same_succ_equal (const_same_succ e1, const_same_succ e2)
  {
    unsigned int i, first1, first2;
    gimple_stmt_iterator gsi1, gsi2;
--- 525,534 ----
    return (f1a & mask) == (f2a & mask) && (f1b & mask) == (f2b & mask);
  }
  
! /* Compares SAME_SUCCs E1 and E2.  */
  
  int
! same_succ_def::equal (const_same_succ e1, const_same_succ e2)
  {
    unsigned int i, first1, first2;
    gimple_stmt_iterator gsi1, gsi2;
*************** same_succ_alloc (void)
*** 584,593 ****
    return same;
  }
  
! /* Delete same_succ VE.  */
  
! inline void
! ssa_same_succ_delete (same_succ e)
  {
    BITMAP_FREE (e->bbs);
    BITMAP_FREE (e->succs);
--- 598,607 ----
    return same;
  }
  
! /* Delete same_succ E.  */
  
! void
! same_succ_def::remove (same_succ e)
  {
    BITMAP_FREE (e->bbs);
    BITMAP_FREE (e->succs);
*************** same_succ_reset (same_succ same)
*** 608,618 ****
    VEC_truncate (int, same->succ_flags, 0);
  }
  
! /* Hash table with all same_succ entries.  */
! 
! static hash_table <struct same_succ_def, ssa_same_succ_hash,
! 		   ssa_same_succ_equal, ssa_same_succ_delete>
! 		  same_succ_htab;
  
  /* Array that is used to store the edge flags for a successor.  */
  
--- 622,628 ----
    VEC_truncate (int, same->succ_flags, 0);
  }
  
! static hash_table <same_succ_def> same_succ_htab;
  
  /* Array that is used to store the edge flags for a successor.  */
  
*************** find_same_succ_bb (basic_block bb, same_
*** 692,698 ****
    EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
      VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
  
!   same->hashval = ssa_same_succ_hash (same);
  
    slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
    if (*slot == NULL)
--- 702,708 ----
    EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
      VEC_safe_push (int, heap, same->succ_flags, same_succ_edge_flags[j]);
  
!   same->hashval = same_succ_hash (same);
  
    slot = same_succ_htab.find_slot_with_hash (same, same->hashval, INSERT);
    if (*slot == NULL)
*************** find_same_succ (void)
*** 728,734 ****
  	same = same_succ_alloc ();
      }
  
!   ssa_same_succ_delete (same);
  }
  
  /* Initializes worklist administration.  */
--- 738,744 ----
  	same = same_succ_alloc ();
      }
  
!   same_succ_def::remove (same);
  }
  
  /* Initializes worklist administration.  */
*************** update_worklist (void)
*** 860,866 ****
        if (same == NULL)
  	same = same_succ_alloc ();
      }
!   ssa_same_succ_delete (same);
    bitmap_clear (deleted_bb_preds);
  }
  
--- 870,876 ----
        if (same == NULL)
  	same = same_succ_alloc ();
      }
!   same_succ_def::remove (same);
    bitmap_clear (deleted_bb_preds);
  }
  
Index: gcc/tree-ssa-threadupdate.c
===================================================================
*** gcc/tree-ssa-threadupdate.c.orig	2012-08-16 10:33:59.000000000 +0200
--- gcc/tree-ssa-threadupdate.c	2012-08-16 11:04:35.307285820 +0200
*************** struct el
*** 110,116 ****
     may have many incoming edges threaded to the same outgoing edge.  This
     can be naturally implemented with a hash table.  */
  
! struct redirection_data
  {
    /* A duplicate of B with the trailing control statement removed and which
       targets a single successor of B.  */
--- 110,116 ----
     may have many incoming edges threaded to the same outgoing edge.  This
     can be naturally implemented with a hash table.  */
  
! struct redirection_data : typed_free_remove<redirection_data>
  {
    /* A duplicate of B with the trailing control statement removed and which
       targets a single successor of B.  */
*************** struct redirection_data
*** 125,132 ****
--- 125,154 ----
    /* A list of incoming edges which we want to thread to
       OUTGOING_EDGE->dest.  */
    struct el *incoming_edges;
+ 
+   /* hash_table support.  */
+   typedef redirection_data T;
+   static inline hashval_t hash (const redirection_data *);
+   static inline int equal (const redirection_data *, const redirection_data *);
  };
  
+ inline hashval_t
+ redirection_data::hash (const redirection_data *p)
+ {
+   edge e = p->outgoing_edge;
+   return e->dest->index;
+ }
+ 
+ inline int
+ redirection_data::equal (const redirection_data *p1, const redirection_data *p2)
+ {
+   edge e1 = p1->outgoing_edge;
+   edge e2 = p2->outgoing_edge;
+   edge e3 = p1->intermediate_edge;
+   edge e4 = p2->intermediate_edge;
+   return e1 == e2 && e3 == e4;
+ }
+ 
  /* Data structure of information to pass to hash table traversal routines.  */
  struct ssa_local_info_t
  {
*************** create_block_for_threading (basic_block
*** 217,248 ****
    rd->dup_block->count = 0;
  }
  
- /* Hashing and equality routines for our hash table.  */
- inline hashval_t
- ssa_redirection_data_hash (const struct redirection_data *p)
- {
-   edge e = p->outgoing_edge;
-   return e->dest->index;
- }
- 
- inline int
- ssa_redirection_data_eq (const struct redirection_data *p1,
- 			 const struct redirection_data *p2)
- {
-   edge e1 = p1->outgoing_edge;
-   edge e2 = p2->outgoing_edge;
-   edge e3 = p1->intermediate_edge;
-   edge e4 = p2->intermediate_edge;
- 
-   return e1 == e2 && e3 == e4;
- }
- 
  /* Main data structure to hold information for duplicates of BB.  */
  
! static hash_table <struct redirection_data, ssa_redirection_data_hash,
! 		   ssa_redirection_data_eq,
! 		   typed_free_remove<struct redirection_data> >
! 		  redirection_data;
  
  /* Given an outgoing edge E lookup and return its entry in our hash table.
  
--- 239,247 ----
    rd->dup_block->count = 0;
  }
  
  /* Main data structure to hold information for duplicates of BB.  */
  
! static hash_table <redirection_data> redirection_data;
  
  /* Given an outgoing edge E lookup and return its entry in our hash table.
  

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-16  9:22             ` Richard Guenther
@ 2012-08-16 14:56               ` Paolo Carlini
  2012-08-16 14:58                 ` Richard Guenther
  2012-08-16 19:02               ` Lawrence Crowl
  1 sibling, 1 reply; 29+ messages in thread
From: Paolo Carlini @ 2012-08-16 14:56 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Lawrence Crowl, Richard Henderson, Michael Matz, Diego Novillo,
	gcc-patches

Hi,

I have another "out of curiosity"-type question ;)

On 08/16/2012 11:19 AM, Richard Guenther wrote:
>
> !
> ! template <typename Element>
> ! inline int
> ! pointer_hash<Element>::equal (const T *existing,
> ! 			      const T *candidate)
> ! {
> !   return existing == candidate;
>    }
are these uses in the new code of int instead of bool intended or 
"historical"? Seem weird, definitely from the C++ (but even from the C) 
point of view.

Paolo.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-16 14:56               ` Paolo Carlini
@ 2012-08-16 14:58                 ` Richard Guenther
  0 siblings, 0 replies; 29+ messages in thread
From: Richard Guenther @ 2012-08-16 14:58 UTC (permalink / raw)
  To: Paolo Carlini
  Cc: Lawrence Crowl, Richard Henderson, Michael Matz, Diego Novillo,
	gcc-patches

On Thu, 16 Aug 2012, Paolo Carlini wrote:

> Hi,
> 
> I have another "out of curiosity"-type question ;)
> 
> On 08/16/2012 11:19 AM, Richard Guenther wrote:
> > 
> > !
> > ! template <typename Element>
> > ! inline int
> > ! pointer_hash<Element>::equal (const T *existing,
> > ! 			      const T *candidate)
> > ! {
> > !   return existing == candidate;
> >    }
> are these uses in the new code of int instead of bool intended or
> "historical"? Seem weird, definitely from the C++ (but even from the C) point
> of view.

Historical, copying what libiberty htab did.

Richard.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-16  9:22             ` Richard Guenther
  2012-08-16 14:56               ` Paolo Carlini
@ 2012-08-16 19:02               ` Lawrence Crowl
  1 sibling, 0 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-08-16 19:02 UTC (permalink / raw)
  To: Richard Guenther
  Cc: Richard Henderson, Michael Matz, Diego Novillo, gcc-patches

On 8/16/12, Richard Guenther <rguenther@suse.de> wrote:
> On Wed, 15 Aug 2012, Lawrence Crowl wrote:
> > On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
> > > On 2012-08-15 07:29, Richard Guenther wrote:
> > > > +   typedef typename Element::Element_t Element_t;
> > >
> > > Can we use something less ugly than Element_t?
> > > Such as
> > >
> > >   typedef typename Element::T T;
> > >
> > > ?  Given that this name is scoped anyway...
> >
> > I do not much like _t names either.
>
> The following is what I'm testing now, it also integrates the
> hashtable support functions and typedef within the existing local
> data types which is IMHO cleaner.  (it also shows we can do with
> a janitorial cleanup replacing typedef struct foo_d {} foo; with
> struct foo {}; and the likes)

Yes.

> Bootstrap and regtest ongoing on x86_64-unknown-linux-gnu, ok?

Looks good to me.

I would have prefered the Element->T rename in a separate patch
so that it is easier to see the core difference.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-08-15 16:17         ` Richard Henderson
  2012-08-15 21:58           ` Lawrence Crowl
@ 2012-09-25 23:19           ` Lawrence Crowl
  2012-09-26 13:48             ` Michael Matz
  2012-09-26 14:51             ` Gabriel Dos Reis
  1 sibling, 2 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-09-25 23:19 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Richard Guenther, Michael Matz, Diego Novillo, gcc-patches

On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
> On 2012-08-15 07:29, Richard Guenther wrote:
> > +   typedef typename Element::Element_t Element_t;
>
> Can we use something less ugly than Element_t?
> Such as
>
>   typedef typename Element::T T;
>
> ?  Given that this name is scoped anyway...

I've been finding the use of T as a typedef confusing.  It sort of
flies in the face of all existing convention.  The C++ standard would
use either element_type or value_type.  I suggest a rename, but I'm
guessing that folks don't want something as verbose as element_type.
How about elemtype?  Any objections to me changing it to that?

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-25 23:19           ` Lawrence Crowl
@ 2012-09-26 13:48             ` Michael Matz
  2012-09-26 20:20               ` Lawrence Crowl
  2012-09-26 14:51             ` Gabriel Dos Reis
  1 sibling, 1 reply; 29+ messages in thread
From: Michael Matz @ 2012-09-26 13:48 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Richard Henderson, Richard Guenther, Diego Novillo, gcc-patches

Hi,

On Tue, 25 Sep 2012, Lawrence Crowl wrote:

> On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
> > On 2012-08-15 07:29, Richard Guenther wrote:
> > > +   typedef typename Element::Element_t Element_t;
> >
> > Can we use something less ugly than Element_t?
> > Such as
> >
> >   typedef typename Element::T T;
> >
> > ?  Given that this name is scoped anyway...
> 
> I've been finding the use of T as a typedef confusing.

Why?  As type placeholder in templates it's quite customary, as the "most 
interesting to users of this template".  I would have no trouble at all to 
see declarations like "T x = getme();" in a function.  In some way I even 
prefer that to some lower-case variant, because it reminds me that this 
specific "T" is actually variant.

A lower-case type name indicates to me a non-changing type, i.e. nothing 
that depends on a template.  In C we only had such types so we used 
lower-case names everywhere.  With C++ and templates I think we should 
start using upper case for some very specific use cases, like first letter 
of dependend types.

> It sort of flies in the face of all existing convention.

If you talk about the conventions used for the c++ standard library, then 
they are IMHO quite ugly and we should not follow them.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-25 23:19           ` Lawrence Crowl
  2012-09-26 13:48             ` Michael Matz
@ 2012-09-26 14:51             ` Gabriel Dos Reis
  1 sibling, 0 replies; 29+ messages in thread
From: Gabriel Dos Reis @ 2012-09-26 14:51 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Richard Henderson, Richard Guenther, Michael Matz, Diego Novillo,
	gcc-patches

On Tue, Sep 25, 2012 at 4:30 PM, Lawrence Crowl <crowl@google.com> wrote:
> On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
>> On 2012-08-15 07:29, Richard Guenther wrote:
>> > +   typedef typename Element::Element_t Element_t;
>>
>> Can we use something less ugly than Element_t?
>> Such as
>>
>>   typedef typename Element::T T;
>>
>> ?  Given that this name is scoped anyway...
>
> I've been finding the use of T as a typedef confusing.  It sort of
> flies in the face of all existing convention.  The C++ standard would
> use either element_type or value_type.  I suggest a rename, but I'm
> guessing that folks don't want something as verbose as element_type.
> How about elemtype?  Any objections to me changing it to that?
>


In general, we would be better off following standard convention.
It does not seem to me that we have enough reasons and benefits in
building our own universe around this issue.  Consequently, I would suggest
that we use value_type or element_type in the interface -- which is better
served being readable: this is the *interface*.

I am pretty sure that people will quickly resort to local typedefs that are
more readable even if we adopt a short (therefore cryptic) abbreviations
such as T in the interface.  It is one more hurdle that has no reason to be.

-- Gaby

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-26 13:48             ` Michael Matz
@ 2012-09-26 20:20               ` Lawrence Crowl
  2012-09-26 20:28                 ` Gabriel Dos Reis
  2012-09-27 12:55                 ` Michael Matz
  0 siblings, 2 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-09-26 20:20 UTC (permalink / raw)
  To: Michael Matz
  Cc: Richard Henderson, Richard Guenther, Diego Novillo, gcc-patches

On 9/26/12, Michael Matz <matz@suse.de> wrote:
> On Tue, 25 Sep 2012, Lawrence Crowl wrote:
> > On 8/15/12, Richard Henderson <rth@redhat.com> wrote:
> > > On 2012-08-15 07:29, Richard Guenther wrote:
> > > > typedef typename Element::Element_t Element_t;
> > >
> > > Can we use something less ugly than Element_t?
> > > Such as typedef typename Element::T T;
> > > ?  Given that this name is scoped anyway...
> >
> > I've been finding the use of T as a typedef confusing.
>
> Why?  As type placeholder in templates it's quite customary,
> as the "most interesting to users of this template".  I would
> have no trouble at all to see declarations like "T x = getme();"
> in a function.  In some way I even prefer that to some lower-case
> variant, because it reminds me that this specific "T" is actually
> variant.

The problem is that while T is customary as a template parameter, I
have never seen it used as a typedef name.  And that's the situation
that we are in now.

> A lower-case type name indicates to me a non-changing type,
> i.e. nothing that depends on a template.  In C we only had
> such types so we used lower-case names everywhere.  With C++
> and templates I think we should start using upper case for some
> very specific use cases, like first letter of dependend types.

How would you distinguish them from template parameter names,
which by convention have an upper case first letter?

What about non-type dependent names?

I think we really do need a separate convention for the two,
because dependent members of class templates often need special
access syntax.

> > It sort of flies in the face of all existing convention.
>
> If you talk about the conventions used for the c++ standard
> library, then they are IMHO quite ugly and we should not follow
> them.

The advantage to following them is that they will surprise no one.
Do you have an alternate suggestion, one that does not confuse
template parameters and dependent names?

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-26 20:20               ` Lawrence Crowl
@ 2012-09-26 20:28                 ` Gabriel Dos Reis
  2012-09-27 12:55                 ` Michael Matz
  1 sibling, 0 replies; 29+ messages in thread
From: Gabriel Dos Reis @ 2012-09-26 20:28 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Michael Matz, Richard Henderson, Richard Guenther, Diego Novillo,
	gcc-patches

On Wed, Sep 26, 2012 at 1:09 PM, Lawrence Crowl <crowl@google.com> wrote:
>
> The problem is that while T is customary as a template parameter, I
> have never seen it used as a typedef name.  And that's the situation
> that we are in now.

this should be a no-brainer: T should be reserved for the name of the
template parameter.
[...]

> I think we really do need a separate convention for the two,
> because dependent members of class templates often need special
> access syntax.

Yes.

-- Gaby

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-26 20:20               ` Lawrence Crowl
  2012-09-26 20:28                 ` Gabriel Dos Reis
@ 2012-09-27 12:55                 ` Michael Matz
  2012-09-27 13:01                   ` Gabriel Dos Reis
  2012-09-27 20:51                   ` Lawrence Crowl
  1 sibling, 2 replies; 29+ messages in thread
From: Michael Matz @ 2012-09-27 12:55 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Richard Henderson, Richard Guenther, Diego Novillo, gcc-patches

Hi,

On Wed, 26 Sep 2012, Lawrence Crowl wrote:

> > A lower-case type name indicates to me a non-changing type,
> > i.e. nothing that depends on a template.  In C we only had
> > such types so we used lower-case names everywhere.  With C++
> > and templates I think we should start using upper case for some
> > very specific use cases, like first letter of dependend types.
> 
> How would you distinguish them from template parameter names,
> which by convention have an upper case first letter?

I wouldn't.  If the distinction becomes so important that authors need to 
see the speciality immediately by having a different convention how to 
spell names, then I think we did something wrong, and we should simplify 
the code.

> What about non-type dependent names?

I'm not sure what you're asking.  Let's make an example:

template <typename T>
struct D : B<T>
{
  typedef typename B<T>::E E; // element_type
  E getme (int index);
}

In fact, as B<T>::E would probably be defined like "typedef typename T E", 
I would even have no issue to call the above E also T.  The distinction 
between the template arg name and the typedef would be blurred, and I say, 
so what; one is a typedef of the other and hence mostly equivalent for 
practical purposes.  (And if they aren't, then again, we did something too 
complicated with the switch to C++).

> The advantage to following them is that they will surprise no one.

They will surprise everyone used to different conventions, for instance 
Qt, so that's not a reason.

> Do you have an alternate suggestion, one that does not confuse template 
> parameters and dependent names?

Upper last character?  Just kidding :)  Too many detailed rules for 
conventions are the death of them, use rules of thumbs, my one would be 
"somehow depends on template args -> has upper character in name", where 
"somehow depends on" includes "is a".


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-27 12:55                 ` Michael Matz
@ 2012-09-27 13:01                   ` Gabriel Dos Reis
  2012-09-27 20:51                   ` Lawrence Crowl
  1 sibling, 0 replies; 29+ messages in thread
From: Gabriel Dos Reis @ 2012-09-27 13:01 UTC (permalink / raw)
  To: Michael Matz
  Cc: Lawrence Crowl, Richard Henderson, Richard Guenther,
	Diego Novillo, gcc-patches

On Thu, Sep 27, 2012 at 7:12 AM, Michael Matz <matz@suse.de> wrote:

> (And if they aren't, then again, we did something too
> complicated with the switch to C++).

or we are doing something by insisting not to use
standard notation.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-27 12:55                 ` Michael Matz
  2012-09-27 13:01                   ` Gabriel Dos Reis
@ 2012-09-27 20:51                   ` Lawrence Crowl
  2012-09-28  1:44                     ` Gabriel Dos Reis
  2012-09-28 15:08                     ` Michael Matz
  1 sibling, 2 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-09-27 20:51 UTC (permalink / raw)
  To: Michael Matz
  Cc: Richard Henderson, Richard Guenther, Diego Novillo, gcc-patches

On 9/27/12, Michael Matz <matz@suse.de> wrote:
> On Wed, 26 Sep 2012, Lawrence Crowl wrote:
> > > A lower-case type name indicates to me a non-changing type,
> > > i.e. nothing that depends on a template.  In C we only had
> > > such types so we used lower-case names everywhere.  With C++
> > > and templates I think we should start using upper case for some
> > > very specific use cases, like first letter of dependend types.
> >
> > How would you distinguish them from template parameter names,
> > which by convention have an upper case first letter?
>
> I wouldn't.  If the distinction becomes so important that authors
> need to see the speciality immediately by having a different
> convention how to spell names, then I think we did something wrong,
> and we should simplify the code.
>
> > What about non-type dependent names?
>
> I'm not sure what you're asking.  Let's make an example:
>
> template <typename T>
> struct D : B<T>
> {
>   typedef typename B<T>::E E; // element_type
>   E getme (int index);
> }

Inside that struct, lets say we have a field of type E.  Do we name
it F or f?

> In fact, as B<T>::E would probably be defined like "typedef
> typename T E", I would even have no issue to call the above E
> also T.  The distinction between the template arg name and the
> typedef would be blurred, and I say, so what; one is a typedef
> of the other and hence mostly equivalent for practical purposes.
> (And if they aren't, then again, we did something too complicated
> with the switch to C++).
>
> > The advantage to following them is that they will surprise
> > no one.
>
> They will surprise everyone used to different conventions, for
> instance Qt, so that's not a reason.

Anyone using the standard library will not be surprised if we follow
the conventions of the standard library.  I'd guess that the number
standard library programmers outnumbers the Qt programmers by 100
to 1.  I'd guess that the number of Qt programmers that do not know
the standard library is a minority.

> > Do you have an alternate suggestion, one that does not confuse
> > template parameters and dependent names?
>
> Upper last character?  Just kidding :)  Too many detailed rules
> for conventions are the death of them, use rules of thumbs,
> my one would be "somehow depends on template args -> has upper
> character in name", where "somehow depends on" includes "is a".

Ah, but there is a problem.  That typedef name does not necessarily
depend on a template parameter.

It is common practice to have

struct Q
{
  typedef int E;
  E getme (int index);
};

and use it in exactly the same places you would use D<something>.

In fact, one place is in the hash table code we are discussing.
The hash descriptor type may not itself be a template.  I believe
that few of them will actually be templates.

So, if E implies comes from template, the implication is wrong.

If we were to follow C++ standard library conventions, we would call
it value_type.  That would be my preference.  However, if folks
want a shorter name, I'll live with that too.  But as it stands,
the current name is very confusing.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-27 20:51                   ` Lawrence Crowl
@ 2012-09-28  1:44                     ` Gabriel Dos Reis
  2012-09-28 15:08                     ` Michael Matz
  1 sibling, 0 replies; 29+ messages in thread
From: Gabriel Dos Reis @ 2012-09-28  1:44 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Michael Matz, Richard Henderson, Richard Guenther, Diego Novillo,
	gcc-patches

On Thu, Sep 27, 2012 at 1:35 PM, Lawrence Crowl <crowl@google.com> wrote:

> If we were to follow C++ standard library conventions, we would call
> it value_type.  That would be my preference.  However, if folks
> want a shorter name, I'll live with that too.  But as it stands,
> the current name is very confusing.

Yes, and there appears to be no good reason to let it stand.

-- Gaby

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-27 20:51                   ` Lawrence Crowl
  2012-09-28  1:44                     ` Gabriel Dos Reis
@ 2012-09-28 15:08                     ` Michael Matz
  2012-09-28 15:21                       ` Gabriel Dos Reis
  2012-09-28 19:47                       ` Lawrence Crowl
  1 sibling, 2 replies; 29+ messages in thread
From: Michael Matz @ 2012-09-28 15:08 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Richard Henderson, Richard Guenther, Diego Novillo, gcc-patches

Hi,

On Thu, 27 Sep 2012, Lawrence Crowl wrote:

> > template <typename T>
> > struct D : B<T>
> > {
> >   typedef typename B<T>::E E; // element_type
> >   E getme (int index);
> > }
> 
> Inside that struct, lets say we have a field of type E.  Do we name
> it F or f?

IMHO only for types, not for any other decls.

> > > Do you have an alternate suggestion, one that does not confuse
> > > template parameters and dependent names?
> >
> > Upper last character?  Just kidding :)  Too many detailed rules
> > for conventions are the death of them, use rules of thumbs,
> > my one would be "somehow depends on template args -> has upper
> > character in name", where "somehow depends on" includes "is a".
> 
> Ah, but there is a problem.  That typedef name does not necessarily
> depend on a template parameter.
> 
> It is common practice to have
> 
> struct Q
> {
>   typedef int E;
>   E getme (int index);
> };

Easy: I wouldn't make a typedef for Q::E that merely is int.  The reason 
is that it makes knowing what getme really returns harder.  You have to 
look it up always (or know the class already).  In fact that's one of my 
gripes with the standard library, much too much indirection through 
entities merely referring to other entities.  Might be only important for 
the libraries implementors but I sure hope that we don't start down that 
road in GCC.

> In fact, one place is in the hash table code we are discussing.
> The hash descriptor type may not itself be a template.  I believe
> that few of them will actually be templates.

Then I don't see the need for class-local typedefs.

> So, if E implies comes from template, the implication is wrong.
> 
> If we were to follow C++ standard library conventions, we would call it 
> value_type.

Well, but value_type surely does depend on the hashtables type argument, 
doesn't it?   After all it is a typedef from 'Key'.
I would expect that htab<tree>::value_type is tree, and 
htab<int>::value_type is int, and I would like to see it named 
htab<tree>::T or ::E.

> That would be my preference.  However, if folks want a shorter name, 
> I'll live with that too.  But as it stands, the current name is very 
> confusing.

I would even prefer 'e' over value_type.  It's scoped, the context always 
will be clear, no need to be verbose in that name.  I find the long names 
inelegant, as most of the standard libs conventions.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-28 15:08                     ` Michael Matz
@ 2012-09-28 15:21                       ` Gabriel Dos Reis
  2012-09-28 20:07                         ` Lawrence Crowl
  2012-09-28 19:47                       ` Lawrence Crowl
  1 sibling, 1 reply; 29+ messages in thread
From: Gabriel Dos Reis @ 2012-09-28 15:21 UTC (permalink / raw)
  To: Michael Matz
  Cc: Lawrence Crowl, Richard Henderson, Richard Guenther,
	Diego Novillo, gcc-patches

On Fri, Sep 28, 2012 at 8:18 AM, Michael Matz <matz@suse.de> wrote:

>> It is common practice to have
>>
>> struct Q
>> {
>>   typedef int E;
>>   E getme (int index);
>> };
>
> Easy: I wouldn't make a typedef for Q::E that merely is int.  The reason
> is that it makes knowing what getme really returns harder.

The point of these nested type is precisely to allow  a *uniform* access
to associated from within a template (e.g. a container) -- irrespective of
what those types happen to resolve to, builtin or not.

-- Gaby

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-28 15:08                     ` Michael Matz
  2012-09-28 15:21                       ` Gabriel Dos Reis
@ 2012-09-28 19:47                       ` Lawrence Crowl
  2012-09-28 20:03                         ` Diego Novillo
  1 sibling, 1 reply; 29+ messages in thread
From: Lawrence Crowl @ 2012-09-28 19:47 UTC (permalink / raw)
  To: Michael Matz
  Cc: Richard Henderson, Richard Guenther, Diego Novillo, gcc-patches

On 9/28/12, Michael Matz <matz@suse.de> wrote:
> On Thu, 27 Sep 2012, Lawrence Crowl wrote:
> > > template <typename T>
> > > struct D : B<T>
> > > {
> > >   typedef typename B<T>::E E; // element_type
> > >   E getme (int index);
> > > }
> >
> > Inside that struct, lets say we have a field of type E.  Do we name
> > it F or f?
>
> IMHO only for types, not for any other decls.
>
> > > > Do you have an alternate suggestion, one that does not confuse
> > > > template parameters and dependent names?
> > >
> > > Upper last character?  Just kidding :)  Too many detailed rules
> > > for conventions are the death of them, use rules of thumbs,
> > > my one would be "somehow depends on template args -> has upper
> > > character in name", where "somehow depends on" includes "is a".
> >
> > Ah, but there is a problem.  That typedef name does not necessarily
> > depend on a template parameter.
> >
> > It is common practice to have
> >
> > struct Q
> > {
> >   typedef int E;
> >   E getme (int index);
> > };
>
> Easy: I wouldn't make a typedef for Q::E that merely is int.  The reason
> is that it makes knowing what getme really returns harder.  You have to
> look it up always (or know the class already).  In fact that's one of my
> gripes with the standard library, much too much indirection through
> entities merely referring to other entities.  Might be only important for
> the libraries implementors but I sure hope that we don't start down that
> road in GCC.
>
> > In fact, one place is in the hash table code we are discussing.
> > The hash descriptor type may not itself be a template.  I believe
> > that few of them will actually be templates.
>
> Then I don't see the need for class-local typedefs.
>
> > So, if E implies comes from template, the implication is wrong.
> >
> > If we were to follow C++ standard library conventions, we would call it
> > value_type.
>
> Well, but value_type surely does depend on the hashtables
> type argument, doesn't it?  After all it is a typedef from
> 'Key'.  I would expect that htab<tree>::value_type is tree, and
> htab<int>::value_type is int, and I would like to see it named
> htab<tree>::T or ::E.

One declares a hash table as follows.

  hash_table <hash_descriptor> variable;

The type stored in the hash table is not part of the declaration.
It is part of the descriptor, along with other things like the
hash function.  The hash table essentially queries the descriptor
for the value type.  For example,

  template <Descriptor> class hash_table {
    typename Descriptor::value_type *storage;
    ...

More typically though, the typedef is repeated inside the class to
avoid excess verbosity, and more importantly, to reexport the name.

  template <Descriptor> class hash_table {
    typedef typename Descriptor::value_type value_type;
    value_type *storage;
    ...

Using these typedef names is an essential component of the
abstraction.  Without it, we end up going to void* and loosing all
type safety.

> > That would be my preference.  However, if folks want a shorter name,
> > I'll live with that too.  But as it stands, the current name is very
> > confusing.
>
> I would even prefer 'e' over value_type.  It's scoped, the context always
> will be clear, no need to be verbose in that name.  I find the long names
> inelegant, as most of the standard libs conventions.

We need some convention.  If we choose a convention different from
the standard library, then we are essentially saying that we do not
intend to interoperate with the standard library.  I do not think
that is the intent of the community, but I could be wrong about that.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-28 19:47                       ` Lawrence Crowl
@ 2012-09-28 20:03                         ` Diego Novillo
  0 siblings, 0 replies; 29+ messages in thread
From: Diego Novillo @ 2012-09-28 20:03 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Michael Matz, Richard Henderson, Richard Guenther, gcc-patches

On Fri, Sep 28, 2012 at 12:40 PM, Lawrence Crowl <crowl@google.com> wrote:
> On 9/28/12, Michael Matz <matz@suse.de> wrote:
>>
>> I would even prefer 'e' over value_type.  It's scoped, the context always
>> will be clear, no need to be verbose in that name.  I find the long names
>> inelegant, as most of the standard libs conventions.
>
> We need some convention.  If we choose a convention different from
> the standard library, then we are essentially saying that we do not
> intend to interoperate with the standard library.  I do not think
> that is the intent of the community, but I could be wrong about that.

I agree.  If there already exists a convention that is widely known
and recognized, then we should use it.  There is negative value in
inventing a new convention.  We need to lower barriers to adoption,
not raise them.

Using the standard library convention seems to me like the best thing
to do here.


Diego.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
  2012-09-28 15:21                       ` Gabriel Dos Reis
@ 2012-09-28 20:07                         ` Lawrence Crowl
  0 siblings, 0 replies; 29+ messages in thread
From: Lawrence Crowl @ 2012-09-28 20:07 UTC (permalink / raw)
  To: Gabriel Dos Reis
  Cc: Michael Matz, Richard Henderson, Richard Guenther, Diego Novillo,
	gcc-patches

On 9/28/12, Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> On Fri, Sep 28, 2012 at 8:18 AM, Michael Matz <matz@suse.de> wrote:
>>> It is common practice to have
>>>
>>> struct Q
>>> {
>>>   typedef int E;
>>>   E getme (int index);
>>> };
>>
>> Easy: I wouldn't make a typedef for Q::E that merely is int.  The reason
>> is that it makes knowing what getme really returns harder.
>
> The point of these nested type is precisely to allow  a *uniform* access
> to associated from within a template (e.g. a container) -- irrespective of
> what those types happen to resolve to, builtin or not.

Perhaps an analogy might be helpful.  If I say "Tim's father" you know
role of that person without knowing exactly who it is.  The typedef
convention serves the same purpose.  It is important that we use the
same term for father, or we wouldn't be able to communicate.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2012-09-28 19:45 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-12 20:14 Merge C++ conversion into trunk (4/6 - hash table rewrite) Diego Novillo
2012-08-15 10:59 ` Richard Guenther
2012-08-15 13:00 ` Richard Guenther
2012-08-15 13:41   ` Richard Guenther
2012-08-15 14:05     ` Michael Matz
2012-08-15 14:32       ` Richard Guenther
2012-08-15 16:17         ` Richard Henderson
2012-08-15 21:58           ` Lawrence Crowl
2012-08-15 22:26             ` Ian Lance Taylor
2012-08-16  9:22             ` Richard Guenther
2012-08-16 14:56               ` Paolo Carlini
2012-08-16 14:58                 ` Richard Guenther
2012-08-16 19:02               ` Lawrence Crowl
2012-09-25 23:19           ` Lawrence Crowl
2012-09-26 13:48             ` Michael Matz
2012-09-26 20:20               ` Lawrence Crowl
2012-09-26 20:28                 ` Gabriel Dos Reis
2012-09-27 12:55                 ` Michael Matz
2012-09-27 13:01                   ` Gabriel Dos Reis
2012-09-27 20:51                   ` Lawrence Crowl
2012-09-28  1:44                     ` Gabriel Dos Reis
2012-09-28 15:08                     ` Michael Matz
2012-09-28 15:21                       ` Gabriel Dos Reis
2012-09-28 20:07                         ` Lawrence Crowl
2012-09-28 19:47                       ` Lawrence Crowl
2012-09-28 20:03                         ` Diego Novillo
2012-09-26 14:51             ` Gabriel Dos Reis
2012-08-15 21:57         ` Lawrence Crowl
2012-08-15 21:52   ` Lawrence Crowl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).