From 7c9fb048f4dd3df0d8417eb2b43bceecb69d93c1 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 16 Apr 2020 16:50:20 -0400
Subject: [PATCH 50/96] FIXME: move store code a new store2.cc/h

---
 gcc/Makefile.in               |   1 +
 gcc/analyzer/analyzer.h       |  21 +++
 gcc/analyzer/region-model2.cc | 245 -------------------------
 gcc/analyzer/region-model2.h  | 217 +---------------------
 gcc/analyzer/store2.cc        | 334 ++++++++++++++++++++++++++++++++++
 gcc/analyzer/store2.h         | 219 ++++++++++++++++++++++
 6 files changed, 576 insertions(+), 461 deletions(-)
 create mode 100644 gcc/analyzer/store2.cc
 create mode 100644 gcc/analyzer/store2.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7357c0c886b..c0ea09954bc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1243,6 +1243,7 @@ ANALYZER_OBJS = \
 	analyzer/sm-signal.o \
 	analyzer/sm-taint.o \
 	analyzer/state-purge.o \
+	analyzer/store2.o \
 	analyzer/supergraph.o \
 	analyzer/uniq-manager.o
 
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index ed81438a411..a3daddc813f 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -139,6 +139,27 @@ enum poison_kind
 
 extern const char *poison_kind_to_str (enum poison_kind);
 
+/* The location of a region expressesd as an offset relative to a
+   base region.  */
+
+class region_offset
+{
+public:
+  typedef offset_int bit_offset_t;
+
+  region_offset (const region2 *base_region, bit_offset_t offset)
+  : m_base_region (base_region), m_offset (offset)
+  {}
+
+  const region2 *get_base_region () const { return m_base_region; }
+  bit_offset_t get_bit_offset () const { return m_offset; }
+
+private:
+  const region2 *m_base_region;
+  bit_offset_t m_offset;
+  // FIXME: also need a "symbolic" value
+};
+
 } // namespace ana
 
 extern bool is_special_named_call_p (const gcall *call, const char *funcname,
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index d541a57cc18..e937f78ac60 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -2800,137 +2800,6 @@ element_region2::add_to_hash (inchash::hash &hstate) const
   hstate.add_ptr (m_index);
 }
 
-/* class binding_key2.  */
-
-const binding_key2 *
-binding_key2::make (store2_manager *mgr, region2 *r, enum kind kind)
-{
-  region_offset offset = r->get_offset ();
-  // FIXME: what if symbolic vs concrete?
-  return mgr->get_concrete_binding (offset.get_base_region (), kind,
-				    offset.get_bit_offset ());
-}
-
-/* FIXME.  */
-
-int
-binding_key2::cmp_ptrs (const void *p1, const void *p2)
-{
-  const binding_key2 * const *pk1 = (const binding_key2 * const *)p1;
-  const binding_key2 * const *pk2 = (const binding_key2 * const *)p2;
-  return cmp (*pk1, *pk2);
-}
-
-/* FIXME.  */
-
-int
-binding_key2::cmp (const binding_key2 *k1, const binding_key2 *k2)
-{
-  if (int reg_cmp = region2::cmp_ids (k1->m_region, k2->m_region))
-    return reg_cmp;
-
-  enum kind kind1 = k1->get_kind ();
-  enum kind kind2 = k2->get_kind ();
-  if (kind1 != kind2)
-    return (int)kind1 - (int)kind2;
-
-  int concrete1 = k1->concrete_p ();
-  int concrete2 = k2->concrete_p ();
-  if (int concrete_cmp = concrete1 - concrete2)
-    return concrete_cmp;
-  if (concrete1)
-    {
-      const concrete_binding2 *b1 = (const concrete_binding2 *)k1;
-      const concrete_binding2 *b2 = (const concrete_binding2 *)k2;
-      return wi::cmp (b1->get_bit_offset (), b2->get_bit_offset (), SIGNED);
-    }
-  else
-    {
-      // TODO
-      gcc_unreachable ();
-    }
-}
-
-/* class binding_cluster2.  */
-
-void
-binding_cluster2::dump_to_pp (pretty_printer *pp, bool simple) const
-{
-  auto_vec <const binding_key2 *> binding_key2s;
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end (); ++iter)
-    {
-      const binding_key2 *key = (*iter).first;
-      binding_key2s.safe_push (key);
-    }
-
-  binding_key2s.qsort (binding_key2::cmp_ptrs);
-
-  const binding_key2 *key;
-  unsigned i;
-  FOR_EACH_VEC_ELT (binding_key2s, i, key)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      svalue2 *value = *const_cast <map_t &> (m_map).get (key);
-      pp_string (pp, "binding key: {");
-      key->dump_to_pp (pp, simple);
-      pp_string (pp, "}, value: {");
-      value->dump_to_pp (pp, simple);
-      pp_string (pp, "}");
-    }
-}
-
-void
-binding_cluster2::bind (store2_manager *mgr,
-			region2 *reg, svalue2 *val)
-{
-  const binding_key2 *binding
-    = binding_key2::make (mgr, reg, binding_key2::BK_direct);
-  m_map.put (binding, val);
-}
-
-svalue2 *
-binding_cluster2::get_binding (store2_manager *mgr,
-			       region2 *reg,
-			       binding_key2::kind kind) const
-{
-  const binding_key2 *binding = binding_key2::make (mgr, reg, kind);
-  svalue2 **slot = const_cast<map_t &> (m_map).get (binding);
-  if (slot)
-    return *slot;
-  return NULL;
-}
-
-/* Populate OUT with all bindings within this cluster that overlap REG.  */
-
-void
-binding_cluster2::get_overlapping_bindings (region2 */*reg*/,
-					    auto_vec<const binding_key2 *> */*out*/)
-{
-  /* Get the size of REG.  */
-  // TODO
-
-  for (map_t::iterator iter = m_map.begin ();
-       iter != m_map.end (); ++iter)
-    {
-      //const binding_key2 *key = (*iter).first;
-      // TODO
-    }
-}
-
-/* FIXME.  */
-
-void
-binding_cluster2::remove_overlapping_bindings (store2_manager */*mgr*/,
-					       region2 *reg)
-{
-  auto_vec<const binding_key2 *> bindings;
-  get_overlapping_bindings (reg, &bindings);
-  // TODO
-  //gcc_unreachable ();
-}
-
 /* class region_model2_manager.  */
 
 region_model2_manager::region_model2_manager ()
