From 054a8a18a8f60d788eb7ee03ce23d6dae5c24b25 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 18 Aug 2020 13:57:20 -0400
Subject: [PATCH 42/47] FIXME: WIP on avoiding hstate.add_ptr on regions and
 svalues

---
 gcc/analyzer/constraint-manager.cc   |   2 +-
 gcc/analyzer/engine.cc               |   9 ++
 gcc/analyzer/program-state.cc        |   5 +-
 gcc/analyzer/region-model-manager.cc |  80 ++++++-----
 gcc/analyzer/region-model.cc         |  21 +++
 gcc/analyzer/region-model.h          | 201 ++++++++++++++-------------
 gcc/analyzer/region.cc               |  27 +---
 gcc/analyzer/store.cc                |  11 +-
 gcc/analyzer/store.h                 |  31 +++--
 gcc/analyzer/svalue.cc               |  44 +++++-
 10 files changed, 252 insertions(+), 179 deletions(-)

diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc
index 603b22811c1..f5ad5c8bf38 100644
--- a/gcc/analyzer/constraint-manager.cc
+++ b/gcc/analyzer/constraint-manager.cc
@@ -340,7 +340,7 @@ equiv_class::hash () const
   int i;
   const svalue *sval;
   FOR_EACH_VEC_ELT (m_vars, i, sval)
-    hstate.add_ptr (sval);
+    sval->add_to_hash (&hstate);
   return hstate.end ();
 }
 
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 71232d818b3..d5a1f28b685 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -145,6 +145,15 @@ impl_region_model_context::on_unknown_change (const svalue *sval,
     smap->on_unknown_change (sval, is_mutable, m_ext_state);
 }
 
