From 8a26e38954a78d8f2691550b3fc275af7bddc99b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 16 Jan 2020 21:20:43 -0500
Subject: [PATCH 13/68] FIXME: more WIP on stopping enode explosion

---
 gcc/analyzer/program-state.cc | 132 ++++++++++++++++++++++++++++++++--
 gcc/analyzer/region-model.cc  |  55 +++++++-------
 gcc/analyzer/region-model.h   |  10 +--
 3 files changed, 155 insertions(+), 42 deletions(-)

diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 7716c1a6d80..12ac298bff4 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -780,10 +780,10 @@ program_state::prune_for_point (exploded_graph &eg,
 
   purge_stats stats;
 
+  region_id_set purgeable_regions (new_state.m_region_model);
   const state_purge_map *pm = eg.get_purge_map ();
   if (pm)
     {
-      region_id_set purgeable_ssa_regions (new_state.m_region_model);
       region_id frame_rid
 	= new_state.m_region_model->get_current_frame_id ();
       frame_region *frame
@@ -833,7 +833,7 @@ program_state::prune_for_point (exploded_graph &eg,
 			    continue;
 			  }
 		    }
-		  purgeable_ssa_regions.add_region (rid);
+		  purgeable_regions.add_region (rid);
 		  ssa_names_to_purge.safe_push (var);
 		  if (logger)
 		    logger->log ("purging RID: %i for %qE", rid.as_int (), var);
@@ -849,13 +849,110 @@ program_state::prune_for_point (exploded_graph &eg,
       tree var;
       FOR_EACH_VEC_ELT (ssa_names_to_purge, i, var)
 	frame->unbind (var);
+    }
+
+#if 0
+  /* Unset "unknown" values for global variables that are only used by
+     that global variable, and which don't have children.  */
+  // FIXME: must also not be used in any ECs
+  if (globals_region *globals = new_state.m_region_model->get_globals_region ())
+    {
+#if 0
+      auto_sbitmap single_use_sids;
+      new_state.m_region_model->get_single_use_svalues (&single_use_sids);
+#endif
+
+      auto_vec<tree> globals_to_purge;
+      for (globals_region::map_t::iterator iter = globals->begin ();
+	   iter != globals->end ();
+	   ++iter)
+	{
+	  tree var = (*iter).first;
+	  region_id rid = (*iter).second;
+	  region *region = new_state.m_region_model->get_region (rid);
+	  svalue_id sid = region->get_value_direct ();
+	  if (svalue *sval = new_state.m_region_model->get_svalue (sid))
+	    {
+	      if (sval->get_kind () == SK_UNKNOWN)
+		//if (1/* bitmap_bit_p (&single_use_sids, sid.as_int () */)
+		{
+		  purgeable_regions.add_region (rid);
+		  globals_to_purge.safe_push (var);
+		  if (logger)
+		    logger->log ("purging RID: %i for global %qE",
+				 rid.as_int (), var);
+		}
+	    }
+	}
 
-      /* Purge the regions.  Nothing should point to them, and they
-	 should have no children, as they are for SSA names.  */
-      new_state.m_region_model->purge_regions (purgeable_ssa_regions,
-					       &stats,
-					       eg.get_logger ());
+      /* Unbind the regions from the global regions's map of
+	 vars-to-regions.  */
+      unsigned i;
+      tree var;
+      FOR_EACH_VEC_ELT (globals_to_purge, i, var)
+	globals->unbind (var);
     }
+#endif
+
+#if 0
+  region_id global_rid = snew_state.m_region_model->get_globals_region_id ();
+  if (!globals_rid.null_p ())
+    {
+      auto_vec<int> usage_count;
+      new_state.m_region_model->get_svalue_usage (usage_count);
+      for (int r_idx = 0; r_idx < new_state.m_region_model->get_num_regions ();
+	   r_idx++)
+	{
+	  region *reg
+	    = new_state.m_region_model->get_region (region_id::from_int (r_idx));
+	  if (reg->get_parent () != globals_rid)
+	    continue;
+	  svalue_id sid = reg->get_svalue_direct ();
+	  if (!sid.null_p ())
+	    if (usage_count[sid.as_int ()] <= 1)
+	      {
+		// TODO: needs to have no children
+		purgeable_regions.add_region (rid);
+		if (logger)
+		  logger->log ("purging RID: %i for global", rid.as_int ());
+	      }
+	}
+
+    }
+#endif
+
+#if 1
+  /* TODO: should probably also purge any regions that aren't
+     referenced. */
+  // FIXME: but this needs to happen after the svalues are purged
+  // perhaps; there's an interaction
+  // FIXME: this isn't visiting views, and so the m_view_rids vec can contain
+  // rids that get deleted.
+  // Probably we should visit the views
+  {
+    canonicalization c (*m_region_model);
+    c.walk_rid (m_region_model->get_root_rid ());
+    for (unsigned r_idx = 0 ; r_idx < m_region_model->get_num_regions ();
+	 r_idx++)
+      {
+	region_id rid (region_id::from_int (r_idx));
+	if (c.m_rid_map.get_dst_for_src (rid).null_p ())
+	  {
+	    purgeable_regions.add_region (rid);
+	    if (logger)
+	      logger->log ("purging RID: %i (not referenced)", rid.as_int ());
+	  }
+      }
+  }
+#endif
+
+  /* TODO: should probably also purge "globals" if there aren't any.  */
+
+  /* Purge the regions.  Nothing should point to them, and they
+     should have no children, as they are for SSA names.  */
+  new_state.m_region_model->purge_regions (purgeable_regions,
+					   &stats,
+					   eg.get_logger ());
 
   /* Purge unused svalues.  */
   // TODO: which enode to use, if any?
@@ -1042,6 +1139,27 @@ program_state::validate (const extrinsic_state &ext_state,
 	  /* Not found?  Then sid is redundant.  */
 	  gcc_unreachable ();
 	}
+
+      /* Assert that there are no unreferenced regions.  */
+      /* Presumably we want to find the regions that aren't referenced by
+	 traversing from the root.  */
+      // FIXME: maybe we should do this during pruning
+      canonicalization c (*m_region_model);
+      c.walk_rid (m_region_model->get_root_rid ());
+      for (unsigned r_idx = 0 ; r_idx < m_region_model->get_num_regions ();
+	   r_idx++)
+	{
+	  region_id rid (region_id::from_int (r_idx));
+	  gcc_assert (!c.m_rid_map.get_dst_for_src (rid).null_p ());
+	}
+#if 0
+#error
+	{
+	  bool found_rid = false;
+	  /* Not found?  Then rid is redundant.  */
+	  gcc_unreachable ();
+	}
+#endif
     }
 }
 
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 01ab26e2625..b7f43e61084 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1521,6 +1521,20 @@ region::non_null_p (const region_model &model) const
   return true;
 }
 