@@ -3051,27 +2920,6 @@ region_model2_manager::get_symbolic_region (svalue2 *sval)
   return const_cast <region2 *> (m_symbolic_regions.consolidate (reg));
 }
 
-/* binding consolidation.  */
-
-const concrete_binding2 *
-store2_manager::get_concrete_binding (const region2 *reg,
-					     enum binding_key2::kind kind,
-					     concrete_binding2::bit_offset_t offset)
-{
-  concrete_binding2 *b = new concrete_binding2 (reg, kind, offset);
-  return m_concrete_binding_key_mgr.consolidate (b);
-}
-
-const symbolic_binding2 *
-store2_manager::get_symbolic_binding (const region2 *reg,
-				      enum binding_key2::kind kind,
-				      region2 *concrete_offset_region)
-{
-  symbolic_binding2 *b
-    = new symbolic_binding2 (reg, kind, concrete_offset_region);
-  return m_symbolic_binding_key_mgr.consolidate (b);
-}
-
 /* class region_model2.  */
 
 /* FIXME: region_model2's default ctor.  */
@@ -3291,39 +3139,6 @@ region_model2::dump_dot (const char *path) const
 #endif
 
 
-// TODO: move this to its own header and source file
-
-/* class store2.  */
-
-void
-store2::dump_to_pp (pretty_printer *pp, bool summarize) const
-{
-  /* Sort into some deterministic order.  */
-  auto_vec<const region2 *> base_regions;
-  for (cluster_map_t::iterator iter = m_cluster_map.begin ();
-       iter != m_cluster_map.end (); ++iter)
-    {
-      const region2 *base_reg = (*iter).first;
-      base_regions.safe_push (base_reg);
-    }
-  base_regions.qsort (region2::cmp_ptrs);
-
-  const region2 *base_reg;
-  unsigned i;
-  FOR_EACH_VEC_ELT (base_regions, i, base_reg)
-    {
-      if (i > 0)
-	pp_string (pp, ", ");
-      binding_cluster2 *cluster
-	= *const_cast<cluster_map_t &> (m_cluster_map).get (base_reg);
-      pp_string (pp, "base region: {");
-      base_reg->dump_to_pp (pp, summarize);
-      pp_string (pp, "} has cluster: {");
-      cluster->dump_to_pp (pp, summarize);
-      pp_string (pp, "}");
-    }
-}
-
 // FIXME:
 /* Dump a multiline representation of this model to PP, showing the
    region2 hierarchy, the svalue2s, and any constraints.
@@ -4681,50 +4496,6 @@ region_model2::get_store_value (region2 *reg)
   return m_mgr->get_or_create_initial_value (reg);
 }
 
-svalue2 *
-store2::get_direct_binding (store2_manager *mgr, region2 *reg)
-{
-  return get_binding (mgr, reg, binding_key2::BK_direct);
-}
-
-svalue2 *
-store2::get_default_binding (store2_manager *mgr, region2 *reg)
-{
-  return get_binding (mgr, reg, binding_key2::BK_direct);
-}
-
-svalue2 *
-store2::get_binding (store2_manager *mgr,
-		     region2 *reg,
-		     binding_key2::kind kind)
-{
-  const region2 *base_reg = reg->get_base_region ();
-  binding_cluster2 **cluster_slot = m_cluster_map.get (base_reg);
-  if (!cluster_slot)
-    return NULL;
-  return (*cluster_slot)->get_binding (mgr, reg, kind);
-}
-
-void
-store2::set_value (store2_manager *mgr, region2 *lhs_reg, svalue2 *rhs_sval)
-{
-  remove_overlapping_bindings (mgr, lhs_reg);
-
-  const region2 *base_reg = lhs_reg->get_base_region ();
-  binding_cluster2 *cluster = NULL;
-  binding_cluster2 **slot = m_cluster_map.get (base_reg);
-  if (slot)
-    cluster = *slot;
-  else
-    {
-      cluster = new binding_cluster2 ();
-      m_cluster_map.put (base_reg, cluster);
-    }
-  cluster->bind (mgr, lhs_reg, rhs_sval);
-  // TODO: various kinds of invalidation etc
-}
-
-
 /* Return an svalue2 *for a pointer to RID of type PTR_TYPE, reusing
    existing pointer values if one is available.  */
 #if 0
