From c055bc34975da42e40aeeabc5084c0444071867e Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Sat, 26 Oct 2019 13:51:28 -0400
Subject: [PATCH 081/119] FIXME: more on revamp of region model: add views

---
 gcc/analyzer/region-model.cc | 185 +++++++++++++++++++++++++++++++++++--------
 gcc/analyzer/region-model.h  |  21 +++--
 2 files changed, 160 insertions(+), 46 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 9a926dd..7f187b4 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -966,6 +966,15 @@ region::operator== (const region &other) const
   if (this_kind != other_kind)
     return false;
 
+  /* Compare views.  */
+  if (m_view_rids.length () != other.m_view_rids.length ())
+    return false;
+  int i;
+  region_id *rid;
+  FOR_EACH_VEC_ELT (m_view_rids, i, rid)
+    if (! (*rid == other.m_view_rids[i]))
+      return false;
+
   switch (this_kind)
     {
     default:
@@ -1078,6 +1087,8 @@ region::set_value (region_model &model, svalue_id rhs_sid)
 #endif
     }
 
+  // TODO: views
+
   m_sval_id = rhs_sid;
 }
 
@@ -1329,12 +1340,35 @@ POP_IGNORE_WFORMAT
 /* Base implementation of region::dump_child_label vfunc.  */
 
 void
-region::dump_child_label (const region_model &model ATTRIBUTE_UNUSED,
+region::dump_child_label (const region_model &model,
 			  region_id this_rid ATTRIBUTE_UNUSED,
-			  region_id child_rid ATTRIBUTE_UNUSED,
-			  pretty_printer *pp ATTRIBUTE_UNUSED) const
+			  region_id child_rid,
+			  pretty_printer *pp) const
 {
-  /* Empty.  */
+  if (is_view_p (child_rid))
+    {
+      region *child = model.get_region (child_rid);
+      gcc_assert (TYPE_P (child->get_type ()));
+PUSH_IGNORE_WFORMAT
+      pp_printf (pp, "view as %qT: ", child->get_type ());
+POP_IGNORE_WFORMAT
+    }
+}
+
+/* FIXME.  */
+void
+region::validate (const region_model *model) const
+{
+  svalue_id sid = get_value_direct ();
+  if (!sid.null_p ())
+    gcc_assert (sid.as_int () < model->get_num_svalues ());
+  unsigned i;
+  region_id *view_rid;
+  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
+    {
+      gcc_assert (!view_rid->null_p ());
+      gcc_assert (view_rid->as_int () < model->get_num_regions ());
+    }
 }
 
 /* Apply MAP to svalue_ids to this region.  This updates the value
@@ -1353,6 +1387,76 @@ void
 region::remap_region_ids (const region_id_map &map)
 {
   map.update (&m_parent_rid);
+  unsigned i;
+  region_id *view_rid;
+  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
+    map.update (view_rid);
+}
+
+/* FIXME.  */
+
+void
+region::add_view (region_id view_rid, region_model *model)
+{
+  gcc_assert (!view_rid.null_p ());
+  region *new_view = model->get_region (view_rid);
+
+  //gcc_assert (new_view->get_type () != NULL_TREE);
+  // TODO: this can sometimes be NULL, when viewing through a (void *)
+
+  // TODO: the type ought to not be present yet
+
+  m_view_rids.safe_push (view_rid);
+}
+
+/* FIXME.  */
+
+region_id
+region::get_view (tree type, region_model *model) const
+{
+  unsigned i;
+  region_id *view_rid;
+  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
+    {
+      region *view = model->get_region (*view_rid);
+      if (view->get_type () == type)
+	return *view_rid;
+    }
+  return region_id::null ();
+}
+
+/* FIXME.  */
+
+bool
+region::is_view_p (region_id child_rid) const
+{
+  unsigned i;
+  region_id *view_rid;
+  FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
+    if (child_rid == *view_rid)
+      return true;
+  return false;
+}
+
+/* region's ctor.  */
+
+region::region (region_id parent_rid, svalue_id sval_id, tree type)
+: m_parent_rid (parent_rid), m_sval_id (sval_id), m_type (type),
+  m_view_rids ()
+{
+  gcc_assert (type == NULL_TREE || TYPE_P (type));
+}
+
+/* region's copy ctor.  */
+
+region::region (const region &other)
+: m_parent_rid (other.m_parent_rid), m_sval_id (other.m_sval_id),
+  m_type (other.m_type), m_view_rids (other.m_view_rids.length ())
+{
+  int i;
+  region_id *rid;
+  FOR_EACH_VEC_ELT (other.m_view_rids, i, rid)
+    m_view_rids.quick_push (*rid);
 }
 
 /* Base implementation of region::add_to_hash vfunc; subclasses should
@@ -1364,6 +1468,7 @@ region::add_to_hash (inchash::hash &hstate) const
   inchash::add (m_parent_rid, hstate);
   inchash::add (m_sval_id, hstate);
   hstate.add_ptr (m_type);
+  // TODO: views
 }
 
 /* Base implementation of region::print_fields vfunc.  */
