From 4eb8a913d3e1006740cc55758715fb7952a9be42 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 11 May 2020 17:25:39 -0400
Subject: [PATCH 112/315] FIXME: WIP on CONSTRUCTOR, default bindings, etc

---
 gcc/analyzer/region-model2.cc |  24 ++++++--
 gcc/analyzer/region-model2.h  |   1 +
 gcc/analyzer/store2.cc        | 101 ++++++++++++++++++++++++++++------
 gcc/analyzer/store2.h         |  22 +++++++-
 4 files changed, 124 insertions(+), 24 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index f9c608c7288..d8ea2cb6f5e 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -2758,7 +2758,8 @@ region_model2_manager::region_model2_manager ()
   m_code_region (alloc_region_id (), &m_root_region),
   m_fndecls_map (), m_labels_map (),
   m_globals_region (alloc_region_id (), &m_root_region),
-  m_globals_map ()
+  m_globals_map (),
+  m_store2_mgr (this)
 {
   // TODO
 }
@@ -3769,7 +3770,13 @@ region_model2::on_gassign (const supernode */*snode*/,
 	    clobber_region (lhs_reg);
 	  }
 	else
-	  gcc_unreachable (); // TODO
+	  {
+	    /* Any CONSTRUCTOR that survives to this point is presumably
+	       just a zero-init of everything.  */
+	    gcc_assert (CONSTRUCTOR_NELTS (rhs1) == 0);
+	    gcc_assert (!CONSTRUCTOR_NO_CLEARING (rhs1));
+	    zero_fill_region (lhs_reg);
+	  }
       }
       break;
 
