From 82acd2122431268088c329a7b51cdfe16b1a1d54 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 15 Jun 2020 15:47:41 -0400
Subject: [PATCH 230/251] FIXME: pass a model2_merger around, rather than just
 a program_point

---
 gcc/analyzer/analyzer.h       |   1 +
 gcc/analyzer/region-model2.cc | 163 ++++------------------------------
 gcc/analyzer/region-model2.h  |  33 ++++---
 gcc/analyzer/store2.cc        |   8 +-
 gcc/analyzer/store2.h         |   4 +-
 5 files changed, 39 insertions(+), 170 deletions(-)

diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 9735b826911..5944d4127dd 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -77,6 +77,7 @@ class region2;
   class field_region2;
   class string_region2;
 class region_model2_manager;
+struct model2_merger;
 class store2_manager;
 class store2;
 class region_model2;
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 0a622b4a881..d7736301829 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -241,7 +241,7 @@ svalue2::unwrap_any_unmergeable () const
 const svalue2 *
 svalue2::can_merge_p (const svalue2 *other,
 		      region_model2_manager *mgr,
-		      const program_point &point) const
+		      model2_merger *merger) const
 {
   if (!(get_type () && other->get_type ()))
     return NULL;
@@ -262,7 +262,8 @@ svalue2::can_merge_p (const svalue2 *other,
     if (tree cst1 = other->maybe_get_constant ())
       {
 	return mgr->get_or_create_widening_svalue2 (other->get_type (),
-						    point, other, this);
+						    merger->m_point,
+						    other, this);
       }
   /* TODO: also detect widening symbolically via binary ops
      e.g. for (i = start; i < end; i+= step).  */
@@ -7697,9 +7698,11 @@ region_model2::can_merge_with_p (const region_model2 &other_model,
     return false;
   out_model->m_current_frame = m_current_frame;
 
+  model2_merger m (this, &other_model, point, out_model);
+
   if (!store2::can_merge_p (&m_store, &other_model.m_store,
 			    &out_model->m_store, m_mgr->get_store2_manager (),
-			    point))
+			    &m))
     return false;
 
   /* Merge constraints.  */
@@ -8007,184 +8010,50 @@ region_model2::record_dynamic_extents (const region2 *reg,
 #endif
 }
 
-/* struct model_merger.  */
+/* struct model2_merger.  */
 
 /* Dump a multiline representation of this merger to PP.  */
-#if 0
+
 void
-model_merger::dump_to_pp (pretty_printer *pp, bool simple) const
+model2_merger::dump_to_pp (pretty_printer *pp, bool simple) const
 {
   pp_string (pp, "model A:");
   pp_newline (pp);
-  m_model_a->dump_to_pp (pp, false);
+  m_model_a->dump_to_pp (pp, simple, true);
   pp_newline (pp);
 
   pp_string (pp, "model B:");
   pp_newline (pp);
-  m_model_b->dump_to_pp (pp, false);
+  m_model_b->dump_to_pp (pp, simple, true);
   pp_newline (pp);
 
   pp_string (pp, "merged model:");
   pp_newline (pp);
-  m_merged_model->dump_to_pp (pp, false);
-  pp_newline (pp);
-
-  pp_string (pp, "region2 map: model A to merged model:");
-  pp_newline (pp);
-  m_map_region2s_from_a_to_m.dump_to_pp (pp);
-  pp_newline (pp);
-
-  pp_string (pp, "region2 map: model B to merged model:");
+  m_merged_model->dump_to_pp (pp, simple, true);
   pp_newline (pp);
-  m_map_region2s_from_b_to_m.dump_to_pp (pp);
-  pp_newline (pp);
-
-  m_sval_mapping->dump_to_pp (pp);
 }
 
 /* Dump a multiline representation of this merger to FILE.  */
 
 void
-model_merger::dump (FILE *fp) const
+model2_merger::dump (FILE *fp, bool simple) const
 {
   pretty_printer pp;
   pp_format_decoder (&pp) = default_tree_printer;
   pp_show_color (&pp) = pp_show_color (global_dc->printer);
   pp.buffer->stream = fp;
-  dump_to_pp (&pp);
+  dump_to_pp (&pp, simple);
   pp_flush (&pp);
 }
 
 /* Dump a multiline representation of this merger to stderr.  */
 
 DEBUG_FUNCTION void
