From f52492fd160bef626cd0ea8b4f1d62a3030a1cb9 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 13 Jan 2020 11:17:31 -0500
Subject: [PATCH] FIXME: experiments with fixing hash_map::empty

---
 gcc/hash-map-traits.h | 16 ++++++++++++++++
 gcc/hash-map.h        |  4 ++++
 gcc/hash-table.h      | 10 ++++++----
 gcc/hash-traits.h     | 23 +++++++++++++++++++++++
 4 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/gcc/hash-map-traits.h b/gcc/hash-map-traits.h
index 4764380b364..051e1d4b899 100644
--- a/gcc/hash-map-traits.h
+++ b/gcc/hash-map-traits.h
@@ -39,6 +39,7 @@ struct simple_hashmap_traits
   template <typename T> static inline bool is_empty (const T &);
   template <typename T> static inline bool is_deleted (const T &);
   template <typename T> static inline void mark_empty (T &);
+  template <typename T> static inline void bulk_mark_empty (T *, size_t);
   template <typename T> static inline void mark_deleted (T &);
 };
 
@@ -90,6 +91,21 @@ simple_hashmap_traits <H, Value>::mark_empty (T &entry)
   H::mark_empty (entry.m_key);
 }
 
+template <typename H, typename Value>
+template <typename T>
+inline void
+simple_hashmap_traits <H, Value>::bulk_mark_empty (T *entry, size_t count)
+{
+#if 0  
+  /* This assumes that the value type is a POD.  */
+  if (H::empty_is_all_zeroes_p () && std::is_pod<T> ())
+    memset (entry, 0, sizeof (T) * count);
+  else
+#endif
+    for (size_t i = 0; i < count; i++)
+      mark_empty (entry[i]);
+}
+
 template <typename H, typename Value>
 template <typename T>
 inline void
diff --git a/gcc/hash-map.h b/gcc/hash-map.h
index 7cb466767ea..472e420edba 100644
--- a/gcc/hash-map.h
+++ b/gcc/hash-map.h
@@ -68,6 +68,10 @@ class GTY((user)) hash_map
 
     static void mark_empty (hash_entry &e) { Traits::mark_empty (e); }
     static bool is_empty (const hash_entry &e) { return Traits::is_empty (e); }
+    static void bulk_mark_empty (hash_entry *e, size_t count)
+    {
+      Traits::bulk_mark_empty (e, count);
+    }
 
     static void ggc_mx (hash_entry &e)
       {
diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 539f8ba7adb..75da7f4201c 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -551,6 +551,11 @@ private:
     Descriptor::mark_empty (v);
   }
 
+  static void bulk_mark_empty (value_type *v, size_t count)
+  {
+    Descriptor::bulk_mark_empty (v, count);
+  }
+
   /* Table itself.  */
   typename Descriptor::value_type *m_entries;
 
@@ -868,10 +873,7 @@ hash_table<Descriptor, Lazy, Allocator>::empty_slow ()
       m_size_prime_index = nindex;
     }
   else
-    {
-      for (size_t i = 0; i < size; i++)
-	mark_empty (entries[i]);
-    }
+    bulk_mark_empty (entries, size);
 
   m_n_deleted = 0;
   m_n_elements = 0;
diff --git a/gcc/hash-traits.h b/gcc/hash-traits.h
index d259a41a418..fdcac613c4c 100644
--- a/gcc/hash-traits.h
+++ b/gcc/hash-traits.h
@@ -91,6 +91,7 @@ struct int_hash : typed_noop_remove <Type>
   static inline void mark_empty (Type &);
   static inline bool is_deleted (Type);
   static inline bool is_empty (Type);
+  static inline bool empty_is_all_zeroes_p ();
 };
 
 template <typename Type, Type Empty, Type Deleted>
@@ -136,6 +137,12 @@ int_hash <Type, Empty, Deleted>::is_empty (Type x)
   return x == Empty;
 }
 
+template <typename Type, Type Empty, Type Deleted>
+inline bool empty_is_all_zeroes_p ()
+{
+  return Empty == 0;
+}
+
 /* Pointer hasher based on pointer equality.  Other types of pointer hash
    can inherit this and override the hash and equal functions with some
    other form of equality (such as string equality).  */
@@ -151,8 +158,10 @@ struct pointer_hash
 			    const compare_type &candidate);
   static inline void mark_deleted (Type *&);
   static inline void mark_empty (Type *&);
+  static inline void bulk_mark_empty (Type **, size_t);
   static inline bool is_deleted (Type *);
   static inline bool is_empty (Type *);
+  static inline bool empty_is_all_zeroes_p ();
 };
 
 template <typename Type>
@@ -186,6 +195,13 @@ pointer_hash <Type>::mark_empty (Type *&e)
   e = NULL;
 }
 
+template <typename Type>
+inline void
+pointer_hash <Type>::bulk_mark_empty (Type **e, size_t count)
+{
+  memset (e, 0, sizeof (Type *) * count);
+}
+
 template <typename Type>
 inline bool
 pointer_hash <Type>::is_deleted (Type *e)
@@ -200,6 +216,13 @@ pointer_hash <Type>::is_empty (Type *e)
   return e == NULL;
 }
 
+template <typename Type>
+inline bool
+pointer_hash <Type>::empty_is_all_zeroes_p ()
+{
+  return true;
+}
+
 /* Hasher for "const char *" strings, using string rather than pointer
    equality.  */
 
-- 
2.21.0

