From c17a3de62427a1d571cec8b46f67f0b30bd5f273 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 10 May 2019 15:14:08 -0400
Subject: [PATCH 32/66] FIXME: rework exploded_graph's hash_map

---
 gcc/analyzer/impl-4.cc | 117 ++++++++++++++++++++++++++-----------------------
 1 file changed, 61 insertions(+), 56 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 41b5cbb..55f7610 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -708,63 +708,15 @@ struct point_and_state
   {
     return m_point.hash () ^ m_state.hash ();
   }
+  bool operator== (const point_and_state &other) const
+  {
+    return m_point == other.m_point && m_state == other.m_state;
+  }
 
   program_point m_point;
   program_state m_state;
 };
 
-} // namespace impl_4
-
-using impl_4::point_and_state;
-using impl_4::pod_hash_traits;
-
-template <> struct default_hash_traits<point_and_state>
-: public pod_hash_traits<point_and_state>
-{
-};
-
-template <>
-inline hashval_t
-pod_hash_traits<point_and_state>::hash (value_type v)
-{
-  return v.hash ();
-}
-
-template <>
-inline bool
-pod_hash_traits<point_and_state>::equal (const value_type &existing,
-					 const value_type &candidate)
-{
-  return (existing.m_point == candidate.m_point
-	  && existing.m_state == candidate.m_state);
-}
-template <>
-inline void
-pod_hash_traits<point_and_state>::mark_deleted (value_type &v)
-{
-  v = point_and_state (program_point::deleted (), program_state (0));
-}
-template <>
-inline void
-pod_hash_traits<point_and_state>::mark_empty (value_type &v)
-{
-  v = point_and_state (program_point::empty (), program_state (0));
-}
-template <>
-inline bool
-pod_hash_traits<point_and_state>::is_deleted (value_type v)
-{
-  return (v.m_point.m_kind == PK_DELETED);
-}
-template <>
-inline bool
-pod_hash_traits<point_and_state>::is_empty (value_type v)
-{
-  return (v.m_point.m_kind == PK_EMPTY);
-}
-
-namespace impl_4 {
-
 /* An exploded_node is a unique, immutable <point, state> pair within the
    exploded_graph.
    Each exploded_node has a unique index within the graph
@@ -780,6 +732,8 @@ class exploded_node : public dnode
   {
   }
 
+  hashval_t hash () const { return m_ps.hash (); }
+
   void dump_dot (graphviz_out *gv) const FINAL OVERRIDE;
   void dump_dot_id (pretty_printer *pp) const;
 
@@ -819,6 +773,8 @@ class exploded_node : public dnode
 
   const program_state &get_state () const { return m_ps.m_state; }
 
+  const point_and_state *get_key () const { return &m_ps; }
+
 private:
   /* The <program_point, program_state> pair.  This is const, as it
      is immutable once the exploded_node has been created.  */
@@ -864,6 +820,49 @@ struct stats
   int m_path_vars_purged;
 };
 
+/* FIXME.  */
+
+struct eg_hashmap_traits
+{
+  typedef const point_and_state *key_type;
+  typedef exploded_node *value_type;
+  typedef exploded_node *compare_type;
+
+  static inline hashval_t hash (const key_type &v)
+  {
+    return v->hash ();
+  }
+  static inline bool equal_keys (const key_type &k1, const key_type &k2)
+  {
+    return *k1 == *k2;
+  }
+  template <typename T>
+  static inline void remove (T &)
+  {
+    /* empty; the nodes are handled elsewhere.  */
+  }
+  template <typename T>
+  static inline void mark_deleted (T &entry)
+  {
+    entry.m_key = reinterpret_cast<key_type> (1);
+  }
+  template <typename T>
+  static inline void mark_empty (T &entry)
+  {
+    entry.m_key = NULL;
+  }
+  template <typename T>
+  static inline bool is_deleted (const T &entry)
+  {
+    return entry.m_key == reinterpret_cast<key_type> (1);
+  }
+  template <typename T>
+  static inline bool is_empty (const T &entry)
+  {
+    return entry.m_key == NULL;
+  }
+};
+
 /* An exploded_graph is a directed graph of unique <point, state> pairs.
    It also has a worklist of nodes that are waiting for their successors
    to be added to the graph.  */
@@ -910,8 +909,14 @@ public:
 private:
   const supergraph &m_sg;
 
-  /* Map from point/state to exploded node.  */
-  typedef hash_map <point_and_state, exploded_node *> map_t;
+  /* Map from point/state to exploded node.
+     I couldn't get hash_map to properly clean up its keys, so
+     we store point_and_state pointers as keys, rather than
+     point_and_state, using the value from within
+     the exploded_node, with a custom hasher.
+   */
+  typedef hash_map <const point_and_state *, exploded_node *,
+		    eg_hashmap_traits> map_t;
   map_t m_point_and_state_to_node;
 
   auto_vec<exploded_node *> m_worklist;
@@ -3241,7 +3246,7 @@ exploded_graph::get_or_create_node (const program_point &point,
   stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
 
   point_and_state ps (point, pruned_state);
-  if (exploded_node **slot = m_point_and_state_to_node.get (ps))
+  if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
     {
       /* An exploded_node for PS already exists.  */
       log ("reused EN: %i", (*slot)->m_index);
@@ -3253,7 +3258,7 @@ exploded_graph::get_or_create_node (const program_point &point,
   /* An exploded_node for PS doesn't already exist; create one.  */
   exploded_node *node = new exploded_node (ps, m_ext_state, m_nodes.length ());
   add_node (node);
-  m_point_and_state_to_node.put (ps, node);
+  m_point_and_state_to_node.put (node->get_key (), node);
   m_global_stats.m_num_nodes[node->get_point ().m_kind]++;
   per_fn_stats->m_num_nodes[node->get_point ().m_kind]++;
 
-- 
1.8.5.3

