From f0464a051683087c89d711cd9d03c1bbcf31ac43 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 20 Apr 2020 16:13:23 -0400
Subject: [PATCH 060/159] FIXME: implement clobbering

---
 gcc/analyzer/region-model2.cc | 22 +++++++++--
 gcc/analyzer/region-model2.h  |  1 +
 gcc/analyzer/store2.cc        | 72 ++++++++++++++++++++++++++++++-----
 gcc/analyzer/store2.h         | 13 ++++++-
 4 files changed, 94 insertions(+), 14 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index d3b86bb4b28..cf1d2167245 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -3612,14 +3612,22 @@ region_model2::on_gassign (const supernode */*snode*/,
 	// TODO
       }
       break;
+#endif
 
     case CONSTRUCTOR:
       {
-	/* e.g. "x ={v} {CLOBBER};"  */
-	// TODO
+	if (TREE_CLOBBER_P (rhs1))
+	  {
+	    /* e.g. "x ={v} {CLOBBER};"  */
+	    /* TODO: should we remove the value, or replace it with an
+	       "unknown" value?  */
+	    clobber_region (lhs_reg);
+	  }
+	else
+	  gcc_unreachable (); // TODO
       }
       break;
-
+#if 0
     case POINTER_PLUS_EXPR:
       {
 	/* e.g. "_1 = a_10(D) + 12;" */
@@ -4984,6 +4992,14 @@ region_model2::set_value (tree lhs, tree rhs, region_model2_context *ctxt)
   set_value (lhs_reg, rhs_sval, ctxt);
 }
 
+/* FIXME.  */
+
+void
+region_model2::clobber_region (region2 *reg)
+{
+  m_store.clobber_region (m_mgr->get_store2_manager(), reg);
+}
+
 /* Determine what is known about the condition "LHS_SVAL OP RHS_SVAL" within
    this model.  */
 
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 1dae5eca564..d00f207eb41 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -1672,6 +1672,7 @@ class region_model2
   void set_value (region2 *lhs_reg, svalue2 *rhs_sval,
 		  region_model2_context *ctxt);
   void set_value (tree lhs, tree rhs, region_model2_context *ctxt);
+  void clobber_region (region2 *reg);
   svalue2 *set_to_new_unknown_value (region2 *dst_reg, tree type,
 				     region_model2_context *ctxt);
   void copy_region (region2 *dst_reg, region2 *src_reg,
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index 9aca20b586d..839f4259278 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -195,6 +195,16 @@ binding_cluster2::bind (store2_manager *mgr,
   m_map.put (binding, val);
 }
 
+/* FIXME.
+   Return true if the cluster is now empty of bindings.  */
+
+bool
+binding_cluster2::clobber_region (store2_manager *mgr, region2 *reg)
+{
+  remove_overlapping_bindings (mgr, reg);
+  return m_map.elements () == 0;
+}
+
 svalue2 *
 binding_cluster2::get_binding (store2_manager *mgr,
 			       region2 *reg,
@@ -210,30 +220,53 @@ binding_cluster2::get_binding (store2_manager *mgr,
 /* 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*/)
+binding_cluster2::get_overlapping_bindings (store2_manager *mgr,
+					    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 *binding
+    = binding_key2::make (mgr, reg, binding_key2::BK_direct);
+  if (const concrete_binding2 *ckey = binding->dyn_cast_concrete_binding2 ())
     {
-      //const binding_key2 *key = (*iter).first;
-      // TODO
+      for (map_t::iterator iter = m_map.begin ();
+	   iter != m_map.end (); ++iter)
+	{
+	  const binding_key2 *iter_key = (*iter).first;
+	  if (const concrete_binding2 *iter_ckey
+	      = iter_key->dyn_cast_concrete_binding2 ())
+	    {
+	      if (ckey->get_bit_offset () == iter_ckey->get_bit_offset ())
+		out->safe_push (iter_key);
+	      // TODO: also compare sizes?
+	    }
+	  else
+	    {
+	      gcc_unreachable ();
+	    }
+	}
+    }
+  else
+    {
+      gcc_unreachable ();
     }
 }
 
 /* FIXME.  */
 
 void
-binding_cluster2::remove_overlapping_bindings (store2_manager */*mgr*/,
+binding_cluster2::remove_overlapping_bindings (store2_manager *mgr,
 					       region2 *reg)
 {
   auto_vec<const binding_key2 *> bindings;
-  get_overlapping_bindings (reg, &bindings);
-  // TODO
-  //gcc_unreachable ();
+  get_overlapping_bindings (mgr, reg, &bindings);
+
+  unsigned i;
+  const binding_key2 *binding;
+  FOR_EACH_VEC_ELT (bindings, i, binding)
+    m_map.remove (binding);
 }
 
 /* class store2_manager.  */
@@ -273,7 +306,9 @@ store2::store2 (const store2 &other)
        ++iter)
     {
       const region2 *reg = (*iter).first;
+      gcc_assert (reg);
       binding_cluster2 *c = (*iter).second;
+      gcc_assert (c);
       m_cluster_map.put (reg, new binding_cluster2 (*c));
     }
 }
@@ -382,6 +417,23 @@ store2::set_value (store2_manager *mgr, region2 *lhs_reg, svalue2 *rhs_sval)
 
 /* FIXME.  */
 
+void
+store2::clobber_region (store2_manager *mgr, region2 *reg)
+{
+  const region2 *base_reg = reg->get_base_region ();
+  binding_cluster2 **slot = m_cluster_map.get (base_reg);
+  if (!slot)
+    return;
+  binding_cluster2 *cluster = *slot;
+  if (cluster->clobber_region (mgr, reg))
+    {
+      delete cluster;
+      m_cluster_map.remove (base_reg);
+    }
+}
+
+/* FIXME.  */
+
 void
 store2::remove_overlapping_bindings (store2_manager *mgr, region2 *reg)
 {
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index b7b086d149b..47f07397fdb 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace ana {
 
+class concrete_binding2;
+
 /* A binding within a store.  */
 
 class binding_key2
@@ -58,6 +60,9 @@ public:
   static int cmp_ptrs (const void *, const void *);
   static int cmp (const binding_key2 *, const binding_key2 *);
 
+  virtual const concrete_binding2 *dyn_cast_concrete_binding2 () const
+  { return NULL; }
+
 protected:
   binding_key2 (const region2 *region, enum kind kind)
   : m_region (region), m_kind (kind) {}
@@ -108,6 +113,9 @@ public:
     pp_wide_int (pp, m_offset, SIGNED);
   }
 
+  const concrete_binding2 *dyn_cast_concrete_binding2 () const FINAL OVERRIDE
+  { return this; }
+
   bit_offset_t get_bit_offset () const { return m_offset; }
 
 private:
@@ -162,13 +170,15 @@ public:
 			       const region2 *, const svalue2 *) const;
 #endif
 
+  bool clobber_region (store2_manager *mgr, region2 *reg);
+
   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,
+  void get_overlapping_bindings (store2_manager *mgr, region2 *reg,
 				 auto_vec<const binding_key2 *> *out);
 
   typedef hash_map <const binding_key2 *, svalue2 *> map_t;
@@ -200,6 +210,7 @@ public:
 			region2 *reg, binding_key2::kind kind);
 
   void set_value (store2_manager *mgr, region2 *lhs_reg, svalue2 *rhs_sval);
+  void clobber_region (store2_manager *mgr, region2 *reg);
 
 private:
   void remove_overlapping_bindings (store2_manager *mgr, region2 *reg);
-- 
2.21.0