@@ -1387,6 +1492,8 @@ PUSH_IGNORE_WFORMAT
 POP_IGNORE_WFORMAT
 }
 
+// FIXME: what about canonicalization of m_view_rids of a region?
+
 /* class primitive_region : public region.  */
 
 /* Implementation of region::clone vfunc for primitive_region.  */
@@ -1503,11 +1610,13 @@ POP_IGNORE_WFORMAT
 /* Implementation of region::dump_child_label vfunc for map_region.  */
 
 void
-map_region::dump_child_label (const region_model &model ATTRIBUTE_UNUSED,
-			      region_id this_rid ATTRIBUTE_UNUSED,
+map_region::dump_child_label (const region_model &model,
+			      region_id this_rid,
 			      region_id child_rid,
 			      pretty_printer *pp) const
 {
+  region::dump_child_label (model, this_rid, child_rid, pp);
+
   for (map_t::iterator iter = m_map.begin ();
        iter != m_map.end ();
        ++iter)
@@ -3363,11 +3472,7 @@ region_model::validate () const
   unsigned i;
   region *r;
   FOR_EACH_VEC_ELT (m_regions, i, r)
-    {
-      svalue_id sid = r->get_value_direct ();
-      if (!sid.null_p ())
-	gcc_assert (sid.as_int () < (signed)m_svalues.length ());
-    }
+    r->validate (this);
 
   // TODO: anything else?
 
@@ -4435,7 +4540,12 @@ region_model::maybe_cast (tree dst_type, svalue_id sid)
       tree src_cst = cst_sval->get_constant ();
       // FIXME: maybe introduce a helper for this?
 
-      tree dst = fold_build1 (NOP_EXPR, dst_type, src_cst);
+#if 1
+      //tree dst = fold_convert (dst_type, src_cst);
+      tree dst = convert (dst_type, src_cst);
+#else
+      tree dst = fold_build1 (NOP_EXPR/*VIEW_CONVERT_EXPR*/, dst_type, src_cst);
+#endif
       if (CONSTANT_CLASS_P (dst))
 	return get_or_create_constant_svalue (dst);
     }
@@ -5614,6 +5724,8 @@ region_model::purge_regions (const region_id_set &set_to_purge,
       if (stats)
 	stats->m_num_regions++;
     }
+
+  // FIXME: what about views???
 }
 
 /* Populate *OUT with RID and all of its descendents.  */