@@ -4852,7 +4859,8 @@ static void
 assert_compat_types (tree src_type, tree dst_type)
 {
   if (src_type && dst_type && !VOID_TYPE_P (dst_type))
-    gcc_checking_assert (useless_type_conversion_p (src_type, dst_type));
+    if (!(useless_type_conversion_p (src_type, dst_type)))
+      internal_error ("incompatible types: %qT and %qT", src_type, dst_type);
 }
 
 /* Get the region2 for PV within this region_model2,
@@ -5003,7 +5011,7 @@ const svalue2 *
 region_model2::get_store_value (const region2 *reg)
 {
   const svalue2 *sval
-    = m_store.get_direct_binding (m_mgr->get_store2_manager (), reg);
+    = m_store.get_any_binding (m_mgr->get_store2_manager (), reg);
   if (sval)
     return sval;
 
@@ -5379,6 +5387,14 @@ region_model2::purge_region (const region2 *reg)
   m_store.purge_region (m_mgr->get_store2_manager(), reg);
 }
 
+/* Zero-fill REG.  */
+
+void
+region_model2::zero_fill_region (const region2 *reg)
+{
+  m_store.zero_fill_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 1b5c567df2f..b63d329fffd 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -1861,6 +1861,7 @@ class region_model2
   void set_value (tree lhs, tree rhs, region_model2_context *ctxt);
   void clobber_region (const region2 *reg);
   void purge_region (const region2 *reg);
+  void zero_fill_region (const region2 *reg);
   const svalue2 *set_to_new_unknown_value (const region2 *dst_reg, tree type,
 				     region_model2_context *ctxt);
   void copy_region (const region2 *dst_reg, const region2 *src_reg,
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index 570194dbf64..7a933fc2652 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -234,10 +234,10 @@ binding_cluster2::dump_to_pp (pretty_printer *pp, bool simple,
 
 void
 binding_cluster2::bind (store2_manager *mgr,
-			const region2 *reg, const svalue2 *val)
+			const region2 *reg, const svalue2 *val,
+			binding_key2::kind kind)
 {
-  const binding_key2 *binding
-    = binding_key2::make (mgr, reg, binding_key2::BK_direct);
+  const binding_key2 *binding = binding_key2::make (mgr, reg, kind);
   m_map.put (binding, val);
 }
 
@@ -261,6 +261,25 @@ binding_cluster2::purge_region (store2_manager *mgr, const region2 *reg)
   m_map.remove (binding);
 }
 
+/* FIXME.  */
+
+void
+binding_cluster2::zero_fill_region (store2_manager *mgr, const region2 *reg)
+{
+  clobber_region (mgr, reg);
+
+  /* Add a default binding to zero.  */
+  region_model2_manager *sval_mgr = mgr->get_svalue2_manager ();
+  tree cst_zero = build_int_cst (integer_type_node, 0);
+  const svalue2 *cst_sval = sval_mgr->get_or_create_constant_svalue2 (cst_zero);
+  const svalue2 *cast_sval
+    = sval_mgr->get_or_create_unaryop (reg->get_type (), NOP_EXPR, cst_sval);
+  // FIXME: will want this to fold redundant casts, I guess; it may do it already
+  bind (mgr, reg, cast_sval, binding_key2::BK_default);
+}
+
+/* FIXME.  */
+
 const svalue2 *
 binding_cluster2::get_binding (store2_manager *mgr,
 			       const region2 *reg,
@@ -273,6 +292,34 @@ binding_cluster2::get_binding (store2_manager *mgr,
   return NULL;
 }
 
+/* FIXME.  */
+
+const svalue2 *
+binding_cluster2::get_default_binding_recursive (store2_manager *mgr,
+						 const region2 *reg) const
+{
+  if (const svalue2 *default_sval
+      = get_binding (mgr, reg, binding_key2::BK_default))
+    return default_sval;
+  if (const region2 *parent_reg = reg->get_parent_region ())
+    if (const svalue2 *parent_default_sval
+	= get_default_binding_recursive (mgr, parent_reg))
+      gcc_unreachable (); // TODO: extract value for child
+  return NULL;
+}
+
+/* FIXME.  */
+
+const svalue2 *
+binding_cluster2::get_any_binding (store2_manager *mgr,
+				   const region2 *reg) const
+{
+  if (const svalue2 *direct_sval
+      = get_binding (mgr, reg, binding_key2::BK_direct))
+    return direct_sval;
+  return get_default_binding_recursive (mgr, reg);
+}
+
 /* Populate OUT with all bindings within this cluster that overlap REG.  */
 
 void
@@ -550,6 +597,7 @@ store2::dump_to_pp (pretty_printer *pp, bool summarize, bool multiline) const
     }
 }
 
+#if 0
 const svalue2 *
 store2::get_direct_binding (store2_manager *mgr, const region2 *reg)
 {
@@ -561,17 +609,17 @@ store2::get_default_binding (store2_manager *mgr, const region2 *reg)
 {
   return get_binding (mgr, reg, binding_key2::BK_direct);
 }
+#endif
 
 const svalue2 *
-store2::get_binding (store2_manager *mgr,
-		     const region2 *reg,
-		     binding_key2::kind kind)
+store2::get_any_binding (store2_manager *mgr, const 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);
+  return (*cluster_slot)->get_any_binding (mgr, reg);
 }
 
 void
@@ -581,16 +629,8 @@ store2::set_value (store2_manager *mgr, const region2 *lhs_reg,
   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);
+  binding_cluster2 *cluster = get_or_create_cluster (base_reg);
+  cluster->bind (mgr, lhs_reg, rhs_sval, binding_key2::BK_direct);
   // TODO: various kinds of invalidation etc
 }
 
@@ -632,6 +672,16 @@ store2::purge_region (store2_manager *mgr, const region2 *reg)
 
 /* FIXME.  */
 
+void
+store2::zero_fill_region (store2_manager *mgr, const region2 *reg)
+{
+  const region2 *base_reg = reg->get_base_region ();
+  binding_cluster2 *cluster = get_or_create_cluster (base_reg);
+  cluster->zero_fill_region (mgr, reg);
+}
+
+/* FIXME.  */
+
 binding_cluster2 *
 store2::get_cluster (const region2 *base_reg)
 {
@@ -643,6 +693,23 @@ store2::get_cluster (const region2 *base_reg)
     return NULL;
 }
 