@@ -5066,22 +4837,6 @@ region_model2::set_value (region2 *lhs_reg, svalue2 *rhs_sval,
   m_store.set_value (m_mgr->get_store2_manager(), lhs_reg, rhs_sval);
 }
 
-/* FIXME.  */
-
-void
-store2::remove_overlapping_bindings (store2_manager *mgr, region2 *reg)
-{
-  const region2 *base_reg = reg->get_base_region ();
-  if (reg == base_reg)
-    {
-      /* Remove whole cluster (if any).  */
-      m_cluster_map.remove (base_reg);
-      return;
-    }
-  if (binding_cluster2 **cluster_slot = m_cluster_map.get (base_reg))
-    (*cluster_slot)->remove_overlapping_bindings (mgr, reg);
-}
-
 /* Set the value of the region2 given by LHS to the value given
    by RHS.  */
 
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 84adeed13d8..f7a3b9539a4 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_ANALYZER_REGION_MODEL_2_H
 
 #include "analyzer/uniq-manager.h" // FIXME
+#include "analyzer/store2.h" // FIXME
 
 /* Implementation of the region-based ternary model described in:
      "A Memory Model for Static Analysis of C Programs"
@@ -529,27 +530,6 @@ is_a_helper <initial_svalue2 *>::test (svalue2 *sval)
 
 namespace ana {
 
-/* The location of a region expressesd as an offset relative to a
-   base region.  */
-
-class region_offset
-{
-public:
-  typedef offset_int bit_offset_t;
-
-  region_offset (const region2 *base_region, bit_offset_t offset)
-  : m_base_region (base_region), m_offset (offset)
-  {}
-
-  const region2 *get_base_region () const { return m_base_region; }
-  bit_offset_t get_bit_offset () const { return m_offset; }
-
-private:
-  const region2 *m_base_region;
-  bit_offset_t m_offset;
-  // FIXME: also need a "symbolic" value
-};
-
 /* Region and its subclasses.
 
    The class hierarchy looks like this (using indentation to show
@@ -1287,201 +1267,6 @@ private:
   svalue2 *m_index;
 };
 
-/* A binding within a store.  */
-
-class binding_key2
-{
-public:
-  virtual ~binding_key2 () {}
-  virtual bool concrete_p () const = 0;
-
-  enum kind
-  {
-   BK_direct,
-   BK_default
-  };
-  static const char *kind_to_string (enum kind kind)
-  {
-    return kind == BK_direct ? "direct" : "default";
-  }
-
-  static const binding_key2 *make (store2_manager *mgr, region2 *r,
-				   enum kind kind);
-
-  virtual void dump_to_pp (pretty_printer *pp, bool simple) const
-  {
-    pp_string (pp, "region: ");
-    m_region->dump_to_pp (pp, simple);
-    pp_printf (pp, ", kind: %s", kind_to_string (m_kind));
-  }
-
-  static int cmp_ptrs (const void *, const void *);
-  static int cmp (const binding_key2 *, const binding_key2 *);
-
-protected:
-  binding_key2 (const region2 *region, enum kind kind)
-  : m_region (region), m_kind (kind) {}
-
-  const region2 *get_region () const { return m_region; }
-
-  enum kind get_kind () const { return m_kind; }
-
-  hashval_t impl_hash () const
-  {
-    return (long)m_region ^ m_kind;
-  }
-  bool impl_eq (const binding_key2 &other)
-  {
-    return m_region == other.m_region && m_kind == other.m_kind;
-  }
-
-private:
-  const region2 *m_region;
-  enum kind m_kind;
-};
-
-class concrete_binding2 : public binding_key2
-{
-public:
-  typedef region_offset::bit_offset_t bit_offset_t;
-
-  concrete_binding2 (const region2 *region, enum kind kind, bit_offset_t offset)
-  : binding_key2 (region, kind), m_offset (offset)
-  {}
-  bool concrete_p () const FINAL OVERRIDE { return true; }
-
-  hashval_t hash () const
-  {
-    return binding_key2::impl_hash (); // FIXME: ^ m_offset;
-  }
-  bool operator== (const concrete_binding2 &other)
-  {
-    if (!binding_key2::impl_eq (other))
-      return false;
-    return m_offset == other.m_offset;
-  }
-
-  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE
-  {
-    binding_key2::dump_to_pp (pp, simple);
-    pp_string (pp, ", offset: ");
-    pp_wide_int (pp, m_offset, SIGNED);
-  }
-
-  bit_offset_t get_bit_offset () const { return m_offset; }
-
-private:
-  bit_offset_t m_offset;
-};
-
-class symbolic_binding2 : public binding_key2
-{
-public:
-  symbolic_binding2 (const region2 *region, enum kind kind,
-		    const region2 *concrete_offset_region)
-  : binding_key2 (region, kind),
-    m_concrete_offset_region (concrete_offset_region)
-  {}
-  bool concrete_p () const FINAL OVERRIDE { return false; }
-
-  hashval_t hash () const
-  {
-    return binding_key2::impl_hash () ^ (long)m_concrete_offset_region;
-  }
-  bool operator== (const symbolic_binding2 &other)
-  {
-    if (!binding_key2::impl_eq (other))
-      return false;
-    return m_concrete_offset_region == other.m_concrete_offset_region;
-  }
-
-  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE
-  {
-    binding_key2::dump_to_pp (pp, simple);
-    pp_string (pp, ", concrete offset region: ");
-    m_concrete_offset_region->dump_to_pp (pp, simple);
-  }
-
-private:
-  const region2 *m_concrete_offset_region;
-};
-
-/* All of the bindings within a store for regions that share the same
-   base region.  */
-
-class binding_cluster2
-{
-public:
-  typedef hash_map <const binding_key2 *, svalue2 *> map_t;
-  //typedef typename map_t::iterator iterator_t;
-
-#if 0
-  binding_cluster2 ();
-  binding_cluster2 (const binding_cluster2 &other);
-#endif
-
-  void dump_to_pp (pretty_printer *pp, bool simple) const;
-
-#if 1
-  void bind (store2_manager *mgr, region2 *, svalue2 *);
-#else
-  const binding_cluster2 *bind (const extrinsic_state &ext_state,
-			       const region2 *, const svalue2 *) const;
-#endif
-
-  svalue2 *get_binding (store2_manager *mgr, region2 *reg,
-			binding_key2::kind kind) const;
-
-  void remove_overlapping_bindings (store2_manager *mgr, region2 *reg);
-
-private:
-  void get_overlapping_bindings (region2 *reg,
-				 auto_vec<const binding_key2 *> *out);
-
-  map_t m_map;
-};
-
-// TODO: move this (and the binding stuff) to its own header
-/* The mapping from regions to values.
-   This is actually expressed by subdividing into clusters.  */
-
-class store2
-{
-public:
-  void dump_to_pp (pretty_printer *pp, bool summarize) const;
-
-  svalue2 *get_direct_binding (store2_manager *mgr, region2 *reg);
-  svalue2 *get_default_binding (store2_manager *mgr, region2 *reg);
-  svalue2 *get_binding (store2_manager *mgr,
-			region2 *reg, binding_key2::kind kind);
-
-  void set_value (store2_manager *mgr, region2 *lhs_reg, svalue2 *rhs_sval);
-
-private:
-  void remove_overlapping_bindings (store2_manager *mgr, region2 *reg);
-
-  typedef hash_map <const region2 *, binding_cluster2 *> cluster_map_t;
-  cluster_map_t m_cluster_map; // TODO: deep copy of this!
-};
-
-class store2_manager
-{
-public:
-  /* binding consolidation.  */
-  const concrete_binding2 *
-  get_concrete_binding (const region2 *region,
-			enum binding_key2::kind kind,
-			concrete_binding2::bit_offset_t offset);
-
-  const symbolic_binding2 *
-  get_symbolic_binding (const region2 *region,
-			enum binding_key2::kind kind,
-			region2 *concrete_offset_region);
-private:
-  uniq_manager<concrete_binding2> m_concrete_binding_key_mgr;
-  uniq_manager<symbolic_binding2> m_symbolic_binding_key_mgr;
-};
-
 /* A class responsible for owning and consolidating region2 and svalue2
    instances.    */
 
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
new file mode 100644
index 00000000000..5fc2cd627c6
--- /dev/null
+++ b/gcc/analyzer/store2.cc
@@ -0,0 +1,334 @@
+/* Classes for modeling the state of memory.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "diagnostic-core.h"
+#include "graphviz.h"
+#include "options.h"
+#include "cgraph.h"
+#include "tree-dfa.h"
+#include "stringpool.h"
+#include "convert.h"
+#include "target.h"
+#include "fold-const.h"
+#include "tree-pretty-print.h"
+#include "diagnostic-color.h"
+#include "diagnostic-metadata.h"
+#include "tristate.h"
+#include "bitmap.h"
+#include "selftest.h"
+#include "function.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "ordered-hash-map.h"
+#include "options.h"
+#include "cgraph.h"
+#include "cfg.h"
+#include "digraph.h"
+#include "analyzer/supergraph.h"
+#include "sbitmap.h"
+#include "analyzer/region-model2.h"
+//#include "analyzer/constraint-manager.h"
+#include "diagnostic-event-id.h"
+#include "analyzer/sm.h"
+#include "diagnostic-event-id.h"
+#include "analyzer/sm.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/analyzer-selftests.h"
+#include "stor-layout.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* class binding_key2.  */
+
+const binding_key2 *
+binding_key2::make (store2_manager *mgr, region2 *r, enum kind kind)
+{
+  region_offset offset = r->get_offset ();
+  // FIXME: what if symbolic vs concrete?
+  return mgr->get_concrete_binding (offset.get_base_region (), kind,
+				    offset.get_bit_offset ());
+}
+
+/* FIXME.  */
+
+void
+binding_key2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  pp_string (pp, "region: ");
+  m_region->dump_to_pp (pp, simple);
+  pp_printf (pp, ", kind: %s", kind_to_string (m_kind));
+}
+
+/* FIXME.  */
+
+int
+binding_key2::cmp_ptrs (const void *p1, const void *p2)
+{
+  const binding_key2 * const *pk1 = (const binding_key2 * const *)p1;
+  const binding_key2 * const *pk2 = (const binding_key2 * const *)p2;
+  return cmp (*pk1, *pk2);
+}
+
+/* FIXME.  */
+
+int
+binding_key2::cmp (const binding_key2 *k1, const binding_key2 *k2)
+{
+  if (int reg_cmp = region2::cmp_ids (k1->m_region, k2->m_region))
+    return reg_cmp;
+
+  enum kind kind1 = k1->get_kind ();
+  enum kind kind2 = k2->get_kind ();
+  if (kind1 != kind2)
+    return (int)kind1 - (int)kind2;
+
+  int concrete1 = k1->concrete_p ();
+  int concrete2 = k2->concrete_p ();
+  if (int concrete_cmp = concrete1 - concrete2)
+    return concrete_cmp;
+  if (concrete1)
+    {
+      const concrete_binding2 *b1 = (const concrete_binding2 *)k1;
+      const concrete_binding2 *b2 = (const concrete_binding2 *)k2;
+      return wi::cmp (b1->get_bit_offset (), b2->get_bit_offset (), SIGNED);
+    }
+  else
+    {
+      // TODO
+      gcc_unreachable ();
+    }
+}
+
+/* class symbolic_binding2 : public binding_key2.  */
+
+void
+symbolic_binding2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  binding_key2::dump_to_pp (pp, simple);
+  pp_string (pp, ", concrete offset region: ");
+  m_concrete_offset_region->dump_to_pp (pp, simple);
+}
+
+/* class binding_cluster2.  */
+
+void
+binding_cluster2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  auto_vec <const binding_key2 *> binding_key2s;
+  for (map_t::iterator iter = m_map.begin ();
+       iter != m_map.end (); ++iter)
+    {
+      const binding_key2 *key = (*iter).first;
+      binding_key2s.safe_push (key);
+    }
+
+  binding_key2s.qsort (binding_key2::cmp_ptrs);
+
+  const binding_key2 *key;
+  unsigned i;
+  FOR_EACH_VEC_ELT (binding_key2s, i, key)
+    {
+      if (i > 0)
+	pp_string (pp, ", ");
+      svalue2 *value = *const_cast <map_t &> (m_map).get (key);
+      pp_string (pp, "binding key: {");
+      key->dump_to_pp (pp, simple);
+      pp_string (pp, "}, value: {");
+      value->dump_to_pp (pp, simple);
+      pp_string (pp, "}");
+    }
+}
+
+void
+binding_cluster2::bind (store2_manager *mgr,
+			region2 *reg, svalue2 *val)
+{
+  const binding_key2 *binding
+    = binding_key2::make (mgr, reg, binding_key2::BK_direct);
+  m_map.put (binding, val);
+}
+
+svalue2 *
+binding_cluster2::get_binding (store2_manager *mgr,
+			       region2 *reg,
+			       binding_key2::kind kind) const
+{
+  const binding_key2 *binding = binding_key2::make (mgr, reg, kind);
+  svalue2 **slot = const_cast<map_t &> (m_map).get (binding);
+  if (slot)
+    return *slot;
+  return NULL;
+}
+
+/* Populate OUT with all bindings within this cluster that overlap REG.  */
+
+void
+binding_cluster2::get_overlapping_bindings (region2 */*reg*/,
+					    auto_vec<const binding_key2 *> */*out*/)
+{
+  /* Get the size of REG.  */
+  // TODO
+
+  for (map_t::iterator iter = m_map.begin ();
+       iter != m_map.end (); ++iter)
+    {
+      //const binding_key2 *key = (*iter).first;
+      // TODO
+    }
+}
+
+/* FIXME.  */
+
+void
+binding_cluster2::remove_overlapping_bindings (store2_manager */*mgr*/,
+					       region2 *reg)
+{
+  auto_vec<const binding_key2 *> bindings;
+  get_overlapping_bindings (reg, &bindings);
+  // TODO
+  //gcc_unreachable ();
+}
+
+/* class store2_manager.  */
+
+/* binding consolidation.  */
+
+const concrete_binding2 *
+store2_manager::get_concrete_binding (const region2 *reg,
+				      enum binding_key2::kind kind,
+				      concrete_binding2::bit_offset_t offset)
+{
+  concrete_binding2 *b = new concrete_binding2 (reg, kind, offset);
+  return m_concrete_binding_key_mgr.consolidate (b);
+}
+
+const symbolic_binding2 *
+store2_manager::get_symbolic_binding (const region2 *reg,
+				      enum binding_key2::kind kind,
+				      region2 *concrete_offset_region)
+{
+  symbolic_binding2 *b
+    = new symbolic_binding2 (reg, kind, concrete_offset_region);
+  return m_symbolic_binding_key_mgr.consolidate (b);
+}
+
+/* class store2.  */
+
+void
+store2::dump_to_pp (pretty_printer *pp, bool summarize) const
+{
+  /* Sort into some deterministic order.  */
+  auto_vec<const region2 *> base_regions;
+  for (cluster_map_t::iterator iter = m_cluster_map.begin ();
+       iter != m_cluster_map.end (); ++iter)
+    {
+      const region2 *base_reg = (*iter).first;
+      base_regions.safe_push (base_reg);
+    }
+  base_regions.qsort (region2::cmp_ptrs);
+
+  const region2 *base_reg;
+  unsigned i;
+  FOR_EACH_VEC_ELT (base_regions, i, base_reg)
+    {
+      if (i > 0)
+	pp_string (pp, ", ");
+      binding_cluster2 *cluster
+	= *const_cast<cluster_map_t &> (m_cluster_map).get (base_reg);
+      pp_string (pp, "base region: {");
+      base_reg->dump_to_pp (pp, summarize);
+      pp_string (pp, "} has cluster: {");
+      cluster->dump_to_pp (pp, summarize);
+      pp_string (pp, "}");
+    }
+}
+
+svalue2 *
+store2::get_direct_binding (store2_manager *mgr, region2 *reg)
+{
+  return get_binding (mgr, reg, binding_key2::BK_direct);
+}
+
+svalue2 *
+store2::get_default_binding (store2_manager *mgr, region2 *reg)
+{
+  return get_binding (mgr, reg, binding_key2::BK_direct);
+}
+
+svalue2 *
+store2::get_binding (store2_manager *mgr,
+		     region2 *reg,
+		     binding_key2::kind kind)
+{
+  const region2 *base_reg = reg->get_base_region ();
+  binding_cluster2 **cluster_slot = m_cluster_map.get (base_reg);
+  if (!cluster_slot)
+    return NULL;
+  return (*cluster_slot)->get_binding (mgr, reg, kind);
+}
+
+void
+store2::set_value (store2_manager *mgr, region2 *lhs_reg, svalue2 *rhs_sval)
+{
+  remove_overlapping_bindings (mgr, lhs_reg);
+
+  const region2 *base_reg = lhs_reg->get_base_region ();
+  binding_cluster2 *cluster = NULL;
+  binding_cluster2 **slot = m_cluster_map.get (base_reg);
+  if (slot)
+    cluster = *slot;
+  else
+    {
+      cluster = new binding_cluster2 ();
+      m_cluster_map.put (base_reg, cluster);
+    }
+  cluster->bind (mgr, lhs_reg, rhs_sval);
+  // TODO: various kinds of invalidation etc
+}
+
+/* FIXME.  */
+
+void
+store2::remove_overlapping_bindings (store2_manager *mgr, region2 *reg)
+{
+  const region2 *base_reg = reg->get_base_region ();
+  if (reg == base_reg)
+    {
+      /* Remove whole cluster (if any).  */
+      m_cluster_map.remove (base_reg);
+      return;
+    }
+  if (binding_cluster2 **cluster_slot = m_cluster_map.get (base_reg))
+    (*cluster_slot)->remove_overlapping_bindings (mgr, reg);
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
new file mode 100644
index 00000000000..560cc29451c
--- /dev/null
+++ b/gcc/analyzer/store2.h
@@ -0,0 +1,219 @@
+/* Classes for modeling the state of memory.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_ANALYZER_STORE2_H
+#define GCC_ANALYZER_STORE2_H
+
+#include "analyzer/uniq-manager.h" // FIXME
+
+/* Implementation of the region-based ternary model described in:
+     "A Memory Model for Static Analysis of C Programs"
+      (Zhongxing Xu, Ted Kremenek, and Jian Zhang)
+     http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf  */
+
+namespace ana {
+
+/* A binding within a store.  */
+
+class binding_key2
+{
+public:
+  virtual ~binding_key2 () {}
+  virtual bool concrete_p () const = 0;
+
+  enum kind
+  {
+   BK_direct,
+   BK_default
+  };
+  static const char *kind_to_string (enum kind kind)
+  {
+    return kind == BK_direct ? "direct" : "default";
+  }
+
+  static const binding_key2 *make (store2_manager *mgr, region2 *r,
+				   enum kind kind);
+
+  virtual void dump_to_pp (pretty_printer *pp, bool simple) const;
+
+  static int cmp_ptrs (const void *, const void *);
+  static int cmp (const binding_key2 *, const binding_key2 *);
+
+protected:
+  binding_key2 (const region2 *region, enum kind kind)
+  : m_region (region), m_kind (kind) {}
+
+  const region2 *get_region () const { return m_region; }
+
+  enum kind get_kind () const { return m_kind; }
+
+  hashval_t impl_hash () const
+  {
+    return (long)m_region ^ m_kind;
+  }
+  bool impl_eq (const binding_key2 &other)
+  {
+    return m_region == other.m_region && m_kind == other.m_kind;
+  }
+
+private:
+  const region2 *m_region;
+  enum kind m_kind;
+};
+
+class concrete_binding2 : public binding_key2
+{
+public:
+  typedef region_offset::bit_offset_t bit_offset_t;
+
+  concrete_binding2 (const region2 *region, enum kind kind, bit_offset_t offset)
+  : binding_key2 (region, kind), m_offset (offset)
+  {}
+  bool concrete_p () const FINAL OVERRIDE { return true; }
+
+  hashval_t hash () const
+  {
+    return binding_key2::impl_hash (); // FIXME: ^ m_offset;
+  }
+  bool operator== (const concrete_binding2 &other)
+  {
+    if (!binding_key2::impl_eq (other))
+      return false;
+    return m_offset == other.m_offset;
+  }
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE
+  {
+    binding_key2::dump_to_pp (pp, simple);
+    pp_string (pp, ", offset: ");
+    pp_wide_int (pp, m_offset, SIGNED);
+  }
+
+  bit_offset_t get_bit_offset () const { return m_offset; }
+
+private:
+  bit_offset_t m_offset;
+};
+
+class symbolic_binding2 : public binding_key2
+{
+public:
+  symbolic_binding2 (const region2 *region, enum kind kind,
+		    const region2 *concrete_offset_region)
+  : binding_key2 (region, kind),
+    m_concrete_offset_region (concrete_offset_region)
+  {}
+  bool concrete_p () const FINAL OVERRIDE { return false; }
+
+  hashval_t hash () const
+  {
+    return binding_key2::impl_hash () ^ (long)m_concrete_offset_region;
+  }
+  bool operator== (const symbolic_binding2 &other)
+  {
+    if (!binding_key2::impl_eq (other))
+      return false;
+    return m_concrete_offset_region == other.m_concrete_offset_region;
+  }
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+
+private:
+  const region2 *m_concrete_offset_region;
+};
+
+/* All of the bindings within a store for regions that share the same
+   base region.  */
+
+class binding_cluster2
+{
+public:
+  typedef hash_map <const binding_key2 *, svalue2 *> map_t;
+  //typedef typename map_t::iterator iterator_t;
+
+#if 0
+  binding_cluster2 ();
+  binding_cluster2 (const binding_cluster2 &other);
+#endif
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const;
+
+#if 1
+  void bind (store2_manager *mgr, region2 *, svalue2 *);
+#else
+  const binding_cluster2 *bind (const extrinsic_state &ext_state,
+			       const region2 *, const svalue2 *) const;
+#endif
+
+  svalue2 *get_binding (store2_manager *mgr, region2 *reg,
+			binding_key2::kind kind) const;
+
+  void remove_overlapping_bindings (store2_manager *mgr, region2 *reg);
+
+private:
+  void get_overlapping_bindings (region2 *reg,
+				 auto_vec<const binding_key2 *> *out);
+
+  map_t m_map;
+};
+
+/* The mapping from regions to values.
+   This is actually expressed by subdividing into clusters.  */
+
+class store2
+{
+public:
+  void dump_to_pp (pretty_printer *pp, bool summarize) const;
+
+  svalue2 *get_direct_binding (store2_manager *mgr, region2 *reg);
+  svalue2 *get_default_binding (store2_manager *mgr, region2 *reg);
+  svalue2 *get_binding (store2_manager *mgr,
+			region2 *reg, binding_key2::kind kind);
+
+  void set_value (store2_manager *mgr, region2 *lhs_reg, svalue2 *rhs_sval);
+
+private:
+  void remove_overlapping_bindings (store2_manager *mgr, region2 *reg);
+
+  typedef hash_map <const region2 *, binding_cluster2 *> cluster_map_t;
+  cluster_map_t m_cluster_map; // TODO: deep copy of this!
+};
+
+class store2_manager
+{
+public:
+  /* binding consolidation.  */
+  const concrete_binding2 *
+  get_concrete_binding (const region2 *region,
+			enum binding_key2::kind kind,
+			concrete_binding2::bit_offset_t offset);
+
+  const symbolic_binding2 *
+  get_symbolic_binding (const region2 *region,
+			enum binding_key2::kind kind,
+			region2 *concrete_offset_region);
+private:
+  uniq_manager<concrete_binding2> m_concrete_binding_key_mgr;
+  uniq_manager<symbolic_binding2> m_symbolic_binding_key_mgr;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_STORE2_H */
-- 
2.21.0

