This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/N] allow storing values directly in hash tables


From: Trevor Saunders <tsaunders@mozilla.com>

Hi,

this patch allows you to define the type the hash table stores as elements
instead of the type elements point at by having your hash descriptor define the
type store_values_directly.  It turns out trying to implement both cases with
the same code is really confusing, so I ended up providing one partial
specialization for each case.  Its a lot of coppying, but I'm hoping the next
patch will get rid of many direct users of hash_table, and the rest can all get
converted to tell the hash table the type entries should have at which point
the dupplication can be removed.

bootstrapped + regtested without regression on x86_64-unknown-linux-gnu, ok?

Trev

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.

diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 41cc19e..22af12f 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -272,19 +272,18 @@ typed_noop_remove <Type>::remove (Type *p ATTRIBUTE_UNUSED)
 template <typename Type>
 struct pointer_hash : typed_noop_remove <Type>
 {
-  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 <typename Type>
 inline hashval_t
-pointer_hash <Type>::hash (const value_type *candidate)
+pointer_hash <Type>::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 <Type>::hash (const value_type *candidate)
 }
 
 template <typename Type>
-inline int
-pointer_hash <Type>::equal (const value_type *existing,
-			   const compare_type *candidate)
+inline bool
+pointer_hash <Type>::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<typename T> struct notype { typedef void type; };
+
+template<typename T, typename = void>
+struct storage_tester
+{
+  static const bool value = false;
+};
+
+template<typename T>
+struct storage_tester<T, typename notype<typename
+					 T::store_values_directly>::type>
+{
+  static const bool value = true;
+};
+
+ template<typename Traits>
+ struct has_is_deleted
+{
+  template<typename U, bool (*)(U &)> struct helper {};
+  template<typename U> static char test (helper<U, U::is_deleted> *);
+  template<typename U> static int test (...);
+  static const bool value = sizeof (test<Traits> (0)) == sizeof (char);
+};
+
+template<typename Type, typename Traits, bool = has_is_deleted<Traits>::value>
+struct is_deleted_helper
+{
+  static inline bool
+  call (Type &v)
+  {
+    return Traits::is_deleted (v);
+  }
+};
+
+template<typename Type, typename Traits>
+struct is_deleted_helper<Type *, Traits, false>
+{
+  static inline bool
+  call (Type *v)
+  {
+    return v == HTAB_DELETED_ENTRY;
+  }
+};
+
+ template<typename Traits>
+ struct has_is_empty
+{
+  template<typename U, bool (*)(U &)> struct helper {};
+  template<typename U> static char test (helper<U, U::is_empty> *);
+  template<typename U> static int test (...);
+  static const bool value = sizeof (test<Traits> (0)) == sizeof (char);
+};
+
+template<typename Type, typename Traits, bool = has_is_deleted<Traits>::value>
+struct is_empty_helper
+{
+  static inline bool
+  call (Type &v)
+  {
+    return Traits::is_empty (v);
+  }
+};
+
+template<typename Type, typename Traits>
+struct is_empty_helper<Type *, Traits, false>
+{
+  static inline bool
+  call (Type *v)
+  {
+    return v == HTAB_EMPTY_ENTRY;
+  }
+};
+
+ template<typename Traits>
+ struct has_mark_deleted
+{
+  template<typename U, void (*)(U &)> struct helper {};
+  template<typename U> static char test (helper<U, U::mark_deleted> *);
+  template<typename U> static int test (...);
+  static const bool value = sizeof (test<Traits> (0)) == sizeof (char);
+};
+
+template<typename Type, typename Traits, bool = has_is_deleted<Traits>::value>
+struct mark_deleted_helper
+{
+  static inline void
+  call (Type &v)
+  {
+    Traits::mark_deleted (v);
+  }
+};
+
+template<typename Type, typename Traits>
+struct mark_deleted_helper<Type *, Traits, false>
+{
+  static inline void
+  call (Type *&v)
+  {
+    v = static_cast<Type *> (HTAB_DELETED_ENTRY);
+  }
+};
+
+ template<typename Traits>
+ struct has_mark_empty
+{
+  template<typename U, void (*)(U &)> struct helper {};
+  template<typename U> static char test (helper<U, U::mark_empty> *);
+  template<typename U> static int test (...);
+  static const bool value = sizeof (test<Traits> (0)) == sizeof (char);
+};
+
+template<typename Type, typename Traits, bool = has_is_deleted<Traits>::value>
+struct mark_empty_helper
+{
+  static inline void
+  call (Type &v)
+  {
+    Traits::mark_empty (v);
+  }
+};
+
+template<typename Type, typename Traits>
+struct mark_empty_helper<Type *, Traits, false>
+{
+  static inline void
+  call (Type *&v)
+  {
+    v = static_cast<Type *> (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,11 +476,21 @@ 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 <typename Descriptor,
-	 template<typename Type> class Allocator= xcallocator>
+	 template<typename Type> class Allocator= xcallocator,
+	 bool Storage = storage_tester<Descriptor>::value>
 class hash_table
 {
+};
+
+template <typename Descriptor,
+	 template<typename Type> class Allocator>
+class hash_table<Descriptor, Allocator, false>
+{
   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<typename Descriptor, template<typename Type> class Allocator>
-hash_table<Descriptor, Allocator>::hash_table (size_t size) :
+hash_table<Descriptor, Allocator, false>::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<Descriptor, Allocator>::hash_table (size_t size) :
 }
 
 template<typename Descriptor, template<typename Type> class Allocator>
-hash_table<Descriptor, Allocator>::~hash_table ()
+hash_table<Descriptor, Allocator, false>::~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<Descriptor, Allocator>::~hash_table ()
 
 template<typename Descriptor, template<typename Type> class Allocator>
 typename Descriptor::value_type **
-hash_table<Descriptor, Allocator>::find_empty_slot_for_expand (hashval_t hash)
+hash_table<Descriptor, Allocator, false>
+::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<Descriptor, Allocator>::find_empty_slot_for_expand (hashval_t hash)
 
 	  template<typename Descriptor, template<typename Type> class Allocator>
 void
-hash_table<Descriptor, Allocator>::expand ()
+hash_table<Descriptor, Allocator, false>::expand ()
 {
   value_type **oentries = m_entries;
   unsigned int oindex = m_size_prime_index;
@@ -606,7 +753,7 @@ hash_table<Descriptor, Allocator>::expand ()
 
 template<typename Descriptor, template<typename Type> class Allocator>
 void
-hash_table<Descriptor, Allocator>::empty ()
+hash_table<Descriptor, Allocator, false>::empty ()
 {
   size_t size = m_size;
   value_type **entries = m_entries;
@@ -639,7 +786,7 @@ hash_table<Descriptor, Allocator>::empty ()
 
 template<typename Descriptor, template<typename Type> class Allocator>
 void
-hash_table<Descriptor, Allocator>::clear_slot (value_type **slot)
+hash_table<Descriptor, Allocator, false>::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<Descriptor, Allocator>::clear_slot (value_type **slot)
 
 template<typename Descriptor, template<typename Type> class Allocator>
 typename Descriptor::value_type *
-hash_table<Descriptor, Allocator>
+hash_table<Descriptor, Allocator, false>
 ::find_with_hash (const compare_type *comparable, hashval_t hash)
 {
   m_searches++;
@@ -695,7 +842,7 @@ hash_table<Descriptor, Allocator>
 
 template<typename Descriptor, template<typename Type> class Allocator>
 typename Descriptor::value_type **
-hash_table<Descriptor, Allocator>
+hash_table<Descriptor, Allocator, false>
 ::find_slot_with_hash (const compare_type *comparable, hashval_t hash,
 		       enum insert_option insert)
 {
@@ -756,7 +903,7 @@ hash_table<Descriptor, Allocator>
 
 template<typename Descriptor, template<typename Type> class Allocator>
 void
-hash_table<Descriptor, Allocator>
+hash_table<Descriptor, Allocator, false>
 ::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<Descriptor, Allocator>
    each live entry.  If CALLBACK returns false, the iteration stops.
    ARGUMENT is passed as CALLBACK's second argument. */
 
-template<typename Descriptor,
-	  template<typename Type> class Allocator>
+template<typename Descriptor, template<typename Type> class Allocator>
 template<typename Argument,
 	  int (*Callback) (typename Descriptor::value_type **slot, Argument argument)>
 void
-hash_table<Descriptor, Allocator>::traverse_noresize (Argument argument)
+hash_table<Descriptor, Allocator, false>::traverse_noresize (Argument argument)
 {
   value_type **slot = m_entries;
   value_type **limit = slot + size ();
@@ -803,7 +949,7 @@ template <typename Argument,
 	  int (*Callback) (typename Descriptor::value_type **slot,
 			   Argument argument)>
 void
-hash_table<Descriptor, Allocator>::traverse (Argument argument)
+hash_table<Descriptor, Allocator, false>::traverse (Argument argument)
 {
   size_t size = m_size;
   if (elements () * 8 < size && size > 32)
@@ -816,7 +962,7 @@ hash_table<Descriptor, Allocator>::traverse (Argument argument)
 
 template<typename Descriptor, template<typename Type> class Allocator>
 void
-hash_table<Descriptor, Allocator>::iterator::slide ()
+hash_table<Descriptor, Allocator, false>::iterator::slide ()
 {
   for ( ; m_slot < m_limit; ++m_slot )
     {
@@ -831,8 +977,527 @@ hash_table<Descriptor, Allocator>::iterator::slide ()
 /* Bump the iterator.  */
 
 template<typename Descriptor, template<typename Type> class Allocator>
-inline typename hash_table<Descriptor, Allocator>::iterator &
-hash_table<Descriptor, Allocator>::iterator::operator ++ ()
+inline typename hash_table<Descriptor, Allocator, false>::iterator &
+hash_table<Descriptor, Allocator, false>::iterator::operator ++ ()
+{
+  ++m_slot;
+  slide ();
+  return *this;
+}
+
+/* A partial specialization used when values should be stored directly.  */
+
+template <typename Descriptor,
+	 template<typename Type> class Allocator>
+class hash_table<Descriptor, Allocator, true>
+{
+  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 <typename Argument,
+	    int (*Callback) (value_type *slot, Argument argument)>
+  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 <typename Argument,
+	    int (*Callback) (value_type *slot, Argument argument)>
+  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 <double> (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<value_type, Descriptor>::call (v);
+    }
+  static bool is_empty (value_type &v)
+    {
+      return is_empty_helper<value_type, Descriptor>::call (v);
+    }
+
+  static void mark_deleted (value_type &v)
+    {
+      return mark_deleted_helper<value_type, Descriptor>::call (v);
+    }
+
+  static void mark_empty (value_type &v)
+    {
+      return mark_empty_helper<value_type, Descriptor>::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<typename Descriptor, template<typename Type> class Allocator>
+hash_table<Descriptor, Allocator, true>::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 <value_type> ::data_alloc (size);
+  gcc_assert (m_entries != NULL);
+  m_size = size;
+  m_size_prime_index = size_prime_index;
+}
+
+template<typename Descriptor, template<typename Type> class Allocator>
+hash_table<Descriptor, Allocator, true>::~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 <value_type> ::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<typename Descriptor, template<typename Type> class Allocator>
+typename Descriptor::value_type *
+hash_table<Descriptor, Allocator, true>
+::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<typename Descriptor, template<typename Type> class Allocator>
+void
+hash_table<Descriptor, Allocator, true>::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 <value_type> ::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 <value_type> ::data_free (oentries);
+}
+
+template<typename Descriptor, template<typename Type> class Allocator>
+void
+hash_table<Descriptor, Allocator, true>::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 <value_type> ::data_free (m_entries);
+      m_entries = Allocator <value_type> ::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<typename Descriptor, template<typename Type> class Allocator>
+void
+hash_table<Descriptor, Allocator, true>::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<typename Descriptor, template<typename Type> class Allocator>
+typename Descriptor::value_type &
+hash_table<Descriptor, Allocator, true>
+::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<typename Descriptor, template<typename Type> class Allocator>
+typename Descriptor::value_type *
+hash_table<Descriptor, Allocator, true>
+::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<typename Descriptor, template<typename Type> class Allocator>
+void
+hash_table<Descriptor, Allocator, true>
+::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<typename Descriptor,
+	  template<typename Type> class Allocator>
+template<typename Argument,
+	  int (*Callback) (typename Descriptor::value_type *slot,
+			   Argument argument)>
+void
+hash_table<Descriptor, Allocator, true>::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 <typename Descriptor,
+	  template <typename Type> class Allocator>
+template <typename Argument,
+	  int (*Callback) (typename Descriptor::value_type *slot,
+			   Argument argument)>
+void
+hash_table<Descriptor, Allocator, true>::traverse (Argument argument)
+{
+  size_t size = m_size;
+  if (elements () * 8 < size && size > 32)
+    expand ();
+
+  traverse_noresize <Argument, Callback> (argument);
+}
+
+/* Slide down the iterator slots until an active entry is found.  */
+
+template<typename Descriptor, template<typename Type> class Allocator>
+void
+hash_table<Descriptor, Allocator, true>::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<typename Descriptor, template<typename Type> class Allocator>
+inline typename hash_table<Descriptor, Allocator, true>::iterator &
+hash_table<Descriptor, Allocator, true>::iterator::operator ++ ()
 {
   ++m_slot;
   slide ();
@@ -846,7 +1511,7 @@ hash_table<Descriptor, Allocator>::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 8c03550..2a4db1b 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 <tree_node>
+struct tree_upper_hasher : pointer_hash<tree_node>
 {
-  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 <value_type>::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 7b0115d..3ed403a 100644
--- a/gcc/tree-complex.c
+++ b/gcc/tree-complex.c
@@ -83,10 +83,9 @@ static vec<tree> 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 6b28008..ae56a84 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 <int_tree_map>
+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<tree> (1);
+    }
+  static void mark_deleted (value_type &v) { v.to = reinterpret_cast<tree> (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_hasher> int_tree_htab_type;
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index 1cdcc2f..96255f9 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 <var_info_d>
 {
-  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 3ef4aa6..0c486bb 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 6c581ba..61e75b6 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 4d0d6c2..4903f48 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -1023,32 +1023,36 @@ static vec<oecount> cvec;
 
 /* Oecount hashtable helpers.  */
 
-struct oecount_hasher : typed_noop_remove <void>
+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 e553e28..0ad22c7 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -548,14 +548,14 @@ vectorize_loops (void)
       for (hash_table<simd_array_to_simduid>::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;
-- 
2.0.0


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