+/* FIXME.  */
+
+binding_cluster2 *
+store2::get_or_create_cluster (const region2 *base_reg)
+{
+  gcc_assert (base_reg);
+  gcc_assert (base_reg->get_base_region () == base_reg);
+  if (binding_cluster2 **slot = m_cluster_map.get (base_reg))
+    return *slot;
+
+  binding_cluster2 *cluster = new binding_cluster2 ();
+  m_cluster_map.put (base_reg, cluster);
+  // FIXME: can this directly go in *slot ?
+
+  return cluster;
+}
+
 /* FIXME.
    For use when handling an unrecognized function call.  */
 /* FIXME: do we want to mark the cluster as having escaped?
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index 3b341f2978b..3cf3e9bae31 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -167,7 +167,8 @@ public:
   void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
 
 #if 1
-  void bind (store2_manager *mgr, const region2 *, const svalue2 *);
+  void bind (store2_manager *mgr, const region2 *, const svalue2 *,
+	     binding_key2::kind kind);
 #else
   const binding_cluster2 *bind (const extrinsic_state &ext_state,
 			       const region2 *, const svalue2 *) const;
@@ -175,9 +176,14 @@ public:
 
   void clobber_region (store2_manager *mgr, const region2 *reg);
   void purge_region (store2_manager *mgr, const region2 *reg);
+  void zero_fill_region (store2_manager *mgr, const region2 *reg);
 
   const svalue2 *get_binding (store2_manager *mgr, const region2 *reg,
 			      binding_key2::kind kind) const;
+  const svalue2 *get_default_binding_recursive (store2_manager *mgr,
+						const region2 *reg) const;
+  const svalue2 *get_any_binding (store2_manager *mgr,
+				  const region2 *reg) const;
 
   void remove_overlapping_bindings (store2_manager *mgr, const region2 *reg);
 
@@ -236,15 +242,16 @@ public:
 
   const svalue2 *get_direct_binding (store2_manager *mgr, const region2 *reg);
   const svalue2 *get_default_binding (store2_manager *mgr, const region2 *reg);
-  const svalue2 *get_binding (store2_manager *mgr,
-			      const region2 *reg, binding_key2::kind kind);
+  const svalue2 *get_any_binding (store2_manager *mgr, const region2 *reg);
 
   void set_value (store2_manager *mgr, const region2 *lhs_reg,
 		  const svalue2 *rhs_sval);
   void clobber_region (store2_manager *mgr, const region2 *reg);
   void purge_region (store2_manager *mgr, const region2 *reg);
+  void zero_fill_region (store2_manager *mgr, const region2 *reg);
 
   binding_cluster2 *get_cluster (const region2 *base_reg);
+  binding_cluster2 *get_or_create_cluster (const region2 *base_reg);
 
   template <typename T>
   void for_each_cluster (void (*cb) (const region2 *base_reg, T user_data),
@@ -273,6 +280,8 @@ private:
 class store2_manager
 {
 public:
+  store2_manager (region_model2_manager *mgr) : m_mgr (mgr) {}
+
   /* binding consolidation.  */
   const concrete_binding2 *
   get_concrete_binding (const region2 *region,
@@ -283,7 +292,14 @@ public:
   get_symbolic_binding (const region2 *region,
 			enum binding_key2::kind kind,
 			const region2 *concrete_offset_region);
+
+  region_model2_manager *get_svalue2_manager () const
+  {
+    return m_mgr;
+  }
+
 private:
+  region_model2_manager *m_mgr;
   uniq_manager<concrete_binding2> m_concrete_binding_key_mgr;
   uniq_manager<symbolic_binding2> m_symbolic_binding_key_mgr;
 };
-- 
2.26.2

