From d219f619a58de89b2c561a1adc0a27df91e8831c Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 28 Oct 2019 16:19:01 -0400
Subject: [PATCH 83/97] FIXME: fixups to views (region::become_active_view)

---
 gcc/analyzer/region-model.cc | 148 ++++++++++++++++++++++++++++++++++++-------
 gcc/analyzer/region-model.h  |   9 ++-
 2 files changed, 132 insertions(+), 25 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 4ecd782..6381e8c 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1070,7 +1070,7 @@ region::operator== (const region &other) const
    for some kinds of casts).  */
 
 void
-region::set_value (region_model &model, svalue_id rhs_sid)
+region::set_value (region_model &model, region_id this_rid, svalue_id rhs_sid)
 {
   /* Handle some kinds of casting.  */
   if (m_type)
@@ -1087,9 +1087,111 @@ region::set_value (region_model &model, svalue_id rhs_sid)
 #endif
     }
 
+  m_sval_id = rhs_sid;
+
   // TODO: views
+  {
+    /* FIXME: find other views for same region.  */
+    /* FIXME: set to "unknown" all other views for the same region,
+       and recursively clear their child values.
+       FIXME: this could lead to leaks.  Do we need a context?
+       purge_unused_svalues is called by program_state::prune_for_point, so
+       hopefully this happens already.
+       TODO: add a testcase for this.
+       What about a view within a view?
+       Presumably we need to start at the "top-most" view and notify all
+       siblings downwards - but not down the view chain that's currently
+       active.  Perhaps we should mark "active" upwards as we go.
+       Having a concept of an active view might help further: changes to the
+       active view might imply we've already invalidated inactive views,
+       perhaps? */
+    /* If this is a view, it becomes its parent's active view.
+       All other views have their values invalidated.  */
+    if (m_is_view)
+      become_active_view (model, this_rid);
+  }
+}
 
-  m_sval_id = rhs_sid;
+/* FIXME.  */
+
+void
+region::become_active_view (region_model &model, region_id this_rid)
+{
+  gcc_assert (m_is_view);
+
+  region *parent_reg = model.get_region (m_parent_rid);
+  gcc_assert (parent_reg);
+
+
+  region_id old_active_view_rid = parent_reg->m_active_view_rid;
+
+  if (old_active_view_rid == this_rid)
+    {
+      /* Already the active view: do nothing.  */
+      return;
+    }
+
+  /* We have a change of active view.  */
+  parent_reg->m_active_view_rid = this_rid;
+
+  if (old_active_view_rid.null_p ())
+    {
+      /* No previous active view; there ought not to be anything to
+	 invalidate.  */
+      return;
+    }
+
+  /* Purge values from old_active_view_rid and all its
+     descendents.  Potentially we could use a poison value
+     for this, but let's use unknown for now.  */
+  region_id_set below_other_view (&model);
+  model.get_descendents (old_active_view_rid, &below_other_view);
+
+  for (unsigned i = 0; i < model.get_num_regions (); i++)
+    {
+      region_id rid (region_id::from_int (i));
+      if (below_other_view.region_p (rid))
+	{
+	  region *other_reg = model.get_region (rid);
+	  other_reg->m_sval_id = svalue_id::null ();
+	}
+    }
+
+  region *old_active_view = model.get_region (old_active_view_rid);
+  old_active_view->m_sval_id
+    = model.add_svalue (new unknown_svalue (old_active_view->get_type ()));
+
+#if 0
+  /* Iterate over the other views of the parent's region.  */
+  unsigned i;
+  region_id *sibling_rid;
+  FOR_EACH_VEC_ELT (parent_reg->m_view_rids, i, sibling_rid)
+    {
+      if (*sibling_rid != this_rid)
+	{
+	  /* Purge values from sibling_rid and all its
+	     descendents.  Potentially we could use a poison value
+	     for this, but let's use unknown for now.  */
+	  region_id_set below_other_view (&model);
+	  model.get_descendents (*sibling_rid, &below_other_view);
+
+	  for (unsigned i = 0; i < model.get_num_regions (); i++)
+	    {
+	      region_id rid (region_id::from_int (i));
+	      if (below_other_view.region_p (rid))
+		{
+		  region *other_reg = model.get_region (rid);
+		  if (!other_reg->m_sval_id.null_p ())
+		    {
+		      
+		    }
+		    gcc_unreachable (); // TODO
+		}
+	    }
+	}
+    }
+  //#error
+#endif
 }
 
 /* Get a value for this region, either its value if it has one,
@@ -1345,10 +1447,14 @@ region::dump_child_label (const region_model &model,
 			  region_id child_rid,
 			  pretty_printer *pp) const
 {
-  if (is_view_p (child_rid))
+  region *child = model.get_region (child_rid);
+  if (child->m_is_view)
     {
-      region *child = model.get_region (child_rid);
       gcc_assert (TYPE_P (child->get_type ()));
+      if (m_active_view_rid == child_rid)
+	pp_string (pp, "active ");
+      else
+	pp_string (pp, "inactive ");
 PUSH_IGNORE_WFORMAT
       pp_printf (pp, "view as %qT: ", child->get_type ());
 POP_IGNORE_WFORMAT
@@ -1369,6 +1475,8 @@ region::validate (const region_model *model) const
       gcc_assert (!view_rid->null_p ());
       gcc_assert (view_rid->as_int () < model->get_num_regions ());
     }
+  gcc_assert (m_active_view_rid.null_p ()
+	      || m_active_view_rid.as_int () < model->get_num_regions ());
 }
 
 /* Apply MAP to svalue_ids to this region.  This updates the value
@@ -1391,6 +1499,7 @@ region::remap_region_ids (const region_id_map &map)
   region_id *view_rid;
   FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
     map.update (view_rid);
+  map.update (&m_active_view_rid);
 }
 
 /* FIXME.  */
