From 76b46b1d0b99c7a97f75a1ee5e9c1a4a397f7630 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 5 Jun 2020 15:44:43 -0400
Subject: [PATCH 210/377] FIXME: implement merging of svalues that share a
 binding key

---
 gcc/analyzer/region-model2.cc | 23 ++++++++++++++---------
 gcc/analyzer/region-model2.h  |  3 +++
 gcc/analyzer/store2.cc        | 17 ++++++++++++++---
 gcc/analyzer/store2.h         |  5 +++--
 4 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index db25ab5cdbe..a281d26c514 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -227,6 +227,19 @@ svalue2::maybe_undo_cast () const
   return NULL;
 }
 
+/* FIXME.
+   Return NULL if not mergeable.  */
+
+const svalue2 *
+svalue2::can_merge_p (const svalue2 *other,
+		      region_model2_manager *mgr) const
+{
+  if (types_compatible_p (get_type (), other->get_type ()))
+    return mgr->get_or_create_unknown_svalue2 (get_type ());
+  else
+    return NULL;
+}
+
 /* class region_svalue2 : public svalue2.  */
 
 /* FIXME.  */
@@ -7309,7 +7322,7 @@ region_model2::can_merge_with_p (const region_model2 &other_model,
   out_model->m_current_frame = m_current_frame;
 
   if (!store2::can_merge_p (&m_store, &other_model.m_store,
-			    &out_model->m_store))
+			    &out_model->m_store, m_mgr->get_store2_manager ()))
     return false;
 
   /* Merge constraints.  */
@@ -9348,13 +9361,10 @@ test_state_merging ()
   {
     region_model2 merged (&mgr);
     const svalue2 *merged_x_sval;
-    // FIXME:
-#if 0
     assert_region_model2s_merge (x, int_42, int_113, &merged, &merged_x_sval);
 
     /* In particular, there should be an unknown value for "x".  */
     ASSERT_EQ (merged_x_sval->get_kind (), svalue2::SK_UNKNOWN);
-#endif
   }
 
   /* Uninit and constant.  */
@@ -9392,14 +9402,10 @@ test_state_merging ()
   /* Pointers: NULL and non-NULL.  */
   // TODO
 
-  // FIXME: uses "set_to_new_unknown_value"
-#if 0
   /* Pointers: non-NULL and non-NULL: ptr to a local.  */
   {
     region_model2 model0 (&mgr);
     model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
-    model0.set_to_new_unknown_value (model0.get_lvalue (a, NULL),
-				     integer_type_node, NULL);
     model0.set_value (model0.get_lvalue (p, NULL),
 		      model0.get_rvalue (addr_of_a, NULL), NULL);
 
@@ -9411,7 +9417,6 @@ test_state_merging ()
     ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
     ASSERT_EQ (model0, merged);
   }
-#endif
 
   /* Pointers: non-NULL and non-NULL: ptr to a global.  */
   {
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 2a711c9d7d8..c9ce9939913 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -198,6 +198,9 @@ public:
   tree maybe_get_constant () const;
   const svalue2 *maybe_undo_cast () const;
 
+  const svalue2 *can_merge_p (const svalue2 *other,
+			      region_model2_manager *mgr) const;
+
  protected:
   svalue2 (tree type) : m_type (type) {}
 
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index e558aa7c3a3..06953169b25 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -583,7 +583,8 @@ binding_cluster2::remove_overlapping_bindings (store2_manager *mgr,
 bool
 binding_cluster2::can_merge_p (const binding_cluster2 *cluster_a,
 			       const binding_cluster2 *cluster_b,
-			       binding_cluster2 *out_cluster)
+			       binding_cluster2 *out_cluster,
+			       store2_manager *mgr)
 {
   gcc_assert (out_cluster);
 
@@ -644,6 +645,16 @@ binding_cluster2::can_merge_p (const binding_cluster2 *cluster_a,
 	{
 	  /* FIXME: TODO: what should we do when we have non-equal
 	     values?  What does a merged value look like?  */
+	  if (sval_a && sval_b)
+	    {
+	      region_model2_manager *sval_mgr = mgr->get_svalue2_manager ();
+	      if (const svalue2 *merged_sval
+		  = sval_a->can_merge_p (sval_b, sval_mgr))
+		{
+		  out_cluster->m_map.put (key, merged_sval);
+		  continue;
+		}
+	    }
 	  return false;
 	}
     }
@@ -1299,7 +1310,7 @@ store2::get_or_create_cluster (const region2 *base_reg)
 
 bool
 store2::can_merge_p (const store2 *store_a, const store2 *store_b,
-		     store2 *out_store)
+		     store2 *out_store, store2_manager *mgr)
 {
   /* Get the union of all base regions for STORE_A and STORE_B.  */
   hash_set<const region2 *> base_regions;
@@ -1326,7 +1337,7 @@ store2::can_merge_p (const store2 *store_a, const store2 *store_b,
       binding_cluster2 *out_cluster
 	= out_store->get_or_create_cluster (base_reg);
       if (!binding_cluster2::can_merge_p (cluster_a, cluster_b,
-					  out_cluster))
+					  out_cluster, mgr))
 	return false;
     }
   return true;
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index 97435ea9524..b139aa3a15d 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -319,7 +319,8 @@ public:
 
   static bool can_merge_p (const binding_cluster2 *cluster_a,
 			   const binding_cluster2 *cluster_b,
-			   binding_cluster2 *out_cluster);
+			   binding_cluster2 *out_cluster,
+			   store2_manager *mgr);
 
   void on_escape_to_unknown_fncall (store2_manager *mgr);
 
@@ -415,7 +416,7 @@ public:
   }
 
   static bool can_merge_p (const store2 *store_a, const store2 *store_b,
-			   store2 *out_store);
+			   store2 *out_store, store2_manager *mgr);
 
   void on_escape_to_unknown_fncall (store2_manager *mgr,
 				    const region2 *base_reg);
-- 
2.26.2