-model_merger::dump () const
-{
-  dump (stderr);
-}
-
-/* Attempt to merge the svalue2s of SID_A and SID_B (from their
-   respective models), writing the id of the resulting svalue2
-   into *MERGED_SVAL.
-   Return true if the merger is possible, false otherwise.  */
-
-bool
-model_merger::can_merge_values_p (const svalue2 *sval_a,
-				  const svalue2 *sval_b,
-				  const svalue2 **merged_sval)
-{
-  gcc_assert (merged_sval);
-  const svalue2 *sval_a = m_model_a->get_svalue2 (sid_a);
-  const svalue2 *sval_b = m_model_b->get_svalue2 (sid_b);
-
-  /* If both are NULL, then the "values" are trivially mergeable.  */
-  if (!sval_a && !sval_b)
-    return true;
-
-  /* If one is NULL and the other non-NULL, then the "values"
-     are not mergeable.  */
-  if (!(sval_a && sval_b))
-    return false;
-
-  /* Have they both already been mapped to the same new svalue2_id?
-     If so, use it.  */
-  const svalue2 *sval_a_in_m
-    = m_sval_mapping->m_map_from_a_to_m.get_dst_for_src (sid_a);
-  const svalue2 *sval_b_in_m
-    = m_sval_mapping->m_map_from_b_to_m.get_dst_for_src (sid_b);
-  if (!sid_a_in_m.null_p ()
-      && !sid_b_in_m.null_p ()
-      && sid_a_in_m == sid_b_in_m)
-    {
-      *merged_sval = sid_a_in_m;
-      return true;
-    }
-
-  tree type = sval_a->get_type ();
-  if (type == NULL_TREE)
-    type = sval_b->get_type ();
-
-  /* If the values have different kinds, or are both unknown,
-     then merge as "unknown".  */
-  if (sval_a->get_kind () != sval_b->get_kind ()
-      || sval_a->get_kind () == SK_UNKNOWN)
-    {
-      const svalue2 *merged_sval = new unknown_svalue2 (type);
-      *merged_sval = m_merged_model->add_svalue2 (merged_sval);
-      record_svalue2s (sid_a, sid_b, *merged_sval);
-      return true;
-    }
-
-  gcc_assert (sval_a->get_kind () == sval_b->get_kind ());
-
-  switch (sval_a->get_kind ())
-    {
-    default:
-    case SK_UNKNOWN: /* SK_UNKNOWN handled above.  */
-       gcc_unreachable ();
-
-    case SK_REGION2:
-      {
-	/* If we have two region2 pointers, then we can merge (possibly to
-	   "unknown").  */
-	const region_svalue2 &region2_sval_a
-	  = *as_a <const region_svalue2 *> (sval_a);
-	const region_svalue2 &region2_sval_b
-	  = *as_a <const region_svalue2 *> (sval_b);
-	region_svalue2::merge_values (region2_sval_a, region2_sval_b,
-				     merged_sval, type,
-				     this);
-	record_svalue2s (sid_a, sid_b, *merged_sval);
-	return true;
-      }
-      break;
-    case SK_CONSTANT:
-      {
-	/* If we have two constants, then we can merge.  */
-	const constant_svalue2 &cst_sval_a
-	  = *as_a <const constant_svalue2 *> (sval_a);
-	const constant_svalue2 &cst_sval_b
-	  = *as_a <const constant_svalue2 *> (sval_b);
-	constant_svalue2::merge_values (cst_sval_a, cst_sval_b,
-				       merged_sval, this);
-	record_svalue2s (sid_a, sid_b, *merged_sval);
-	return true;
-      }
-      break;
-
-    case SK_POISONED:
-    case SK_SETJMP:
-      return false;
-    }
-}
-
-/* Record that A_REG in model A and B_REG in model B
-   correspond to MERGED_REG in the merged model, so
-   that pointers can be accurately merged.  */
-
-void
-model_merger::record_region2s (region2 *a_reg,
-			      region2 *b_reg,
-			      region2 *merged_reg)
+model2_merger::dump (bool simple) const
 {
-  m_map_region2s_from_a_to_m.put (a_reg, merged_reg);
-  m_map_region2s_from_b_to_m.put (b_reg, merged_reg);
+  dump (stderr, simple);
 }
 
-/* Record that A_SVAL in model A and B_SVAL in model B
-   correspond to MERGED_SVAL in the merged model.  */
-
-void
-model_merger::record_svalue2s (const svalue2 *a_sval,
-			      const svalue2 *b_sval,
-			      const svalue2 *merged_sval)
-{
-  gcc_assert (m_sval_mapping);
-  m_sval_mapping->m_map_from_a_to_m.put (a_sval, merged_sval);
-  m_sval_mapping->m_map_from_b_to_m.put (b_sval, merged_sval);
-}
-#endif
-
 /* struct svalue2_id_merger_mapping.  */
 
 #if 0
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 6e12eea003e..d5bcbe58b09 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -137,7 +137,8 @@ struct purge_stats2
      unaryop_svalue2 (SK_UNARYOP): unary operation on another svalue2
      binop_svalue2 (SK_BINOP): binary operation on two svalue2s
      sub_svalue2 (SK_SUB): the result of accessing a subregion
