This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
- From: Richard Guenther <rguenther at suse dot de>
- To: Diego Novillo <dnovillo at google dot com>
- Cc: gcc-patches at gcc dot gnu dot org, crowl at google dot com, Richard Henderson <rth at redhat dot com>
- Date: Wed, 15 Aug 2012 12:56:16 +0200 (CEST)
- Subject: Re: Merge C++ conversion into trunk (4/6 - hash table rewrite)
- References: <20120812201408.GA14869@google.com>
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);
> }
>
> -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