+/* struct setjmp_record.  */
+
+void
+setjmp_record::add_to_hash (inchash::hash *hstate) const
+{
+  hstate->add_object (m_enode->m_index);
+  hstate->add_ptr (m_setjmp_call);
+}
+
 /* class setjmp_svalue : public svalue.  */
 
 /* Implementation of svalue::accept vfunc for setjmp_svalue.  */
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 5b00bd33020..7966e5d63d8 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -280,10 +280,11 @@ sm_state_map::hash () const
        ++iter)
     {
       inchash::hash hstate;
-      hstate.add_ptr ((*iter).first);
+      (*iter).first->add_to_hash (&hstate);
       entry_t e = (*iter).second;
       hstate.add_int (e.m_state->get_id ());
-      hstate.add_ptr (e.m_origin);
+      if (e.m_origin)
+	e.m_origin->add_to_hash (&hstate);
       result ^= hstate.end ();
     }
   result ^= m_global_state->get_id ();
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index 9c4e4c78e5a..bbbb428641c 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -66,15 +66,15 @@ namespace ana {
 /* region_model_manager's ctor.  */
 
 region_model_manager::region_model_manager ()
-: m_next_region_id (0),
-  m_root_region (alloc_region_id ()),
-  m_stack_region (alloc_region_id (), &m_root_region),
-  m_heap_region (alloc_region_id (), &m_root_region),
+: m_next_symbol_id (0),
+  m_root_region (alloc_symbol_id ()),
+  m_stack_region (alloc_symbol_id (), &m_root_region),
+  m_heap_region (alloc_symbol_id (), &m_root_region),
   m_unknown_NULL (NULL),
   m_max_complexity (0, 0),
-  m_code_region (alloc_region_id (), &m_root_region),
+  m_code_region (alloc_symbol_id (), &m_root_region),
   m_fndecls_map (), m_labels_map (),
-  m_globals_region (alloc_region_id (), &m_root_region),
+  m_globals_region (alloc_symbol_id (), &m_root_region),
   m_globals_map (),
   m_store_mgr (this)
 {
@@ -204,7 +204,8 @@ region_model_manager::get_or_create_constant_svalue (tree cst_expr)
   constant_svalue **slot = m_constants_map.get (cst_expr);
   if (slot)
     return *slot;
-  constant_svalue *cst_sval = new constant_svalue (cst_expr);
+  constant_svalue *cst_sval
+    = new constant_svalue (alloc_symbol_id (), cst_expr);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (cst_sval);
   m_constants_map.put (cst_expr, cst_sval);
   return cst_sval;
@@ -223,14 +224,14 @@ region_model_manager::get_or_create_unknown_svalue (tree type)
   if (type == NULL_TREE)
     {
       if (!m_unknown_NULL)
-	m_unknown_NULL = new unknown_svalue (type);
+	m_unknown_NULL = new unknown_svalue (alloc_symbol_id (), type);
       return m_unknown_NULL;
     }
 
   unknown_svalue **slot = m_unknowns_map.get (type);
   if (slot)
     return *slot;
-  unknown_svalue *sval = new unknown_svalue (type);
+  unknown_svalue *sval = new unknown_svalue (alloc_symbol_id (), type);
   m_unknowns_map.put (type, sval);
   return sval;
 }
@@ -251,7 +252,8 @@ region_model_manager::get_or_create_initial_value (const region *reg)
 
   if (initial_svalue **slot = m_initial_values_map.get (reg))
     return *slot;
-  initial_svalue *initial_sval = new initial_svalue (reg->get_type (), reg);
+  initial_svalue *initial_sval
+    = new initial_svalue (alloc_symbol_id (), reg->get_type (), reg);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (initial_sval);
   m_initial_values_map.put (reg, initial_sval);
   return initial_sval;
@@ -267,7 +269,8 @@ region_model_manager::get_or_create_setjmp_svalue (const setjmp_record &r,
   setjmp_svalue::key_t key (r, type);
   if (setjmp_svalue **slot = m_setjmp_values_map.get (key))
     return *slot;
-  setjmp_svalue *setjmp_sval = new setjmp_svalue (r, type);
+  setjmp_svalue *setjmp_sval
+    = new setjmp_svalue (alloc_symbol_id (), r, type);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (setjmp_sval);
   m_setjmp_values_map.put (key, setjmp_sval);
   return setjmp_sval;
@@ -283,7 +286,8 @@ region_model_manager::get_or_create_poisoned_svalue (enum poison_kind kind,
   poisoned_svalue::key_t key (kind, type);
   if (poisoned_svalue **slot = m_poisoned_values_map.get (key))
     return *slot;
-  poisoned_svalue *poisoned_sval = new poisoned_svalue (kind, type);
+  poisoned_svalue *poisoned_sval
+    = new poisoned_svalue (alloc_symbol_id (), kind, type);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (poisoned_sval);
   m_poisoned_values_map.put (key, poisoned_sval);
   return poisoned_sval;
@@ -304,7 +308,8 @@ region_model_manager::get_ptr_svalue (tree ptr_type, const region *pointee)
   region_svalue::key_t key (ptr_type, pointee);
   if (region_svalue **slot = m_pointer_values_map.get (key))
     return *slot;
-  region_svalue *sval = new region_svalue (ptr_type, pointee);
+  region_svalue *sval
+    = new region_svalue (alloc_symbol_id (), ptr_type, pointee);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (sval);
   m_pointer_values_map.put (key, sval);
   return sval;
@@ -386,7 +391,8 @@ region_model_manager::get_or_create_unaryop (tree type, enum tree_code op,
   unaryop_svalue::key_t key (type, op, arg);
   if (unaryop_svalue **slot = m_unaryop_values_map.get (key))
     return *slot;
-  unaryop_svalue *unaryop_sval = new unaryop_svalue (type, op, arg);
+  unaryop_svalue *unaryop_sval
+    = new unaryop_svalue (alloc_symbol_id (), type, op, arg);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (unaryop_sval);
   m_unaryop_values_map.put (key, unaryop_sval);
   return unaryop_sval;
@@ -562,7 +568,8 @@ region_model_manager::get_or_create_binop (tree type, enum tree_code op,
   binop_svalue::key_t key (type, op, arg0, arg1);
   if (binop_svalue **slot = m_binop_values_map.get (key))
     return *slot;
-  binop_svalue *binop_sval = new binop_svalue (type, op, arg0, arg1);
+  binop_svalue *binop_sval
+    = new binop_svalue (alloc_symbol_id (), type, op, arg0, arg1);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (binop_sval);
   m_binop_values_map.put (key, binop_sval);
   return binop_sval;
@@ -643,7 +650,7 @@ region_model_manager::get_or_create_sub_svalue (tree type,
   if (sub_svalue **slot = m_sub_values_map.get (key))
     return *slot;
   sub_svalue *sub_sval
-    = new sub_svalue (type, parent_svalue, subregion);
+    = new sub_svalue (alloc_symbol_id (), type, parent_svalue, subregion);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (sub_sval);
   m_sub_values_map.put (key, sub_sval);
   return sub_sval;
@@ -660,7 +667,8 @@ region_model_manager::get_or_create_unmergeable (const svalue *arg)
 
   if (unmergeable_svalue **slot = m_unmergeable_values_map.get (arg))
     return *slot;
-  unmergeable_svalue *unmergeable_sval = new unmergeable_svalue (arg);
+  unmergeable_svalue *unmergeable_sval
+    = new unmergeable_svalue (alloc_symbol_id (), arg);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (unmergeable_sval);
   m_unmergeable_values_map.put (arg, unmergeable_sval);
   return unmergeable_sval;
@@ -681,7 +689,8 @@ region_model_manager::get_or_create_widening_svalue (tree type,
   if (widening_svalue **slot = m_widening_values_map.get (key))
     return *slot;
   widening_svalue *widening_sval
-    = new widening_svalue (type, point, base_sval, iter_sval);
+    = new widening_svalue (alloc_symbol_id (), type, point, base_sval,
+			   iter_sval);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (widening_sval);
   m_widening_values_map.put (key, widening_sval);
   return widening_sval;
@@ -698,7 +707,7 @@ region_model_manager::get_or_create_compound_svalue (tree type,
   if (compound_svalue **slot = m_compound_values_map.get (tmp_key))
     return *slot;
   compound_svalue *compound_sval
-    = new compound_svalue (type, map);
+    = new compound_svalue (alloc_symbol_id (), type, map);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (compound_sval);
   /* Use make_key rather than reusing the key, so that we use a
      ptr to compound_sval's binding_map, rather than the MAP param.  */
@@ -718,7 +727,7 @@ region_model_manager::get_or_create_conjured_svalue (tree type,
   if (conjured_svalue **slot = m_conjured_values_map.get (key))
     return *slot;
   conjured_svalue *conjured_sval
-    = new conjured_svalue (type, stmt, id_reg);
+    = new conjured_svalue (alloc_symbol_id (), type, stmt, id_reg);
   RETURN_UNKNOWN_IF_TOO_COMPLEX (conjured_sval);
   m_conjured_values_map.put (key, conjured_sval);
   return conjured_sval;
@@ -765,7 +774,7 @@ region_model_manager::get_region_for_fndecl (tree fndecl)
   if (slot)
     return *slot;
   function_region *reg
-    = new function_region (alloc_region_id (), &m_code_region, fndecl);
+    = new function_region (alloc_symbol_id (), &m_code_region, fndecl);
   m_fndecls_map.put (fndecl, reg);
   return reg;
 }
@@ -786,7 +795,7 @@ region_model_manager::get_region_for_label (tree label)
 
   const function_region *func_reg = get_region_for_fndecl (fndecl);
   label_region *reg
-    = new label_region (alloc_region_id (), func_reg, label);
+    = new label_region (alloc_symbol_id (), func_reg, label);
   m_labels_map.put (label, reg);
   return reg;
 }
@@ -802,7 +811,7 @@ region_model_manager::get_region_for_global (tree expr)
   if (slot)
     return *slot;
   decl_region *reg
-    = new decl_region (alloc_region_id (), &m_globals_region, expr);
+    = new decl_region (alloc_symbol_id (), &m_globals_region, expr);
   m_globals_map.put (expr, reg);
   return reg;
 }
@@ -820,7 +829,7 @@ region_model_manager::get_field_region (const region *parent, tree field)
     return reg;
 
   field_region *field_reg
-    = new field_region (alloc_region_id (), parent, field);
+    = new field_region (alloc_symbol_id (), parent, field);
   m_field_regions.put (key, field_reg);
   return field_reg;
 }
@@ -838,7 +847,7 @@ region_model_manager::get_element_region (const region *parent,
     return reg;
 
   element_region *element_reg
-    = new element_region (alloc_region_id (), parent, element_type, index);
+    = new element_region (alloc_symbol_id (), parent, element_type, index);
   m_element_regions.put (key, element_reg);
   return element_reg;
 }
@@ -874,7 +883,7 @@ region_model_manager::get_offset_region (const region *parent,
     return reg;
 
   offset_region *offset_reg
-    = new offset_region (alloc_region_id (), parent, type, byte_offset);
+    = new offset_region (alloc_symbol_id (), parent, type, byte_offset);
   m_offset_regions.put (key, offset_reg);
   return offset_reg;
 }
@@ -895,7 +904,7 @@ region_model_manager::get_cast_region (const region *original_region,
     return reg;
 
   cast_region *cast_reg
-    = new cast_region (alloc_region_id (), original_region, type);
+    = new cast_region (alloc_symbol_id (), original_region, type);
   m_cast_regions.put (key, cast_reg);
   return cast_reg;
 }
@@ -914,7 +923,7 @@ region_model_manager::get_frame_region (const frame_region *calling_frame,
     return reg;
 
   frame_region *frame_reg
-    = new frame_region (alloc_region_id (), &m_stack_region, calling_frame,
+    = new frame_region (alloc_symbol_id (), &m_stack_region, calling_frame,
 			 fun, index);
   m_frame_regions.put (key, frame_reg);
   return frame_reg;
@@ -931,7 +940,7 @@ region_model_manager::get_symbolic_region (const svalue *sval)
     return reg;
 
   symbolic_region *symbolic_reg
-    = new symbolic_region (alloc_region_id (), &m_root_region, sval);
+    = new symbolic_region (alloc_symbol_id (), &m_root_region, sval);
   m_symbolic_regions.put (key, symbolic_reg);
   return symbolic_reg;
 }
@@ -948,7 +957,7 @@ region_model_manager::get_region_for_string (tree string_cst)
   if (slot)
     return *slot;
   string_region *reg
-    = new string_region (alloc_region_id (), &m_root_region, string_cst);
+    = new string_region (alloc_symbol_id (), &m_root_region, string_cst);
   m_string_map.put (string_cst, reg);
   return reg;
 }
@@ -968,7 +977,7 @@ get_region_for_unexpected_tree_code (region_model_context *ctxt,
 {
   tree type = TYPE_P (t) ? t : TREE_TYPE (t);
   region *new_reg
-    = new unknown_region (alloc_region_id (), &m_root_region, type);
+    = new unknown_region (alloc_symbol_id (), &m_root_region, type);
   if (ctxt)
     ctxt->on_unexpected_tree_code (t, loc);
   return new_reg;
@@ -983,7 +992,8 @@ get_or_create_exception_state (const svalue *exception_ptr_sval,
 			       const svalue *dest_ptr_sval)
 {
   // FIXME: for now just new, no consolidation, and leak
-  return new exception_state (exception_ptr_sval,
+  return new exception_state (alloc_symbol_id (),
+			      exception_ptr_sval,
 			      tinfo_ptr_sval,
 			      dest_ptr_sval);
 }
@@ -994,7 +1004,7 @@ const region *
 region_model_manager::create_region_for_heap_alloc ()
 {
   region *reg
-    = new heap_allocated_region (alloc_region_id (), &m_heap_region);
+    = new heap_allocated_region (alloc_symbol_id (), &m_heap_region);
   m_managed_dynamic_regions.safe_push (reg);
   return reg;
 }
@@ -1005,7 +1015,7 @@ const region *
 region_model_manager::create_region_for_alloca (const frame_region *frame)
 {
   gcc_assert (frame);
-  region *reg = new alloca_region (alloc_region_id (), frame);
+  region *reg = new alloca_region (alloc_symbol_id (), frame);
   m_managed_dynamic_regions.safe_push (reg);
   return reg;
 }
@@ -1082,6 +1092,7 @@ void
 region_model_manager::log_stats (logger *logger, bool show_objs) const
 {
   LOG_SCOPE (logger);
+  logger->log ("next symbol id: %i", m_next_symbol_id);
   logger->log ("svalue consolidation");
   log_uniq_map (logger, show_objs, "constant_svalue", m_constants_map);
   log_uniq_map (logger, show_objs, "unknown_svalue", m_unknowns_map);
@@ -1105,7 +1116,6 @@ region_model_manager::log_stats (logger *logger, bool show_objs) const
 	       m_max_complexity.m_max_depth);
 
   logger->log ("region consolidation");
-  logger->log ("  next region id: %i", m_next_region_id);
   log_uniq_map (logger, show_objs, "function_region", m_fndecls_map);
   log_uniq_map (logger, show_objs, "label_region", m_labels_map);
   log_uniq_map (logger, show_objs, "decl_region for globals", m_globals_map);
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index f6eeaef1671..fcb8a9b1120 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -111,6 +111,27 @@ print_quoted_type (pretty_printer *pp, tree t)
   pp_end_quote (pp, pp_show_color (pp));
 }
 
+/* class symbol.  */
+
+/* Compare SYM1 and SYM2 by id.  */
+
+int
+symbol::cmp_ids (const symbol *sym1, const symbol *sym2)
+{
+  return (long)sym1->get_id () - (long)sym2->get_id ();
+}
+
+  /* Comparator for regions, using their IDs to order them.  */
+
+int
+symbol::cmp_ptrs (const void *p1, const void *p2)
+{
+  const symbol * const *sym1 = (const symbol * const *)p1;
+  const symbol * const *sym2 = (const symbol * const *)p2;
+
+  return cmp_ids (*sym1, *sym2);
+}
+
 /* class region_model.  */
 
 /* Ctor for region_model: construct an "empty" model.  */
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index e99abaceca7..2c07be1056a 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -195,6 +195,34 @@ public:
   virtual void visit_region (const region *) {}
 };
 
+/* A base class for svalues and regions: has an id (unique within
+   the region_model_manager), for hashing purposes (to avoid relying
+   on pointer values in hashes), and for deterministic sorting.  */
+
+class symbol
+{
+public:
+  typedef unsigned symbol_id;
+
+  virtual ~symbol () {}
+
+  void add_to_hash (inchash::hash *hstate) const
+  {
+    hstate->add_object (m_id);
+  }
+
+  symbol_id get_id () const { return m_id; }
+
+  static int cmp_ids (const symbol *sym1, const symbol *sym2);
+  static int cmp_ptrs (const void *, const void *);
+
+protected:
+  symbol (symbol_id id) : m_id (id) {}
+
+private:
+  symbol_id m_id;
+};
+
 /* An enum for discriminating between the different concrete subclasses
    of svalue.  */
 
@@ -243,11 +271,9 @@ enum svalue_kind
 
 /* An abstract base class representing a value held by a region of memory.  */
 
-class svalue
+class svalue : public symbol
 {
 public:
-  virtual ~svalue () {}
-
   tree get_type () const { return m_type; }
 
   virtual enum svalue_kind get_kind () const = 0;
@@ -306,8 +332,8 @@ public:
 				  const region_model *model) const;
 
  protected:
-  svalue (complexity c, tree type)
-  : m_complexity (c), m_type (type)
+  svalue (symbol_id id, complexity c, tree type)
+  : symbol (id), m_complexity (c), m_type (type)
   {}
 
  private:
@@ -328,13 +354,7 @@ public:
     : m_type (type), m_reg (reg)
     {}
 
-    hashval_t hash () const
-    {
-      inchash::hash hstate;
-      hstate.add_ptr (m_type);
-      hstate.add_ptr (m_reg);
-      return hstate.end ();
-    }
+    hashval_t hash () const;
 
     bool operator== (const key_t &other) const
     {
@@ -350,8 +370,8 @@ public:
     const region *m_reg;
   };
 
-  region_svalue (tree type, const region *reg)
-  : svalue (complexity (reg), type),
+  region_svalue (symbol_id id, tree type, const region *reg)
+  : svalue (id, complexity (reg), type),
     m_reg (reg)
   {
     gcc_assert (m_reg != NULL);
@@ -397,8 +417,8 @@ namespace ana {
 class constant_svalue : public svalue
 {
 public:
-  constant_svalue (tree cst_expr)
-  : svalue (complexity (1, 1), TREE_TYPE (cst_expr)), m_cst_expr (cst_expr)
+  constant_svalue (symbol_id id, tree cst_expr)
+  : svalue (id, complexity (1, 1), TREE_TYPE (cst_expr)), m_cst_expr (cst_expr)
   {
     gcc_assert (cst_expr);
     gcc_assert (CONSTANT_CLASS_P (cst_expr));
@@ -442,8 +462,8 @@ namespace ana {
 class unknown_svalue : public svalue
 {
 public:
-  unknown_svalue (tree type)
-  : svalue (complexity (1, 1), type)
+  unknown_svalue (symbol_id id, tree type)
+  : svalue (id, complexity (1, 1), type)
   {}
 
   enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_UNKNOWN; }
@@ -482,7 +502,8 @@ public:
     {
       inchash::hash hstate;
       hstate.add_int (m_kind);
-      hstate.add_ptr (m_type);
+      if (m_type)
+	hstate.add_object (TYPE_HASH (m_type));
       return hstate.end ();
     }
 
@@ -500,8 +521,8 @@ public:
     tree m_type;
   };
 
-  poisoned_svalue (enum poison_kind kind, tree type)
-  : svalue (complexity (1, 1), type), m_kind (kind) {}
+  poisoned_svalue (symbol_id id, enum poison_kind kind, tree type)
+  : svalue (id, complexity (1, 1), type), m_kind (kind) {}
 
   enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_POISONED; }
   const poisoned_svalue *
@@ -551,11 +572,7 @@ struct setjmp_record
 	    && m_setjmp_call == other.m_setjmp_call);
   }
 
-  void add_to_hash (inchash::hash *hstate) const
-  {
-    hstate->add_ptr (m_enode);
-    hstate->add_ptr (m_setjmp_call);
-  }
+  void add_to_hash (inchash::hash *hstate) const;
 
   const exploded_node *m_enode;
   const gcall *m_setjmp_call;
@@ -579,7 +596,8 @@ public:
     {
       inchash::hash hstate;
       m_record.add_to_hash (&hstate);
-      hstate.add_ptr (m_type);
+      if (m_type)
+	hstate.add_object (TYPE_HASH (m_type));
       return hstate.end ();
     }
 
@@ -597,9 +615,8 @@ public:
     tree m_type;
   };
 
-  setjmp_svalue (const setjmp_record &setjmp_record,
-		  tree type)
-  : svalue (complexity (1, 1), type), m_setjmp_record (setjmp_record)
+  setjmp_svalue (symbol_id id, const setjmp_record &setjmp_record, tree type)
+  : svalue (id, complexity (1, 1), type), m_setjmp_record (setjmp_record)
   {}
 
   enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_SETJMP; }
@@ -646,8 +663,8 @@ namespace ana {
 class initial_svalue : public svalue
 {
 public:
-  initial_svalue (tree type, const region *reg)
-  : svalue (complexity (reg), type), m_reg (reg)
+  initial_svalue (symbol_id id, tree type, const region *reg)
+  : svalue (id, complexity (reg), type), m_reg (reg)
   {
     gcc_assert (m_reg != NULL);
   }
@@ -695,9 +712,10 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_type);
+      if (m_type)
+	hstate.add_object (TYPE_HASH (m_type));
       hstate.add_int (m_op);
-      hstate.add_ptr (m_arg);
+      m_arg->add_to_hash (&hstate);
       return hstate.end ();
     }
 
@@ -718,8 +736,8 @@ public:
     const svalue *m_arg;
   };
 
-  unaryop_svalue (tree type, enum tree_code op, const svalue *arg)
-  : svalue (complexity (arg), type), m_op (op), m_arg (arg)
+  unaryop_svalue (symbol_id id, tree type, enum tree_code op, const svalue *arg)
+  : svalue (id, complexity (arg), type), m_op (op), m_arg (arg)
   {
   }
 
@@ -775,10 +793,11 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_type);
+      if (m_type)
+	hstate.add_object (TYPE_HASH (m_type));
       hstate.add_int (m_op);
-      hstate.add_ptr (m_arg0);
-      hstate.add_ptr (m_arg1);
+      m_arg0->add_to_hash (&hstate);
+      m_arg1->add_to_hash (&hstate);
       return hstate.end ();
     }
 
@@ -801,11 +820,12 @@ public:
     const svalue *m_arg1;
   };
 
-  binop_svalue (tree type, enum tree_code op,
-		 const svalue *arg0, const svalue *arg1)
-  : svalue (complexity::from_pair (arg0->get_complexity (),
-				    arg1->get_complexity ()),
-	     type),
+  binop_svalue (symbol_id id, tree type, enum tree_code op,
+		const svalue *arg0, const svalue *arg1)
+  : svalue (id,
+	    complexity::from_pair (arg0->get_complexity (),
+				   arg1->get_complexity ()),
+	    type),
     m_op (op), m_arg0 (arg0), m_arg1 (arg1)
   {
   }
@@ -863,14 +883,7 @@ public:
     : m_type (type), m_parent_svalue (parent_svalue), m_subregion (subregion)
     {}
 
-    hashval_t hash () const
-    {
-      inchash::hash hstate;
-      hstate.add_ptr (m_type);
-      hstate.add_ptr (m_parent_svalue);
-      hstate.add_ptr (m_subregion);
-      return hstate.end ();
-    }
+    hashval_t hash () const;
 
     bool operator== (const key_t &other) const
     {
@@ -888,8 +901,8 @@ public:
     const svalue *m_parent_svalue;
     const region *m_subregion;
   };
-  sub_svalue (tree type, const svalue *parent_svalue,
-	       const region *subregion);
+  sub_svalue (symbol_id id, tree type, const svalue *parent_svalue,
+	      const region *subregion);
 
   enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_SUB; }
   const sub_svalue *dyn_cast_sub_svalue () const FINAL OVERRIDE
