From e305ac97a425e99e0416b88b0609766bf3db0f20 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 6 Apr 2020 18:24:19 -0400
Subject: [PATCH 010/293] FIXME: consolidate store and revamp_states

---
 gcc/analyzer/revamp-state.cc | 126 +++++++++++++++++++++++++++++++++++
 gcc/analyzer/revamp-state.h  |  24 ++++++-
 2 files changed, 149 insertions(+), 1 deletion(-)

diff --git a/gcc/analyzer/revamp-state.cc b/gcc/analyzer/revamp-state.cc
index 84fa12e03bf..573fa20f7f6 100644
--- a/gcc/analyzer/revamp-state.cc
+++ b/gcc/analyzer/revamp-state.cc
@@ -214,6 +214,43 @@ store::dump_to_pp (pretty_printer *pp) const
   pp_character (pp, '}');
 }
 
+hashval_t
+store::hash () const
+{
+  inchash::hash hstate;
+  for (map_t::iterator iter = m_map.begin ();
+       iter != m_map.end ();
+       ++iter)
+    {
+      const region_val *key = (*iter).first;
+      const sval *val = (*iter).second;
+      hstate.add_ptr (key);
+      hstate.add_ptr (val);
+    }
+  return hstate.end ();
+}
+
+bool
+store::operator== (const store &other) const
+{
+  if (m_map.elements () != other.m_map.elements ())
+    return false;
+
+  for (map_t::iterator iter = m_map.begin ();
+       iter != m_map.end ();
+       ++iter)
+    {
+      const region_val *key = (*iter).first;
+      const sval *val = (*iter).second;
+      const sval **other_slot = const_cast <map_t &> (other.m_map).get (key);
+      if (other_slot == NULL)
+	return false;
+      if (val != *other_slot)
+	return false;
+    }
+  return true;
+}
+
 /* class revamp_state.  */
 
 revamp_state::revamp_state (const extrinsic_state &ext_state)
@@ -439,16 +476,44 @@ revamp_state::to_json () const
   return state_obj;
 }
 
+/* Make this object non-modifiable, in preparation for being consolidated.  */
+
+void
+revamp_state::seal (engine *eng)
+{
+  m_store = const_cast <store *> (eng->consolidate_store (m_store));
+}
+
+hashval_t
+revamp_state::hash () const
+{
+  // FIXME: must have been sealed
+  inchash::hash hstate;
+  hstate.add_ptr (m_store);
+  return hstate.end ();
+}
+
+bool
+revamp_state::operator== (const revamp_state &other) const
+{
+  // FIXME: must have been sealed
+  return m_store == other.m_store;
+}
+
 /* class engine.  */
 
 engine::engine ()
 {
   m_sval_mgr = new uniq_manager<sval> ();
+  m_store_mgr = new uniq_manager<store> ();
+  m_state_mgr = new uniq_manager<revamp_state> ();
 }
 
 engine::~engine ()
 {
   delete m_sval_mgr;
+  delete m_store_mgr;
+  delete m_state_mgr;
 }
 
 size_t
@@ -457,6 +522,25 @@ engine::get_num_svals () const
   return m_sval_mgr->get_count ();
 }
 