-     unmergeable_svalue2 (SK_UNMERGEABLE): FIXME
+     unmergeable_svalue2 (SK_UNMERGEABLE): a value that is so interesting
+       from a control-flow perspective that it can inhibit state-merging
      placeholder_svalue2 (SK_PLACEHOLDER): for use in selftests.
      widening_svalue2 (SK_WIDENING): a merger of two svalues (possibly
                                      in an iteration).  */
@@ -213,7 +214,7 @@ public:
 
   const svalue2 *can_merge_p (const svalue2 *other,
 			      region_model2_manager *mgr,
-			      const program_point &point) const;
+			      model2_merger *merger) const;
 
  protected:
   svalue2 (tree type) : m_type (type) {}
@@ -2510,29 +2511,26 @@ private:
   int m_num_unexpected_codes;
 };
 
-#if 0
 /* A bundle of data for use when attempting to merge two region_model2
    instances to make a third.  */
 
-struct model_merger
+struct model2_merger
 {
-  model_merger (const region_model2 *model_a,
-		const region_model2 *model_b,
-		region_model2 *merged_model,
-		svalue2_id_merger_mapping *sid_mapping)
+  model2_merger (const region_model2 *model_a,
+		 const region_model2 *model_b,
+		 const program_point &point,
+		 region_model2 *merged_model)
   : m_model_a (model_a), m_model_b (model_b),
-    m_merged_model (merged_model),
-    m_map_region2s_from_a_to_m (model_a->get_num_region2s ()),
-    m_map_region2s_from_b_to_m (model_b->get_num_region2s ()),
-    m_sid_mapping (sid_mapping)
+    m_point (point),
+    m_merged_model (merged_model)
   {
-    gcc_assert (sid_mapping);
   }
 
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump (FILE *fp) const;
-  void dump () const;
+  void dump_to_pp (pretty_printer *pp, bool simple) const;
+  void dump (FILE *fp, bool simple) const;
+  void dump (bool simple) const;
 
+#if 0
   template <typename Subclass>
   Subclass *get_region2_a (region2_id rid_a) const
   {
@@ -2556,9 +2554,11 @@ struct model_merger
   void record_svalue2s (svalue2_id a_sid,
 		       svalue2_id b_sid,
 		       svalue2_id merged_sid);
+#endif
 
   const region_model2 *m_model_a;
   const region_model2 *m_model_b;
+  const program_point &m_point;
   region_model2 *m_merged_model;
 #if 0
   one_way_region2_id_map m_map_region2s_from_a_to_m;
@@ -2566,7 +2566,6 @@ struct model_merger
   svalue2_id_merger_mapping *m_sid_mapping;
 #endif
 };
-#endif
 
 class engine2
 {
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index a87cb330e63..e6fcfe8d23b 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -603,7 +603,7 @@ binding_cluster2::can_merge_p (const binding_cluster2 *cluster_a,
 			       const binding_cluster2 *cluster_b,
 			       binding_cluster2 *out_cluster,
 			       store2_manager *mgr,
-			       const program_point &point)
+			       model2_merger *merger)
 {
   gcc_assert (out_cluster);
 
@@ -664,7 +664,7 @@ binding_cluster2::can_merge_p (const binding_cluster2 *cluster_a,
 	    {
 	      region_model2_manager *sval_mgr = mgr->get_svalue2_manager ();
 	      if (const svalue2 *merged_sval
-		  = sval_a->can_merge_p (sval_b, sval_mgr, point))
+		  = sval_a->can_merge_p (sval_b, sval_mgr, merger))
 		{
 		  out_cluster->m_map.put (key, merged_sval);
 		  continue;
@@ -1369,7 +1369,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_manager *mgr,
-		     const program_point &point)
+		     model2_merger *merger)
 {
   /* Get the union of all base regions for STORE_A and STORE_B.  */
   hash_set<const region2 *> base_regions;
@@ -1396,7 +1396,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, mgr, point))
+					  out_cluster, mgr, merger))
 	return false;
     }
   return true;
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index 04f5b68a5fc..b80213e2268 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -322,7 +322,7 @@ public:
 			   const binding_cluster2 *cluster_b,
 			   binding_cluster2 *out_cluster,
 			   store2_manager *mgr,
-			   const program_point &point);
+			   model2_merger *merger);
   void make_unknown_relative_to (const binding_cluster2 *other_cluster,
 				 store2_manager *mgr);
 
@@ -421,7 +421,7 @@ public:
 
   static bool can_merge_p (const store2 *store_a, const store2 *store_b,
 			   store2 *out_store, store2_manager *mgr,
-			   const program_point &point);
+			   model2_merger *merger);
 
   void on_escape_to_unknown_fncall (store2_manager *mgr,
 				    const region2 *base_reg);
-- 
2.26.2