@@ -942,8 +955,8 @@ namespace ana {
 class unmergeable_svalue : public svalue
 {
 public:
-  unmergeable_svalue (const svalue *arg)
-  : svalue (complexity (arg), arg->get_type ()), m_arg (arg)
+  unmergeable_svalue (symbol_id id, const svalue *arg)
+  : svalue (id, complexity (arg), arg->get_type ()), m_arg (arg)
   {
   }
 
@@ -977,13 +990,13 @@ namespace ana {
 /* Concrete subclass of svalue for use in selftests, where
    we want a specific but unknown svalue.
    Unlike other svalue subclasses these aren't managed by
-   region_model_manager.  */
+   region_model_manager; they have a placeholder id.  */
 
 class placeholder_svalue : public svalue
 {
 public:
   placeholder_svalue (tree type, const char *name)
-  : svalue (complexity (1, 1), type), m_name (name)
+  : svalue (0, complexity (1, 1), type), m_name (name)
   {
   }
 
@@ -1033,8 +1046,8 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_base_sval);
-      hstate.add_ptr (m_iter_sval);
+      m_base_sval->add_to_hash (&hstate);
+      m_iter_sval->add_to_hash (&hstate);
       return hstate.end ();
     }
 
@@ -1064,9 +1077,10 @@ public:
      DIR_UNKNOWN
     };
 
-  widening_svalue (tree type, const program_point &point,
+  widening_svalue (symbol_id id, tree type, const program_point &point,
 		   const svalue *base_sval, const svalue *iter_sval)
-  : svalue (complexity::from_pair (base_sval->get_complexity (),
+  : svalue (id,
+	    complexity::from_pair (base_sval->get_complexity (),
 				   iter_sval->get_complexity ()),
 	    type),
     m_point (point.get_function_point ()),
@@ -1146,7 +1160,8 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_type);
+      if (m_type)
+	hstate.add_object (TYPE_HASH (m_type));
       //hstate.add_ptr (m_map_ptr); // TODO
       return hstate.end ();
     }
@@ -1166,7 +1181,7 @@ public:
     const binding_map *m_map_ptr;
   };
 
-  compound_svalue (tree type, const binding_map &map);
+  compound_svalue (symbol_id id, tree type, const binding_map &map);
 
   enum svalue_kind get_kind () const FINAL OVERRIDE { return SK_COMPOUND; }
   const compound_svalue *dyn_cast_compound_svalue () const FINAL OVERRIDE
@@ -1238,14 +1253,7 @@ public:
     : m_type (type), m_stmt (stmt), m_id_reg (id_reg)
     {}
 
-    hashval_t hash () const
-    {
-      inchash::hash hstate;
-      hstate.add_ptr (m_type);
-      hstate.add_ptr (m_stmt);
-      hstate.add_ptr (m_id_reg);
-      return hstate.end ();
-    }
+    hashval_t hash () const;
 
     bool operator== (const key_t &other) const
     {
@@ -1269,8 +1277,9 @@ public:
     const region *m_id_reg;
   };
 
-  conjured_svalue (tree type, const gimple *stmt, const region *id_reg)
-  : svalue (complexity (id_reg), type),
+  conjured_svalue (symbol_id id, tree type, const gimple *stmt,
+		   const region *id_reg)
+  : svalue (id, complexity (id_reg), type),
     m_stmt (stmt), m_id_reg (id_reg)
   {
     gcc_assert (m_stmt != NULL);
@@ -1367,14 +1376,11 @@ enum region_kind
    within the frames and the "globals" region.  Regions for structs
    can have subregions for fields.  */
 
-class region
+class region : public symbol
 {
 public:
   virtual ~region ();
 
-  unsigned get_id () const { return m_id; }
-  static int cmp_ids (const region *reg1, const region *reg2);
-
   virtual enum region_kind get_kind () const = 0;
   virtual const frame_region *
   dyn_cast_frame_region () const { return NULL; }
@@ -1423,8 +1429,6 @@ public:
 
   bool non_null_p () const;
 
-  static int cmp_ptrs (const void *, const void *);
-
   region_offset get_offset () const;
   bool get_byte_size (byte_size_t *out) const;
   bool get_bit_size (bit_size_t *out) const;
@@ -1449,7 +1453,6 @@ public:
   region_offset calc_offset () const;
 
   complexity m_complexity;
-  unsigned m_id; // purely for deterministic sorting at this stage, for dumps
   const region *m_parent;
   tree m_type;
 
@@ -1507,7 +1510,8 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_calling_frame);
+      if (m_calling_frame)
+	m_calling_frame->add_to_hash (&hstate);
       hstate.add_ptr (m_fun);
       return hstate.end ();
     }
@@ -1813,8 +1817,8 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_parent);
-      hstate.add_ptr (m_sval_ptr);
+      m_parent->add_to_hash (&hstate);
+      m_sval_ptr->add_to_hash (&hstate);
       return hstate.end ();
     }
 