+size_t
+engine::get_num_stores () const
+{
+  return m_store_mgr->get_count ();
+}
+
+const revamp_state *
+engine::consolidate_state (revamp_state *rs)
+{
+  rs->seal (this);
+  return m_state_mgr->consolidate (rs);
+}
+
+size_t
+engine::get_num_states () const
+{
+  return m_state_mgr->get_count ();
+}
+
 #if CHECKING_P
 
 namespace selftest {
@@ -498,6 +582,48 @@ test_consolidation ()
   ASSERT_EQ (s.get_lvalue (ext_state, y), y_decl);
   ASSERT_EQ (s.get_rvalue (ext_state, int_17), cst17_0);
   ASSERT_EQ (s.get_rvalue (ext_state, int_42), cst42_0);
+
+  /* Create and consolidate some stores.  */
+  ASSERT_EQ (eng.get_num_stores (), 0);
+  store *st0_mut = new store ();
+  st0_mut->bind (x_decl, cst17_0);
+  st0_mut->bind (y_decl, cst42_0);
+  const store *st0_cons = eng.consolidate_store (st0_mut);
+  ASSERT_EQ (eng.get_num_stores (), 1);
+
+  store *st1_mut = new store ();
+  st1_mut->bind (y_decl, cst42_0);
+  st1_mut->bind (x_decl, cst17_0);
+  const store *st1_cons = eng.consolidate_store (st1_mut);
+  ASSERT_EQ (st0_cons, st1_cons);
+  ASSERT_EQ (eng.get_num_stores (), 1);
+
+  /* Create and consolidate some revamp_states.  */
+  revamp_state *state0_mut = new revamp_state (ext_state);
+  const revamp_state *state0_cons = eng.consolidate_state (state0_mut);
+  ASSERT_EQ (eng.get_num_states (), 1);
+
+  revamp_state *state1_mut = new revamp_state (ext_state);
+  state1_mut->bind (ext_state, x, int_17);
+  const revamp_state *state1_cons = eng.consolidate_state (state1_mut);
+  ASSERT_EQ (eng.get_num_states (), 2);
+  ASSERT_NE (state1_cons, state0_cons);
+
+  /* "x = 17; y = 42;" */
+  revamp_state *state2_mut = new revamp_state (ext_state);
+  state2_mut->bind (ext_state, x, int_17);
+  state2_mut->bind (ext_state, y, int_42);
+  const revamp_state *state2_cons = eng.consolidate_state (state2_mut);
+  ASSERT_EQ (eng.get_num_states (), 3);
+
+  /* "y = 42; x = 17;" should be consolidated into the same state within
+     the engine.  */
+  revamp_state *state3_mut = new revamp_state (ext_state);
+  state3_mut->bind (ext_state, y, int_42);
+  state3_mut->bind (ext_state, x, int_17);
+  const revamp_state *state3_cons = eng.consolidate_state (state3_mut);
+  ASSERT_EQ (state3_cons, state2_cons);
+  ASSERT_EQ (eng.get_num_states (), 3);
 }
 
 /* Run all of the selftests within this file.  */
diff --git a/gcc/analyzer/revamp-state.h b/gcc/analyzer/revamp-state.h
index 16472d19c04..05ec299de95 100644
--- a/gcc/analyzer/revamp-state.h
+++ b/gcc/analyzer/revamp-state.h
@@ -150,6 +150,10 @@ class store
   void dump ();
   void dump_to_pp (pretty_printer *pp) const;
 
+  /* For use with uniq_manager.  */
+  hashval_t hash () const;
+  bool operator== (const store &other) const;
+
  private:
   map_t m_map;
 };
@@ -175,6 +179,12 @@ public:
   const loc_val *get_lvalue (const extrinsic_state &ext_state, tree expr);
   const sval *get_rvalue (const extrinsic_state &ext_state, tree expr);
 
+  void seal (engine *eng);
+
+  /* For use with uniq_manager.  */
+  hashval_t hash () const;
+  bool operator== (const revamp_state &other) const;
+
 private:
   bool on_gassign (const extrinsic_state &ext_state,
 		   const supernode *snode,
@@ -201,6 +211,8 @@ class engine
   engine ();
   ~engine ();
 
+  /* Instance consolidation.  */
+
   template <typename SvalSubclass>
   const SvalSubclass *consolidate_sval (SvalSubclass *s)
   {
@@ -208,9 +220,19 @@ class engine
   }
   size_t get_num_svals () const;
 
+  const store *consolidate_store (store *s)
+  {
+    return m_store_mgr->consolidate (s);
+  }
+  size_t get_num_stores () const;
+
+  const revamp_state *consolidate_state (revamp_state *rs);
+  size_t get_num_states () const;
+
  private:
   uniq_manager<sval> *m_sval_mgr;
-  //uniq_manager *m_sval_mgr;
+  uniq_manager<store> *m_store_mgr;
+  uniq_manager<revamp_state> *m_state_mgr;
 };
 
 } // namespace ana
-- 
2.26.2

