From: Trevor Saunders Date: Tue, 24 Jun 2014 13:21:53 +0000 (+0000) Subject: allow storing values directly in hash tables X-Git-Tag: releases/gcc-5.1.0~6695 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=84baa4b968f2dbf4e85e49dba9215ad0f0f3ddc8;p=thirdparty%2Fgcc.git allow storing values directly in hash tables gcc/ * hash-table.h: Add a template arg to choose between storing values and storing pointers to values, and then provide partial specializations for both. * tree-browser.c (tree_upper_hasher): Provide the type the hash table should store, not the type values should point to. * tree-into-ssa.c (var_info_hasher): Likewise. * tree-ssa-dom.c (expr_elt_hasher): Likewise. * tree-complex.c: Adjust. * tree-hasher.h (int_tree_hasher): store int_tree_map in the hash table instead of int_tree_map *. * tree-parloops.c: Adjust. * tree-ssa-reassoc.c (ocount_hasher): Don't lie to hash_map about what type is being stored. * tree-vectorizer.c: Adjust. From-SVN: r211937 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ca591a663050..bf1a716e751c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2014-06-24 Trevor Saunders + + * hash-table.h: Add a template arg to choose between storing values + and storing pointers to values, and then provide partial + specializations for both. + * tree-browser.c (tree_upper_hasher): Provide the type the hash table + should store, not the type values should point to. + * tree-into-ssa.c (var_info_hasher): Likewise. + * tree-ssa-dom.c (expr_elt_hasher): Likewise. + * tree-complex.c: Adjust. + * tree-hasher.h (int_tree_hasher): store int_tree_map in the hash + table instead of int_tree_map *. + * tree-parloops.c: Adjust. + * tree-ssa-reassoc.c (ocount_hasher): Don't lie to hash_map about what + type is being stored. + * tree-vectorizer.c: Adjust. + 2014-06-24 Trevor Saunders * hash-table.h: Remove a layer of indirection from hash_table so that diff --git a/gcc/hash-table.h b/gcc/hash-table.h index 41cc19e52fb3..22af12f996c1 100644 --- a/gcc/hash-table.h +++ b/gcc/hash-table.h @@ -272,19 +272,18 @@ typed_noop_remove ::remove (Type *p ATTRIBUTE_UNUSED) template struct pointer_hash : typed_noop_remove { - typedef Type value_type; - typedef Type compare_type; + typedef Type *value_type; + typedef Type *compare_type; + typedef int store_values_directly; - static inline hashval_t - hash (const value_type *); + static inline hashval_t hash (const value_type &); - static inline int - equal (const value_type *existing, const compare_type *candidate); + static inline bool equal (const value_type &existing, const compare_type &candidate); }; template inline hashval_t -pointer_hash ::hash (const value_type *candidate) +pointer_hash ::hash (const value_type &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. */ @@ -292,9 +291,9 @@ pointer_hash ::hash (const value_type *candidate) } template -inline int -pointer_hash ::equal (const value_type *existing, - const compare_type *candidate) +inline bool +pointer_hash ::equal (const value_type &existing, + const compare_type &candidate) { return existing == candidate; } @@ -319,10 +318,147 @@ 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); +/* The below is some template meta programming to decide if we should use the + hash table partial specialization that directly stores value_type instead of + pointers to value_type. If the Descriptor type defines the type + Descriptor::store_values_directly then values are stored directly otherwise + pointers to them are stored. */ +template struct notype { typedef void type; }; + +template +struct storage_tester +{ + static const bool value = false; +}; + +template +struct storage_tester::type> +{ + static const bool value = true; +}; + + template + struct has_is_deleted +{ + template struct helper {}; + template static char test (helper *); + template static int test (...); + static const bool value = sizeof (test (0)) == sizeof (char); +}; + +template::value> +struct is_deleted_helper +{ + static inline bool + call (Type &v) + { + return Traits::is_deleted (v); + } +}; + +template +struct is_deleted_helper +{ + static inline bool + call (Type *v) + { + return v == HTAB_DELETED_ENTRY; + } +}; + + template + struct has_is_empty +{ + template struct helper {}; + template static char test (helper *); + template static int test (...); + static const bool value = sizeof (test (0)) == sizeof (char); +}; + +template::value> +struct is_empty_helper +{ + static inline bool + call (Type &v) + { + return Traits::is_empty (v); + } +}; + +template +struct is_empty_helper +{ + static inline bool + call (Type *v) + { + return v == HTAB_EMPTY_ENTRY; + } +}; + + template + struct has_mark_deleted +{ + template struct helper {}; + template static char test (helper *); + template static int test (...); + static const bool value = sizeof (test (0)) == sizeof (char); +}; + +template::value> +struct mark_deleted_helper +{ + static inline void + call (Type &v) + { + Traits::mark_deleted (v); + } +}; + +template +struct mark_deleted_helper +{ + static inline void + call (Type *&v) + { + v = static_cast (HTAB_DELETED_ENTRY); + } +}; + + template + struct has_mark_empty +{ + template struct helper {}; + template static char test (helper *); + template static int test (...); + static const bool value = sizeof (test (0)) == sizeof (char); +}; + +template::value> +struct mark_empty_helper +{ + static inline void + call (Type &v) + { + Traits::mark_empty (v); + } +}; + +template +struct mark_empty_helper +{ + static inline void + call (Type *&v) + { + v = static_cast (HTAB_EMPTY_ENTRY); + } +}; /* User-facing hash table type. - The table stores elements of type Descriptor::value_type. + The table stores elements of type Descriptor::value_type, or pointers to + objects of type value_type if the descriptor does not define the type + store_values_directly. It hashes values with the hash member function. The table currently works with relatively weak hash functions. @@ -340,10 +476,20 @@ extern hashval_t hash_table_mod2 (hashval_t hash, unsigned int index); Specify the template Allocator to allocate and free memory. The default is xcallocator. + Storage is an implementation detail and should not be used outside the + hash table code. + */ template class Allocator= xcallocator> + template class Allocator= xcallocator, + bool Storage = storage_tester::value> class hash_table +{ +}; + +template class Allocator> +class hash_table { typedef typename Descriptor::value_type value_type; typedef typename Descriptor::compare_type compare_type; @@ -428,7 +574,7 @@ public: iterator (value_type **slot, value_type **limit) : m_slot (slot), m_limit (limit) {} - inline value_type &operator * () { return **m_slot; } + inline value_type *operator * () { return *m_slot; } void slide (); inline iterator &operator ++ (); bool operator != (const iterator &other) const @@ -485,7 +631,7 @@ private: }; template class Allocator> -hash_table::hash_table (size_t size) : +hash_table::hash_table (size_t size) : m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0) { unsigned int size_prime_index; @@ -500,7 +646,7 @@ hash_table::hash_table (size_t size) : } template class Allocator> -hash_table::~hash_table () +hash_table::~hash_table () { for (size_t i = m_size - 1; i < m_size; i--) if (m_entries[i] != HTAB_EMPTY_ENTRY && m_entries[i] != HTAB_DELETED_ENTRY) @@ -518,7 +664,8 @@ hash_table::~hash_table () template class Allocator> typename Descriptor::value_type ** -hash_table::find_empty_slot_for_expand (hashval_t hash) +hash_table +::find_empty_slot_for_expand (hashval_t hash) { hashval_t index = hash_table_mod1 (hash, m_size_prime_index); size_t size = m_size; @@ -554,7 +701,7 @@ hash_table::find_empty_slot_for_expand (hashval_t hash) template class Allocator> void -hash_table::expand () +hash_table::expand () { value_type **oentries = m_entries; unsigned int oindex = m_size_prime_index; @@ -606,7 +753,7 @@ hash_table::expand () template class Allocator> void -hash_table::empty () +hash_table::empty () { size_t size = m_size; value_type **entries = m_entries; @@ -639,7 +786,7 @@ hash_table::empty () template class Allocator> void -hash_table::clear_slot (value_type **slot) +hash_table::clear_slot (value_type **slot) { if (slot < m_entries || slot >= m_entries + size () || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY) @@ -657,7 +804,7 @@ hash_table::clear_slot (value_type **slot) template class Allocator> typename Descriptor::value_type * -hash_table +hash_table ::find_with_hash (const compare_type *comparable, hashval_t hash) { m_searches++; @@ -695,7 +842,7 @@ hash_table template class Allocator> typename Descriptor::value_type ** -hash_table +hash_table ::find_slot_with_hash (const compare_type *comparable, hashval_t hash, enum insert_option insert) { @@ -756,7 +903,7 @@ hash_table template class Allocator> void -hash_table +hash_table ::remove_elt_with_hash (const compare_type *comparable, hashval_t hash) { value_type **slot = find_slot_with_hash (comparable, hash, NO_INSERT); @@ -773,12 +920,11 @@ hash_table each live entry. If CALLBACK returns false, the iteration stops. ARGUMENT is passed as CALLBACK's second argument. */ -template class Allocator> +template class Allocator> template void -hash_table::traverse_noresize (Argument argument) +hash_table::traverse_noresize (Argument argument) { value_type **slot = m_entries; value_type **limit = slot + size (); @@ -803,7 +949,7 @@ template void -hash_table::traverse (Argument argument) +hash_table::traverse (Argument argument) { size_t size = m_size; if (elements () * 8 < size && size > 32) @@ -816,7 +962,7 @@ hash_table::traverse (Argument argument) template class Allocator> void -hash_table::iterator::slide () +hash_table::iterator::slide () { for ( ; m_slot < m_limit; ++m_slot ) { @@ -831,8 +977,527 @@ hash_table::iterator::slide () /* Bump the iterator. */ template class Allocator> -inline typename hash_table::iterator & -hash_table::iterator::operator ++ () +inline typename hash_table::iterator & +hash_table::iterator::operator ++ () +{ + ++m_slot; + slide (); + return *this; +} + +/* A partial specialization used when values should be stored directly. */ + +template class Allocator> +class hash_table +{ + typedef typename Descriptor::value_type value_type; + typedef typename Descriptor::compare_type compare_type; + +public: + hash_table (size_t); + ~hash_table (); + + /* Current size (in entries) of the hash table. */ + size_t size () const { return m_size; } + + /* Return the current number of elements in this hash table. */ + size_t elements () const { return m_n_elements - m_n_deleted; } + + /* Return the current number of elements in this hash table. */ + size_t elements_with_deleted () const { return m_n_elements; } + + /* This function clears all entries in the given hash table. */ + void empty (); + + /* 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. */ + + void clear_slot (value_type *); + + /* 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. */ + value_type &find_with_hash (const compare_type &, hashval_t); + +/* Like find_slot_with_hash, but compute the hash value from the element. */ + value_type &find (const value_type &value) + { + return find_with_hash (value, Descriptor::hash (value)); + } + + value_type *find_slot (const value_type &value, insert_option insert) + { + return find_slot_with_hash (value, Descriptor::hash (value), insert); + } + + /* 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. */ + value_type *find_slot_with_hash (const compare_type &comparable, + hashval_t hash, enum insert_option insert); + + /* 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. */ + void remove_elt_with_hash (const compare_type &, hashval_t); + +/* Like remove_elt_with_hash, but compute the hash value from the element. */ + void remove_elt (const value_type &value) + { + remove_elt_with_hash (value, Descriptor::hash (value)); + } + + /* 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 + void traverse_noresize (Argument argument); + + /* Like traverse_noresize, but does resize the table when it is too empty + to improve effectivity of subsequent calls. */ + template + void traverse (Argument argument); + + class iterator + { + public: + iterator () : m_slot (NULL), m_limit (NULL) {} + + iterator (value_type *slot, value_type *limit) : + m_slot (slot), m_limit (limit) {} + + inline value_type &operator * () { return *m_slot; } + void slide (); + inline iterator &operator ++ (); + bool operator != (const iterator &other) const + { + return m_slot != other.m_slot || m_limit != other.m_limit; + } + + private: + value_type *m_slot; + value_type *m_limit; + }; + + iterator begin () const + { + iterator iter (m_entries, m_entries + m_size); + iter.slide (); + return iter; + } + + iterator end () const { return iterator (); } + + double collisions () const + { + return m_searches ? static_cast (m_collisions) / m_searches : 0; + } + +private: + + value_type *find_empty_slot_for_expand (hashval_t); + void expand (); + static bool is_deleted (value_type &v) + { + return is_deleted_helper::call (v); + } + static bool is_empty (value_type &v) + { + return is_empty_helper::call (v); + } + + static void mark_deleted (value_type &v) + { + return mark_deleted_helper::call (v); + } + + static void mark_empty (value_type &v) + { + return mark_empty_helper::call (v); + } + + /* Table itself. */ + typename Descriptor::value_type *m_entries; + + size_t m_size; + + /* Current number of elements including also deleted elements. */ + size_t m_n_elements; + + /* Current number of deleted elements in the table. */ + size_t m_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 m_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 m_collisions; + + /* Current size (in entries) of the hash table, as an index into the + table of primes. */ + unsigned int m_size_prime_index; +}; + +template class Allocator> +hash_table::hash_table (size_t size) : + m_n_elements (0), m_n_deleted (0), m_searches (0), m_collisions (0) +{ + unsigned int size_prime_index; + + size_prime_index = hash_table_higher_prime_index (size); + size = prime_tab[size_prime_index].prime; + + m_entries = Allocator ::data_alloc (size); + gcc_assert (m_entries != NULL); + m_size = size; + m_size_prime_index = size_prime_index; +} + +template class Allocator> +hash_table::~hash_table () +{ + for (size_t i = m_size - 1; i < m_size; i--) + if (!is_empty (m_entries[i]) && !is_deleted (m_entries[i])) + Descriptor::remove (m_entries[i]); + + Allocator ::data_free (m_entries); +} + +/* 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 class Allocator> +typename Descriptor::value_type * +hash_table +::find_empty_slot_for_expand (hashval_t hash) +{ + hashval_t index = hash_table_mod1 (hash, m_size_prime_index); + size_t size = m_size; + value_type *slot = m_entries + index; + hashval_t hash2; + + if (is_empty (*slot)) + return slot; + else if (is_deleted (*slot)) + abort (); + + hash2 = hash_table_mod2 (hash, m_size_prime_index); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + slot = m_entries + index; + if (is_empty (*slot)) + return slot; + else if (is_deleted (*slot)) + 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 class Allocator> +void +hash_table::expand () +{ + value_type *oentries = m_entries; + unsigned int oindex = m_size_prime_index; + size_t osize = size (); + value_type *olimit = oentries + osize; + size_t elts = elements (); + + /* Resize only when table after removal of unused elements is either + too full or too empty. */ + unsigned int nindex; + size_t nsize; + 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; + } + + value_type *nentries = Allocator ::data_alloc (nsize); + gcc_assert (nentries != NULL); + m_entries = nentries; + m_size = nsize; + m_size_prime_index = nindex; + m_n_elements -= m_n_deleted; + m_n_deleted = 0; + + value_type *p = oentries; + do + { + value_type &x = *p; + + if (!is_empty (x) && !is_deleted (x)) + { + value_type *q = find_empty_slot_for_expand (Descriptor::hash (x)); + + *q = x; + } + + p++; + } + while (p < olimit); + + Allocator ::data_free (oentries); +} + +template class Allocator> +void +hash_table::empty () +{ + size_t size = m_size; + value_type *entries = m_entries; + int i; + + for (i = size - 1; i >= 0; i--) + if (!is_empty (entries[i]) && !is_deleted (entries[i])) + Descriptor::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 ::data_free (m_entries); + m_entries = Allocator ::data_alloc (nsize); + m_size = nsize; + m_size_prime_index = nindex; + } + else + memset (entries, 0, size * sizeof (value_type)); + m_n_deleted = 0; + m_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 class Allocator> +void +hash_table::clear_slot (value_type *slot) +{ + if (slot < m_entries || slot >= m_entries + size () + || is_empty (*slot) || is_deleted (*slot)) + abort (); + + Descriptor::remove (*slot); + + mark_deleted (*slot); + m_n_deleted++; +} + +/* 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 class Allocator> +typename Descriptor::value_type & +hash_table +::find_with_hash (const compare_type &comparable, hashval_t hash) +{ + m_searches++; + size_t size = m_size; + hashval_t index = hash_table_mod1 (hash, m_size_prime_index); + + value_type *entry = &m_entries[index]; + if (is_empty (*entry) + || (!is_deleted (*entry) && Descriptor::equal (*entry, comparable))) + return *entry; + + hashval_t hash2 = hash_table_mod2 (hash, m_size_prime_index); + for (;;) + { + m_collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = &m_entries[index]; + if (is_empty (*entry) + || (!is_deleted (*entry) && Descriptor::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 class Allocator> +typename Descriptor::value_type * +hash_table +::find_slot_with_hash (const compare_type &comparable, hashval_t hash, + enum insert_option insert) +{ + if (insert == INSERT && m_size * 3 <= m_n_elements * 4) + expand (); + + m_searches++; + + value_type *first_deleted_slot = NULL; + hashval_t index = hash_table_mod1 (hash, m_size_prime_index); + hashval_t hash2 = hash_table_mod2 (hash, m_size_prime_index); + value_type *entry = &m_entries[index]; + size_t size = m_size; + if (is_empty (*entry)) + goto empty_entry; + else if (is_deleted (*entry)) + first_deleted_slot = &m_entries[index]; + else if (Descriptor::equal (*entry, comparable)) + return &m_entries[index]; + + for (;;) + { + m_collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = &m_entries[index]; + if (is_empty (*entry)) + goto empty_entry; + else if (is_deleted (*entry)) + { + if (!first_deleted_slot) + first_deleted_slot = &m_entries[index]; + } + else if (Descriptor::equal (*entry, comparable)) + return &m_entries[index]; + } + + empty_entry: + if (insert == NO_INSERT) + return NULL; + + if (first_deleted_slot) + { + m_n_deleted--; + mark_empty (*first_deleted_slot); + return first_deleted_slot; + } + + m_n_elements++; + return &m_entries[index]; +} + +/* 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 class Allocator> +void +hash_table +::remove_elt_with_hash (const compare_type &comparable, hashval_t hash) +{ + value_type *slot = find_slot_with_hash (comparable, hash, NO_INSERT); + if (is_empty (*slot)) + return; + + Descriptor::remove (*slot); + + mark_deleted (*slot); + m_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 class Allocator> +template +void +hash_table::traverse_noresize (Argument argument) +{ + value_type *slot = m_entries; + value_type *limit = slot + size (); + + do + { + value_type &x = *slot; + + if (!is_empty (x) && !is_deleted (x)) + 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 class Allocator> +template +void +hash_table::traverse (Argument argument) +{ + size_t size = m_size; + if (elements () * 8 < size && size > 32) + expand (); + + traverse_noresize (argument); +} + +/* Slide down the iterator slots until an active entry is found. */ + +template class Allocator> +void +hash_table::iterator::slide () +{ + for ( ; m_slot < m_limit; ++m_slot ) + { + value_type &x = *m_slot; + if (!is_empty (x) && !is_deleted (x)) + return; + } + m_slot = NULL; + m_limit = NULL; +} + +/* Bump the iterator. */ + +template class Allocator> +inline typename hash_table::iterator & +hash_table::iterator::operator ++ () { ++m_slot; slide (); @@ -846,7 +1511,7 @@ hash_table::iterator::operator ++ () #define FOR_EACH_HASH_TABLE_ELEMENT(HTAB, RESULT, TYPE, ITER) \ for ((ITER) = (HTAB).begin (); \ - (ITER) != (HTAB).end () ? (RESULT = &*(ITER) , true) : false; \ + (ITER) != (HTAB).end () ? (RESULT = *(ITER) , true) : false; \ ++(ITER)) #endif /* TYPED_HASHTAB_H */ diff --git a/gcc/tree-browser.c b/gcc/tree-browser.c index 8c03550d58c0..2a4db1b30957 100644 --- a/gcc/tree-browser.c +++ b/gcc/tree-browser.c @@ -102,22 +102,13 @@ static tree TB_history_prev (void); void browse_tree (tree); /* Hashtable helpers. */ -struct tree_upper_hasher : typed_noop_remove +struct tree_upper_hasher : pointer_hash { - typedef tree_node value_type; - typedef tree_node compare_type; - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); + static inline bool equal (const value_type &, const compare_type &); }; -inline hashval_t -tree_upper_hasher::hash (const value_type *v) -{ - return pointer_hash ::hash (v); -} - inline bool -tree_upper_hasher::equal (const value_type *parent, const compare_type *node) +tree_upper_hasher::equal (const value_type &parent, const compare_type &node) { if (parent == NULL || node == NULL) return 0; diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c index 7b0115d0f521..3ed403a1c85c 100644 --- a/gcc/tree-complex.c +++ b/gcc/tree-complex.c @@ -83,10 +83,9 @@ static vec complex_ssa_name_components; static tree cvc_lookup (unsigned int uid) { - struct int_tree_map *h, in; + struct int_tree_map in; in.uid = uid; - h = complex_variable_components->find_with_hash (&in, uid); - return h ? h->to : NULL; + return complex_variable_components->find_with_hash (in, uid).to; } /* Insert the pair UID, TO into the complex_variable_components hashtable. */ @@ -94,14 +93,13 @@ cvc_lookup (unsigned int uid) static void cvc_insert (unsigned int uid, tree to) { - struct int_tree_map *h; - int_tree_map **loc; + int_tree_map h; + int_tree_map *loc; - h = XNEW (struct int_tree_map); - h->uid = uid; - h->to = to; + h.uid = uid; loc = complex_variable_components->find_slot_with_hash (h, uid, INSERT); - *loc = h; + loc->uid = uid; + loc->to = to; } /* Return true if T is not a zero constant. In the case of real values, diff --git a/gcc/tree-hasher.h b/gcc/tree-hasher.h index 6b2800835149..ae56a84d1ce2 100644 --- a/gcc/tree-hasher.h +++ b/gcc/tree-hasher.h @@ -30,28 +30,37 @@ struct int_tree_map { /* Hashtable helpers. */ -struct int_tree_hasher : typed_free_remove +struct int_tree_hasher { typedef int_tree_map value_type; typedef int_tree_map compare_type; - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); + typedef int store_values_directly; + static inline hashval_t hash (const value_type &); + static inline bool equal (const value_type &, const compare_type &); + static bool is_deleted (const value_type &v) + { + return v.to == reinterpret_cast (1); + } + static void mark_deleted (value_type &v) { v.to = reinterpret_cast (0x1); } + static bool is_empty (const value_type &v) { return v.to == NULL; } + static void mark_empty (value_type &v) { v.to = NULL; } + static void remove (value_type &) {} }; /* Hash a UID in a int_tree_map. */ inline hashval_t -int_tree_hasher::hash (const value_type *item) +int_tree_hasher::hash (const value_type &item) { - return item->uid; + return item.uid; } /* Return true if the uid in both int tree maps are equal. */ inline bool -int_tree_hasher::equal (const value_type *a, const compare_type *b) +int_tree_hasher::equal (const value_type &a, const compare_type &b) { - return (a->uid == b->uid); + return (a.uid == b.uid); } typedef hash_table int_tree_htab_type; diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 1cdcc2faa7c3..96255f9a5593 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -203,20 +203,21 @@ typedef struct var_info_d *var_info_p; struct var_info_hasher : typed_free_remove { - typedef var_info_d value_type; - typedef var_info_d compare_type; - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); + typedef var_info_d *value_type; + typedef var_info_d *compare_type; + typedef int store_values_directly; + static inline hashval_t hash (const value_type &); + static inline bool equal (const value_type &, const compare_type &); }; inline hashval_t -var_info_hasher::hash (const value_type *p) +var_info_hasher::hash (const value_type &p) { return DECL_UID (p->var); } inline bool -var_info_hasher::equal (const value_type *p1, const compare_type *p2) +var_info_hasher::equal (const value_type &p1, const compare_type &p2) { return p1->var == p2->var; } diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index 3ef4aa632e07..0c486bbebc22 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -489,8 +489,6 @@ take_address_of (tree obj, tree type, edge entry, int_tree_htab_type *decl_address, gimple_stmt_iterator *gsi) { int uid; - int_tree_map **dslot; - struct int_tree_map ielt, *nielt; tree *var_p, name, addr; gimple stmt; gimple_seq stmts; @@ -511,9 +509,10 @@ take_address_of (tree obj, tree type, edge entry, in the address and share it for all accesses and addresses based on it. */ uid = DECL_UID (TREE_OPERAND (TREE_OPERAND (*var_p, 0), 0)); - ielt.uid = uid; - dslot = decl_address->find_slot_with_hash (&ielt, uid, INSERT); - if (!*dslot) + int_tree_map elt; + elt.uid = uid; + int_tree_map *slot = decl_address->find_slot (elt, INSERT); + if (!slot->to) { if (gsi == NULL) return NULL; @@ -527,13 +526,11 @@ take_address_of (tree obj, tree type, edge entry, stmt = gimple_build_assign (name, addr); gsi_insert_on_edge_immediate (entry, stmt); - nielt = XNEW (struct int_tree_map); - nielt->uid = uid; - nielt->to = name; - *dslot = nielt; + slot->uid = uid; + slot->to = name; } else - name = (*dslot)->to; + name = slot->to; /* Express the address in terms of the canonical SSA name. */ TREE_OPERAND (*var_p, 0) = name; @@ -822,10 +819,10 @@ separate_decls_in_region_name (tree name, name_to_copy_table_type *name_copies, { tree copy, var, var_copy; unsigned idx, uid, nuid; - struct int_tree_map ielt, *nielt; + struct int_tree_map ielt; struct name_to_copy_elt elt, *nelt; name_to_copy_elt **slot; - int_tree_map **dslot; + int_tree_map *dslot; if (TREE_CODE (name) != SSA_NAME) return name; @@ -858,29 +855,25 @@ separate_decls_in_region_name (tree name, name_to_copy_table_type *name_copies, uid = DECL_UID (var); ielt.uid = uid; - dslot = decl_copies->find_slot_with_hash (&ielt, uid, INSERT); - if (!*dslot) + dslot = decl_copies->find_slot_with_hash (ielt, uid, INSERT); + if (!dslot->to) { var_copy = create_tmp_var (TREE_TYPE (var), get_name (var)); DECL_GIMPLE_REG_P (var_copy) = DECL_GIMPLE_REG_P (var); - nielt = XNEW (struct int_tree_map); - nielt->uid = uid; - nielt->to = var_copy; - *dslot = nielt; + dslot->uid = uid; + dslot->to = var_copy; /* Ensure that when we meet this decl next time, we won't duplicate it again. */ nuid = DECL_UID (var_copy); ielt.uid = nuid; - dslot = decl_copies->find_slot_with_hash (&ielt, nuid, INSERT); - gcc_assert (!*dslot); - nielt = XNEW (struct int_tree_map); - nielt->uid = nuid; - nielt->to = var_copy; - *dslot = nielt; + dslot = decl_copies->find_slot_with_hash (ielt, nuid, INSERT); + gcc_assert (!dslot->to); + dslot->uid = nuid; + dslot->to = var_copy; } else - var_copy = ((struct int_tree_map *) *dslot)->to; + var_copy = dslot->to; replace_ssa_name_symbol (copy, var_copy); return copy; @@ -944,7 +937,7 @@ separate_decls_in_region_debug (gimple stmt, struct int_tree_map ielt; struct name_to_copy_elt elt; name_to_copy_elt **slot; - int_tree_map **dslot; + int_tree_map *dslot; if (gimple_debug_bind_p (stmt)) var = gimple_debug_bind_get_var (stmt); @@ -956,13 +949,13 @@ separate_decls_in_region_debug (gimple stmt, return true; gcc_assert (DECL_P (var) && SSA_VAR_P (var)); ielt.uid = DECL_UID (var); - dslot = decl_copies->find_slot_with_hash (&ielt, ielt.uid, NO_INSERT); + dslot = decl_copies->find_slot_with_hash (ielt, ielt.uid, NO_INSERT); if (!dslot) return true; if (gimple_debug_bind_p (stmt)) - gimple_debug_bind_set_var (stmt, ((struct int_tree_map *) *dslot)->to); + gimple_debug_bind_set_var (stmt, dslot->to); else if (gimple_debug_source_bind_p (stmt)) - gimple_debug_source_bind_set_var (stmt, ((struct int_tree_map *) *dslot)->to); + gimple_debug_source_bind_set_var (stmt, dslot->to); FOR_EACH_PHI_OR_STMT_USE (use, stmt, oi, SSA_OP_USE) { diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 6c581ba7ba52..61e75b6fb203 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -158,21 +158,22 @@ static void free_expr_hash_elt (void *); struct expr_elt_hasher { - typedef expr_hash_elt value_type; - typedef expr_hash_elt compare_type; - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); - static inline void remove (value_type *); + typedef expr_hash_elt *value_type; + typedef expr_hash_elt *compare_type; + typedef int store_values_directly; + static inline hashval_t hash (const value_type &); + static inline bool equal (const value_type &, const compare_type &); + static inline void remove (value_type &); }; inline hashval_t -expr_elt_hasher::hash (const value_type *p) +expr_elt_hasher::hash (const value_type &p) { return p->hash; } inline bool -expr_elt_hasher::equal (const value_type *p1, const compare_type *p2) +expr_elt_hasher::equal (const value_type &p1, const compare_type &p2) { gimple stmt1 = p1->stmt; const struct hashable_expr *expr1 = &p1->expr; @@ -211,7 +212,7 @@ expr_elt_hasher::equal (const value_type *p1, const compare_type *p2) /* Delete an expr_hash_elt and reclaim its storage. */ inline void -expr_elt_hasher::remove (value_type *element) +expr_elt_hasher::remove (value_type &element) { free_expr_hash_elt (element); } diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 4d0d6c21b06c..4903f4879fab 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -1023,32 +1023,36 @@ static vec cvec; /* Oecount hashtable helpers. */ -struct oecount_hasher : typed_noop_remove +struct oecount_hasher { - /* Note that this hash table stores integers, not pointers. - So, observe the casting in the member functions. */ - typedef void value_type; - typedef void compare_type; - static inline hashval_t hash (const value_type *); - static inline bool equal (const value_type *, const compare_type *); + typedef int value_type; + typedef int compare_type; + typedef int store_values_directly; + static inline hashval_t hash (const value_type &); + static inline bool equal (const value_type &, const compare_type &); + static bool is_deleted (int &v) { return v == 1; } + static void mark_deleted (int &e) { e = 1; } + static bool is_empty (int &v) { return v == 0; } + static void mark_empty (int &e) { e = 0; } + static void remove (int &) {} }; /* Hash function for oecount. */ inline hashval_t -oecount_hasher::hash (const value_type *p) +oecount_hasher::hash (const value_type &p) { - const oecount *c = &cvec[(size_t)p - 42]; + const oecount *c = &cvec[p - 42]; return htab_hash_pointer (c->op) ^ (hashval_t)c->oecode; } /* Comparison function for oecount. */ inline bool -oecount_hasher::equal (const value_type *p1, const compare_type *p2) +oecount_hasher::equal (const value_type &p1, const compare_type &p2) { - const oecount *c1 = &cvec[(size_t)p1 - 42]; - const oecount *c2 = &cvec[(size_t)p2 - 42]; + const oecount *c1 = &cvec[p1 - 42]; + const oecount *c2 = &cvec[p2 - 42]; return (c1->oecode == c2->oecode && c1->op == c2->op); } @@ -1473,23 +1477,23 @@ undistribute_ops_list (enum tree_code opcode, FOR_EACH_VEC_ELT (subops[i], j, oe1) { oecount c; - void **slot; - size_t idx; + int *slot; + int idx; c.oecode = oecode; c.cnt = 1; c.id = next_oecount_id++; c.op = oe1->op; cvec.safe_push (c); idx = cvec.length () + 41; - slot = ctable.find_slot ((void *)idx, INSERT); + slot = ctable.find_slot (idx, INSERT); if (!*slot) { - *slot = (void *)idx; + *slot = idx; } else { cvec.pop (); - cvec[(size_t)*slot - 42].cnt++; + cvec[*slot - 42].cnt++; } } } diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 4d30cfa6a771..60923557df79 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -550,14 +550,14 @@ vectorize_loops (void) for (hash_table::iterator iter = simd_array_to_simduid_htab->begin (); iter != simd_array_to_simduid_htab->end (); ++iter) - if ((*iter).simduid != -1U) + if ((*iter)->simduid != -1U) { - tree decl = (*iter).decl; + tree decl = (*iter)->decl; int vf = 1; if (simduid_to_vf_htab) { simduid_to_vf *p = NULL, data; - data.simduid = (*iter).simduid; + data.simduid = (*iter)->simduid; p = simduid_to_vf_htab->find (&data); if (p) vf = p->vf;