@@ -1400,6 +1509,8 @@ region::add_view (region_id view_rid, region_model *model)
 {
   gcc_assert (!view_rid.null_p ());
   region *new_view = model->get_region (view_rid);
+  new_view->m_is_view = true;
+  gcc_assert (new_view->m_sval_id.null_p ());
 
   //gcc_assert (new_view->get_type () != NULL_TREE);
   // TODO: this can sometimes be NULL, when viewing through a (void *)
@@ -1419,30 +1530,18 @@ region::get_view (tree type, region_model *model) const
   FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
     {
       region *view = model->get_region (*view_rid);
+      gcc_assert (view->m_is_view);
       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 ()
+  m_view_rids (), m_is_view (false), m_active_view_rid (region_id::null ())
 {
   gcc_assert (type == NULL_TREE || TYPE_P (type));
 }
@@ -1451,7 +1550,8 @@ region::region (region_id parent_rid, svalue_id sval_id, tree type)
 
 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 ())
+  m_type (other.m_type), m_view_rids (other.m_view_rids.length ()),
+  m_is_view (other.m_is_view), m_active_view_rid (other.m_active_view_rid)
 {
   int i;
   region_id *rid;
@@ -1919,6 +2019,7 @@ map_region::can_merge_p (const map_region *map_region_a,
 	    return false;
 	  if (!child_merged_sid.null_p ())
 	    child_merged_region->set_value (*merger->m_merged_model,
+					    child_merged_rid,
 					    child_merged_sid);
 
 #if 0
@@ -2719,7 +2820,8 @@ root_region::push_frame (region_model *model, function *fun,
 	      region_id defssa_rid
 		= region->get_or_create (model, frame_rid, parm_default_ssa,
 					 TREE_TYPE (iter_parm));
-	      model->get_region (defssa_rid)->set_value (*model, parm_sid);
+	      model->get_region (defssa_rid)->set_value (*model, defssa_rid,
+							 parm_sid);
 	    }
 	}
     }
@@ -4321,9 +4423,9 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
       {
 	tree cst_type = TREE_TYPE (expr);
 	array_region *cst_region = new array_region (m_root_rid, cst_type);
-	svalue_id cst_sid = get_or_create_constant_svalue (expr);
-	cst_region->set_value (*this, cst_sid);
 	region_id cst_rid = add_region (cst_region);
+	svalue_id cst_sid = get_or_create_constant_svalue (expr);
+	cst_region->set_value (*this, cst_rid, cst_sid);
 	return cst_rid;
       }
       break;
@@ -4674,7 +4776,7 @@ region_model::set_value (region_id lhs_rid, svalue_id rhs_sid)
 {
   gcc_assert (!lhs_rid.null_p ());
   gcc_assert (!rhs_sid.null_p ());
-  get_region (lhs_rid)->set_value (*this, rhs_sid);
+  get_region (lhs_rid)->set_value (*this, lhs_rid, rhs_sid);
 }
 
 /* Determine what is known about the condition "LHS_SID OP RHS_SID" within
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 9223245..b7c04e3 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -828,7 +828,7 @@ public:
 
   region_id get_parent () const { return m_parent_rid; }
 
-  void set_value (region_model &model, svalue_id rhs_sid);
+  void set_value (region_model &model, region_id this_rid, svalue_id rhs_sid);
   svalue_id get_value (region_model &model, bool non_null,
 		       region_model_context *ctxt);
   svalue_id get_value_direct () const { return m_sval_id; }
@@ -867,7 +867,7 @@ public:
 
   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;
+  //bool is_view_p () const { return m_is_view; }
 
   void validate (const region_model *model) const;
 
@@ -881,11 +881,16 @@ public:
 			     pretty_printer *pp) const;
 
  private:
+  void become_active_view (region_model &model, region_id this_rid);
+
   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;
+
+  bool m_is_view;
+  region_id m_active_view_rid;
 };
 
 template <>
-- 
1.8.5.3