+/* Implementation of region::walk_for_canonicalization vfunc for
+   region base class.  */
+
+void
+region::walk_for_canonicalization (canonicalization *c) const
+{
+#if 0
+  #error views
+  region_id rid;
+  FOR_EACH_VEC_ELT (m_view_rids, i rid)
+    ;
+#endif
+}
+
 /* class primitive_region : public region.  */
 
 /* Implementation of region::clone vfunc for primitive_region.  */
@@ -1531,15 +1545,6 @@ primitive_region::clone () const
   return new primitive_region (*this);
 }
 
-/* Implementation of region::walk_for_canonicalization vfunc for
-   primitive_region.  */
-
-void
-primitive_region::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
 /* class map_region : public region.  */
 
 /* map_region's copy ctor.  */
@@ -1953,6 +1958,7 @@ map_region::can_merge_p (const map_region *map_region_a,
 void
 map_region::walk_for_canonicalization (canonicalization *c) const
 {
+  region::walk_for_canonicalization (c);
   auto_vec<tree> keys (m_map.elements ());
   for (map_t::iterator iter = m_map.begin ();
        iter != m_map.end ();
@@ -2416,6 +2422,7 @@ array_region::key_cmp (const void *p1, const void *p2)
 void
 array_region::walk_for_canonicalization (canonicalization *c) const
 {
+  region::walk_for_canonicalization (c);
   auto_vec<int> keys (m_map.elements ());
   for (map_t::iterator iter = m_map.begin ();
        iter != m_map.end ();
@@ -2681,6 +2688,8 @@ stack_region::can_merge_p (const stack_region *stack_region_a,
 void
 stack_region::walk_for_canonicalization (canonicalization *c) const
 {
+  region::walk_for_canonicalization (c);
+
   int i;
   region_id *frame_rid;
   FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
@@ -2742,15 +2751,6 @@ heap_region::clone () const
   return new heap_region (*this);
 }
 
-/* Implementation of region::walk_for_canonicalization vfunc for
-   heap_region.  */
-
-void
-heap_region::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
 /* class root_region : public region.  */
 
 /* root_region's default ctor.  */
@@ -3138,6 +3138,7 @@ root_region::add_to_hash (inchash::hash &hstate) const
 void
 root_region::walk_for_canonicalization (canonicalization *c) const
 {
+  region::walk_for_canonicalization (c);
   c->walk_rid (m_stack_rid);
   c->walk_rid (m_globals_rid);
   c->walk_rid (m_code_rid);
@@ -3195,15 +3196,6 @@ symbolic_region::clone () const
   return new symbolic_region (*this);
 }
 
-/* Implementation of region::walk_for_canonicalization vfunc for
-   symbolic_region.  */
-
-void
-symbolic_region::walk_for_canonicalization (canonicalization *) const
-{
-  /* Empty.  */
-}
-
 /* class region_model.  */
 
 /* region_model's default ctor.  */
@@ -5948,6 +5940,15 @@ region_model::get_globals_region_id () const
   return get_root_region ()->get_globals_region_id ();
 }
 
+/* Return the globals region (which could be NULL).  */
+
+globals_region *
+region_model::get_globals_region () const
+{
+  region_id globals_rid = get_globals_region_id ();
+  return get_region <globals_region> (globals_rid);
+}
+
 /* Add SVAL to this model, taking ownership, and returning its new
    svalue_id.  */
 
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 62ff442c88e..af410439de5 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -885,7 +885,7 @@ public:
   void remap_svalue_ids (const svalue_id_map &map);
   virtual void remap_region_ids (const region_id_map &map);
 
-  virtual void walk_for_canonicalization (canonicalization *c) const = 0;
+  virtual void walk_for_canonicalization (canonicalization *c) const;
 
   void add_view (region_id view_rid, region_model *model);
   region_id get_view (tree type, region_model *model) const;
@@ -944,8 +944,6 @@ public:
   region *clone () const FINAL OVERRIDE;
 
   enum region_kind get_kind () const FINAL OVERRIDE { return RK_PRIMITIVE; }
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
 };
 
 /* A region that has children identified by tree keys.
@@ -1503,9 +1501,6 @@ public:
 			   const heap_region *heap_b, region_id heap_b_rid,
 			   heap_region *merged_heap, region_id merged_heap_rid,
 			   model_merger *merger);
-
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
 };
 
 } // namespace ana
@@ -1621,8 +1616,6 @@ public:
 
   enum region_kind get_kind () const FINAL OVERRIDE { return RK_SYMBOLIC; }
 
-  void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
-
   bool m_possibly_null;
 };
 
@@ -1712,6 +1705,7 @@ class region_model
   function *get_function_at_depth (unsigned depth) const;
 
   region_id get_globals_region_id () const;
+  globals_region *get_globals_region () const;
 
   svalue_id add_svalue (svalue *sval);
   void replace_svalue (svalue_id sid, svalue *new_sval);
-- 
2.21.0