@@ -5781,12 +5893,19 @@ region_model::add_view (region_id raw_rid, tree type)
 {
   region *raw_region = get_region (raw_rid);
 
-  // TODO: reuse existing views?
-
   gcc_assert (TYPE_P (type));
   if (type != raw_region->get_type ())
     {
+      /* If the region already has a view of the requested type,
+	 reuse it.  */
+      region_id existing_view_rid = raw_region->get_view (type, this);
+      if (!existing_view_rid.null_p ())
+	return existing_view_rid;
+
+      /* Otherwise, make one (adding it to the region_model and
+	 to the viewed region).  */
       region_id view_rid = add_region_for_type (raw_rid, type);
+      raw_region->add_view (view_rid, this);
       // TODO: something to signify that this is a "view"
       return view_rid;
     }
@@ -6319,20 +6438,20 @@ test_svalue_equality ()
 static void
 test_region_equality ()
 {
-#if 0
-  region *r0 = new map_region (region_id::from_int (3), integer_type_node);
-  region *r1 = new map_region (region_id::from_int (4), integer_type_node);
+  region *r0
+    = new primitive_region (region_id::from_int (3), integer_type_node);
+  region *r1
+    = new primitive_region (region_id::from_int (4), integer_type_node);
 
   ASSERT_EQ (*r0, *r0);
   ASSERT_EQ (r0->hash (), r0->hash ());
   ASSERT_NE (*r0, *r1);
   ASSERT_NE (r0->hash (), r1->hash ());
 
-  // TODO: test coverage for the map within a map_region
-
   delete r0;
   delete r1;
-#endif
+
+  // TODO: test coverage for the map within a map_region
 }
 
 /* A subclass of purge_criteria for selftests: purge all svalue_id instances.  */
@@ -7019,18 +7138,16 @@ test_state_merging ()
   /* Pointers: non-NULL and non-NULL: ptr to a global.  */
   {
     region_model merged;
-    /* x == &y in both input models.  */
-    svalue *merged_x_sval;
-    assert_region_models_merge (x, addr_of_y, addr_of_y, &merged,
-				&merged_x_sval);
-
-    /* We should get x == &y in the merged model.  */
-#if 0
-    ASSERT_EQ (merged_x_sval->get_kind (), SK_REGION);
-    region_svalue *merged_x_ptr = merged_x_sval->dyn_cast_region_svalue ();
-    region_id merged_x_star_rid = merged_x_ptr->get_pointee ();
-    ASSERT_EQ (merged_x_star_rid, merged.get_lvalue (y, NULL));
-#endif
+    /* p == &y in both input models.  */
+    svalue *merged_p_sval;
+    assert_region_models_merge (p, addr_of_y, addr_of_y, &merged,
+				&merged_p_sval);
+
+    /* We should get p == &y in the merged model.  */
+    ASSERT_EQ (merged_p_sval->get_kind (), SK_REGION);
+    region_svalue *merged_p_ptr = merged_p_sval->dyn_cast_region_svalue ();
+    region_id merged_p_star_rid = merged_p_ptr->get_pointee ();
+    ASSERT_EQ (merged_p_star_rid, merged.get_lvalue (y, NULL));
   }
 
   /* Pointers: non-NULL ptrs to different globals: should be unknown.  */
@@ -7052,7 +7169,7 @@ test_state_merging ()
     region_id new_rid = model0.add_new_malloc_region ();
     svalue_id ptr_sid
       = model0.get_or_create_ptr_svalue (ptr_type_node, new_rid);
-    model0.set_value (model0.get_lvalue (x, &ctxt),
+    model0.set_value (model0.get_lvalue (p, &ctxt),
 		      ptr_sid);
     model0.canonicalize (&ctxt);
 
@@ -7067,9 +7184,7 @@ test_state_merging ()
 
     /* The merged model ought to be identical (after canonicalization,
        at least).  */
-#if 0
     ASSERT_EQ (model0, merged);
-#endif
   }
 
   /* Two regions sharing the same unknown svalue should continue sharing
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 15554f5..9223245 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -865,18 +865,15 @@ public:
 
   virtual void walk_for_canonicalization (canonicalization *c) const = 0;
 
- protected:
-  region (region_id parent_rid, svalue_id sval_id, tree type)
-  : m_parent_rid (parent_rid), m_sval_id (sval_id), m_type (type)
-  {
-    gcc_assert (type == NULL_TREE || TYPE_P (type));
-  }
+  void add_view (region_id view_rid, region_model *model);
+  region_id get_view (tree type, region_model *model) const;
+  bool is_view_p (region_id child_rid) const;
 
-  region (const region &other)
-  : m_parent_rid (other.m_parent_rid), m_sval_id (other.m_sval_id),
-    m_type (other.m_type)
-  {
-  }
+  void validate (const region_model *model) const;
+
+ protected:
+  region (region_id parent_rid, svalue_id sval_id, tree type);
+  region (const region &other);
 
   virtual void add_to_hash (inchash::hash &hstate) const;
   virtual void print_fields (const region_model &model,
@@ -887,6 +884,8 @@ public:
   region_id m_parent_rid;
   svalue_id m_sval_id;
   tree m_type;
+  /* Child regions that are "views" (one per type).  */
+  auto_vec<region_id> m_view_rids;
 };
 
 template <>
-- 
1.8.5.3