@@ -1930,7 +1934,7 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_parent);
+      m_parent->add_to_hash (&hstate);
       hstate.add_ptr (m_field);
       return hstate.end ();
     }
@@ -2001,9 +2005,9 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_parent);
-      hstate.add_ptr (m_element_type);
-      hstate.add_ptr (m_index);
+      m_parent->add_to_hash (&hstate);
+      hstate.add_object (TYPE_HASH (m_element_type));
+      m_index->add_to_hash (&hstate);
       return hstate.end ();
     }
 
@@ -2083,9 +2087,9 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_parent);
-      hstate.add_ptr (m_element_type);
-      hstate.add_ptr (m_byte_offset);
+      m_parent->add_to_hash (&hstate);
+      hstate.add_object (TYPE_HASH (m_element_type));
+      m_byte_offset->add_to_hash (&hstate);
       return hstate.end ();
     }
 
@@ -2164,8 +2168,8 @@ public:
     hashval_t hash () const
     {
       inchash::hash hstate;
-      hstate.add_ptr (m_original_region);
-      hstate.add_ptr (m_type);
+      m_original_region->add_to_hash (&hstate);
+      hstate.add_object (TYPE_HASH (m_type));
       return hstate.end ();
     }
 
@@ -2308,10 +2312,11 @@ public:
 class exception_state : public svalue
 {
 public:
-  exception_state (const svalue *exception_ptr_sval,
+  exception_state (symbol_id id,
+		   const svalue *exception_ptr_sval,
 		   const svalue *tinfo_ptr_sval,
 		   const svalue *dest_ptr_sval)
-  : svalue (complexity (0, 0), NULL_TREE),
+  : svalue (id, complexity (0, 0), NULL_TREE),
     m_exception_ptr_sval (exception_ptr_sval),
     m_tinfo_ptr_sval (tinfo_ptr_sval),
     m_dest_ptr_sval (dest_ptr_sval)
@@ -2352,6 +2357,8 @@ public:
   region_model_manager ();
   ~region_model_manager ();
 
+  symbol::symbol_id alloc_symbol_id () { return m_next_symbol_id++; }
+
   /* svalue consolidation.  */
   const svalue *get_or_create_constant_svalue (tree cst_expr);
   const svalue *get_or_create_unknown_svalue (tree type);
@@ -2413,8 +2420,6 @@ public:
 				       tree t,
 				       const dump_location_t &loc);
 
-  unsigned alloc_region_id () { return m_next_region_id++; }
-
   const exception_state *
   get_or_create_exception_state (const svalue *exception_ptr_sval,
 				 const svalue *tinfo_ptr_sval,
@@ -2442,7 +2447,7 @@ private:
 				       const svalue *parent_svalue,
 				       const region *subregion);
 
-  unsigned m_next_region_id;
+  symbol::symbol_id m_next_symbol_id;
   root_region m_root_region;
   stack_region m_stack_region;
   heap_region m_heap_region;
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 0820893a9b4..7f4c16cf2f5 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -65,21 +65,13 @@ namespace ana {
 
 /* class region and its various subclasses.  */
 
-/* class region.  */
+/* class region : public symbol.  */
 
 region::~region ()
 {
   delete m_cached_offset;
 }
 
-/* Compare REG1 and REG2 by id.  */
-
-int
-region::cmp_ids (const region *reg1, const region *reg2)
-{
-  return (long)reg1->get_id () - (long)reg2->get_id ();
-}
-
 /* Determine the base region for this region: when considering bindings
    for this region, the base region is the ancestor which identifies
    which cluster they should be partitioned into.
@@ -510,24 +502,13 @@ region::symbolic_for_unknown_ptr_p () const
 
 /* region's ctor.  */
 
-region::region (complexity c, unsigned id, const region *parent, tree type)
-: m_complexity (c), m_id (id), m_parent (parent), m_type (type),
+region::region (complexity c, symbol_id id, const region *parent, tree type)
+: symbol (id), m_complexity (c), m_parent (parent), m_type (type),
   m_cached_offset (NULL)
 {
   gcc_assert (type == NULL_TREE || TYPE_P (type));
 }
 
-/* Comparator for regions, using their IDs to order them.  */
-
-int
-region::cmp_ptrs (const void *p1, const void *p2)
-{
-  const region * const *reg1 = (const region * const *)p1;
-  const region * const *reg2 = (const region * const *)p2;
-
-  return cmp_ids (*reg1, *reg2);
-}
-
 /* Determine if a pointer to this region must be non-NULL.
 
    Generally, pointers to regions must be non-NULL, but pointers
@@ -707,7 +688,7 @@ frame_region::get_region_for_local (region_model_manager *mgr,
   if (decl_region **slot = mutable_locals.get (expr))
     return *slot;
   decl_region *reg
-    = new decl_region (mgr->alloc_region_id (), this, expr);
+    = new decl_region (mgr->alloc_symbol_id (), this, expr);
   mutable_locals.put (expr, reg);
   return reg;
 }
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 11585123561..3b1bda69833 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -218,6 +218,13 @@ symbolic_binding::dump_to_pp (pretty_printer *pp, bool simple) const
   m_region->dump_to_pp (pp, simple);
 }
 
+void
+symbolic_binding::add_to_hash (inchash::hash *hstate) const
+{
+  binding_key::add_to_hash (hstate);
+  m_region->add_to_hash (hstate);
+}
+
 /* The store is oblivious to the types of the svalues bound within
    it: any type can get bound at any location.
    Simplify any casts before binding.
@@ -307,8 +314,8 @@ binding_map::hash () const
       /* Use a new hasher for each key to avoid depending on the ordering
 	 of keys when accumulating the result.  */
       inchash::hash hstate;
-      hstate.add_ptr ((*iter).first);
-      hstate.add_ptr ((*iter).second);
+      (*iter).first->add_to_hash (&hstate);
+      (*iter).second->add_to_hash (&hstate);
       result ^= hstate.end ();
     }
   return result;
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 0f4e7ab2a56..34301e9b677 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -169,6 +169,17 @@ public:
 
   enum binding_kind get_kind () const { return m_kind; }
 
+  hashval_t hash () const
+  {
+    inchash::hash hstate;
+    add_to_hash (&hstate);
+    return hstate.end ();
+  }
+  virtual void add_to_hash (inchash::hash *hstate) const
+  {
+    hstate->add_int (m_kind);
+  }
+
   void mark_deleted () { m_kind = BK_deleted; }
   void mark_empty () { m_kind = BK_empty; }
   bool is_deleted () const { return m_kind == BK_deleted; }
@@ -177,10 +188,6 @@ public:
 protected:
   binding_key (enum binding_kind kind) : m_kind (kind) {}
 
-  hashval_t impl_hash () const
-  {
-    return m_kind;
-  }
   bool impl_eq (const binding_key &other) const
   {
     return m_kind == other.m_kind;
@@ -207,13 +214,13 @@ public:
   {}
   bool concrete_p () const FINAL OVERRIDE { return true; }
 
-  hashval_t hash () const
+  void add_to_hash (inchash::hash *hstate) const FINAL OVERRIDE
   {
-    inchash::hash hstate;
-    hstate.add_wide_int (m_start_bit_offset);
-    hstate.add_wide_int (m_size_in_bits);
-    return hstate.end () ^ binding_key::impl_hash ();
+    binding_key::add_to_hash (hstate);
+    hstate->add_wide_int (m_start_bit_offset);
+    hstate->add_wide_int (m_size_in_bits);
   }
+
   bool operator== (const concrete_binding &other) const
   {
     if (!binding_key::impl_eq (other))
@@ -267,10 +274,8 @@ public:
   {}
   bool concrete_p () const FINAL OVERRIDE { return false; }
 
-  hashval_t hash () const
-  {
-    return (binding_key::impl_hash () ^ (long)m_region);
-  }
+  void add_to_hash (inchash::hash *hstate) const FINAL OVERRIDE;
+
   bool operator== (const symbolic_binding &other) const
   {
     if (!binding_key::impl_eq (other))
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index 863cdbea153..fd12a99ac9c 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -90,7 +90,7 @@ complexity::from_pair (const complexity &c1, const complexity &c2)
 
 /* class svalue and its various subclasses.  */
 
-/* class svalue.  */
+/* class svalue : public symbol.  */
 
 /* Dump a representation of this svalue to stderr.  */
 
@@ -300,6 +300,16 @@ svalue::implicitly_live_p (const svalue_set &, const region_model *) const
 
 /* class region_svalue : public svalue.  */
 
+hashval_t
+region_svalue::key_t::hash () const
+{
+  inchash::hash hstate;
+  if (m_type)
+    hstate.add_object (TYPE_HASH (m_type));
+  m_reg->add_to_hash (&hstate);
+  return hstate.end ();
+}
+
 /* Implementation of svalue::dump_to_pp vfunc for region_svalue.  */
 
 void
@@ -675,11 +685,23 @@ binop_svalue::implicitly_live_p (const svalue_set &live_svalues,
 
 /* class sub_svalue : public svalue.  */
 
+hashval_t
+sub_svalue::key_t::hash () const
+{
+  inchash::hash hstate;
+  if (m_type)
+    hstate.add_object (TYPE_HASH (m_type));
+  m_parent_svalue->add_to_hash (&hstate);
+  m_subregion->add_to_hash (&hstate);
+  return hstate.end ();
+}
+
 /* sub_svalue'c ctor.  */
 
-sub_svalue::sub_svalue (tree type, const svalue *parent_svalue,
+sub_svalue::sub_svalue (symbol_id id, tree type, const svalue *parent_svalue,
 			const region *subregion)
-: svalue (complexity::from_pair (parent_svalue->get_complexity (),
+: svalue (id,
+	  complexity::from_pair (parent_svalue->get_complexity (),
 				 subregion->get_complexity ()),
 	  type),
   m_parent_svalue (parent_svalue), m_subregion (subregion)
@@ -948,8 +970,9 @@ unmergeable_svalue::implicitly_live_p (const svalue_set &live_svalues,
 
 /* class compound_svalue : public svalue.  */
 
-compound_svalue::compound_svalue (tree type, const binding_map &map)
-: svalue (calc_complexity (map), type), m_map (map)
+compound_svalue::compound_svalue (symbol_id id, tree type,
+				  const binding_map &map)
+: svalue (id, calc_complexity (map), type), m_map (map)
 {
   /* All keys within the underlying binding_map are required to be concrete,
      not symbolic.  */
@@ -1018,6 +1041,17 @@ compound_svalue::calc_complexity (const binding_map &map)
 
 /* class conjured_svalue : public svalue.  */
 
+hashval_t
+conjured_svalue::key_t::hash () const
+{
+  inchash::hash hstate;
+  if (m_type)
+    hstate.add_object (TYPE_HASH (m_type));
+  hstate.add_ptr (m_stmt);
+  m_id_reg->add_to_hash (&hstate);
+  return hstate.end ();
+}
+
 /* Implementation of svalue::dump_to_pp vfunc for conjured_svalue.  */
 
 void
-- 
2.26.2

