From 1a38f88ef3c9e22855683329f7edca8f72a85b7d Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 30 Apr 2020 06:55:18 -0400
Subject: [PATCH 92/96] FIXME: enough get_representative to get
 state_change_events working

---
 gcc/analyzer/checker-path.cc       |  1 +
 gcc/analyzer/diagnostic-manager.cc | 15 ++++-----
 gcc/analyzer/program-state.cc      |  9 +++++
 gcc/analyzer/program-state.h       |  3 +-
 gcc/analyzer/region-model2.cc      | 27 ++++++++++++---
 gcc/analyzer/region-model2.h       |  5 ++-
 gcc/analyzer/store2.cc             | 54 ++++++++++++++++++++++++++++++
 gcc/analyzer/store2.h              |  6 ++++
 8 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index c07273460d5..dc8f59b5004 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -227,6 +227,7 @@ state_change_event::state_change_event (const supernode *node,
   m_origin (origin),
   m_dst_state (dst_state)
 {
+  gcc_assert (m_var);
 }
 
 /* Implementation of diagnostic_event::get_desc vfunc for
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 4fe4b1a3680..400acd3d465 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -855,7 +855,7 @@ public:
   bool on_state_change (const state_machine &sm,
 			state_machine::state_t src_sm_val,
 			state_machine::state_t dst_sm_val,
-			/* tree dst_rep, */
+			tree dst_rep,
 			svalue2 *dst_origin_sval) FINAL OVERRIDE
   {
     const exploded_node *src_node = m_eedge.m_src;
@@ -882,11 +882,7 @@ public:
       return false;
 
     tree origin_rep
-#if 0
-      = dst_state.get_representative_tree (dst_origin_sid);
-#else
-    = NULL_TREE; // FIXME
-#endif    
+      = dst_state.get_representative_tree2 (dst_origin_sval);
 #if 0
     if (origin_rep == NULL_TREE)
       origin_rep = get_any_origin (stmt, dst_rep, dst_state);
@@ -895,7 +891,7 @@ public:
 							stmt,
 							stack_depth,
 							sm,
-							NULL_TREE, /* dst_rep FIXME */
+							dst_rep,
 							src_sm_val,
 							dst_sm_val,
 							origin_rep,
@@ -953,16 +949,17 @@ for_each_state_change2 (const program_state &src_state,
 	   ++iter)
 	{
 #if 1
-
 	  // FIXME: we can compare them now
+	  // FIXME: do we want to sort them first, then emit events?
 	  svalue2 *sval = (*iter).first;
+	  tree dst_rep = dst_state.get_representative_tree2 (sval);
 	  state_machine::state_t dst_sm_val = (*iter).second.m_state;
 	  state_machine::state_t src_sm_val = src_smap.get_state (sval);
 	  if (dst_sm_val != src_sm_val)
 	    {
 	      svalue2 *origin_sval = (*iter).second.m_origin;
 	      if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
-					    /*dst_rep, */origin_sval))
+					    dst_rep, origin_sval))
 		return true;
 	    }
 #else
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index bcabb54ce0a..77f15827cd9 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -1575,6 +1575,15 @@ program_state::get_representative_tree (svalue_id sid) const
   return m_region_model->get_representative_tree (sid);
 }
 
+/* FIXME.  */
+
+tree
+program_state::get_representative_tree2 (svalue2 *sval) const
+{
+  gcc_assert (m_region_model2);
+  return m_region_model2->get_representative_tree (sval);
+}
+
 /* Attempt to merge this state with OTHER, both using EXT_STATE.
    Write the result to *OUT.
    If the states were merged successfully, return true.  */
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index cbe57e0f21d..8a49531d42d 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -382,6 +382,7 @@ public:
   void remap_svalue_ids (const svalue_id_map &map);
 
   tree get_representative_tree (svalue_id sid) const;
+  tree get_representative_tree2 (svalue2 *sval) const;
 
   bool can_purge_p (const extrinsic_state &ext_state,
 		    svalue_id sid)
@@ -459,7 +460,7 @@ public:
   virtual bool on_state_change (const state_machine &sm,
 				state_machine::state_t src_sm_val,
 				state_machine::state_t dst_sm_val,
-				/*tree dst_rep, */
+				tree dst_rep,
 				svalue2 *dst_origin_sval) = 0;
 };
 
diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index f5c9515e38b..ec311d86288 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -1125,6 +1125,13 @@ region2::calc_offset () const
   return region_offset::make_concrete (iter_region, accum_bit_offset);
 }
 
+path_var
+region2::get_representative_path_var () const
+{
+  // TODO: convert to pure virtual
+  gcc_unreachable ();
+}
+
 /* Set this region2's value to RHS_SVAL (or potentially a variant of it,
    for some kinds of casts).  */
 #if 0
@@ -2554,6 +2561,15 @@ decl_region2::dump_to_pp (pretty_printer *pp, bool simple) const
     }
 }
 
+/* FIXME.  */
+
+path_var
+decl_region2::get_representative_path_var () const
+{
+  // FIXME: use correct stack depth
+  return path_var (m_decl, 0);
+}
+
 /* class field_region2 : public region2.  */
 
 void
@@ -5483,14 +5499,16 @@ region_model2::add_new_malloc_region2 ()
 }
 #endif
 
-/* Attempt to return a tree that represents SID, or return NULL_TREE.  */
-#if 0
+/* Attempt to return a tree that represents SVAL, or return NULL_TREE.  */
+
 tree
 region_model2::get_representative_tree (svalue2 *sval) const
 {
-  if (sid.null_p ())
+  if (sval == NULL)
     return NULL_TREE;
 
+  return m_store.get_representative_tree (sval);
+#if 0
   /* Find the first region2 that stores the value (e.g. a local) and
      generate a representative tree for it.  */
   unsigned i;
@@ -5516,8 +5534,9 @@ region_model2::get_representative_tree (svalue2 *sval) const
     }
 
   return maybe_get_constant (sid);
-}
 #endif
+}
+
 /* Attempt to return a path_var that represents the region2, or return
    the NULL path_var.
    For example, a region2 for a field of a local would be a path_var
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index 531927a996c..c1cff246f2b 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -873,6 +873,8 @@ public:
 
   region_offset get_offset ();
 
+  virtual path_var get_representative_path_var () const;
+
  protected:
   region2 (unsigned id, region2 *parent, tree type);
 
@@ -1358,6 +1360,7 @@ public:
   enum region2::kind get_kind () const FINAL OVERRIDE { return RK_DECL; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+  path_var get_representative_path_var () const FINAL OVERRIDE;
 
 protected:
   void add_to_hash (inchash::hash &hstate) const OVERRIDE;
@@ -1775,8 +1778,8 @@ class region_model2
   region2 *create_region_for_heap_alloc (svalue2 *size_in_bytes);
   region2 *create_region_for_alloca (svalue2 *size_in_bytes);
 
+  tree get_representative_tree (svalue2 *sval) const;
 #if 0
-  tree get_representative_tree (svalue2_id sid) const;
   path_var get_representative_path_var (region2_id rid) const;
   void get_path_vars_for_svalue2 (svalue2_id sid, vec<path_var> *out) const;
 
diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc
index 807df24becf..0c52fbb3433 100644
--- a/gcc/analyzer/store2.cc
+++ b/gcc/analyzer/store2.cc
@@ -324,6 +324,39 @@ binding_cluster2::redundant_p () const
   return m_map.elements () == 0 && !m_escaped;
 }
 
+/* Find representative path_vars for SVAL within this binding of BASE_REG,
+   appending the results to OUT_PVS.  */
+
+void
+binding_cluster2::get_representative_path_vars (const region2 *base_reg,
+						svalue2 *sval,
+						auto_vec<path_var> *out_pvs)
+{
+  for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
+    {
+      const binding_key2 *key = (*iter).first;
+      svalue2 *bound_sval = (*iter).second;
+      if (bound_sval == sval)
+	{
+	  if (const concrete_binding2 *ckey
+		= key->dyn_cast_concrete_binding2 ())
+	    {
+	      // FIXME: support fields etc
+	      if (ckey->get_bit_offset () == 0)
+		{
+		  out_pvs->safe_push (base_reg->get_representative_path_var ());
+		}
+	      else
+		gcc_unreachable ();
+	    }
+	  else
+	    {
+	      gcc_unreachable ();
+	    }
+	}
+    }
+}
+
 /* class store2_manager.  */
 
 /* binding consolidation.  */
@@ -592,6 +625,27 @@ store2::escaped_p (const region2 *base_reg) const
   return false;
 }
 
+/* Attempt to return a tree that represents SVAL, or return NULL_TREE.  */
+
+tree
+store2::get_representative_tree (svalue2 *sval) const
+{
+  gcc_assert (sval);
+
+  /* Find all bindings that reference SVAL.  */
+  auto_vec<path_var> pvs;
+  for (cluster_map_t::iterator iter = m_cluster_map.begin ();
+       iter != m_cluster_map.end (); ++iter)
+    {
+      const region2 *base_reg = (*iter).first;
+      binding_cluster2 *cluster = (*iter).second;
+      cluster->get_representative_path_vars (base_reg, sval, &pvs);
+    }
+
+  // TODO: sort; pick best:
+  return pvs[0].m_tree;
+}
+
 /* FIXME.  */
 
 void
diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h
index 2fe0c830f02..97e4e178ab0 100644
--- a/gcc/analyzer/store2.h
+++ b/gcc/analyzer/store2.h
@@ -192,6 +192,10 @@ public:
 
   bool redundant_p () const;
 
+  void get_representative_path_vars (const region2 *base_reg,
+				     svalue2 *sval,
+				     auto_vec<path_var> *out_pvs);
+
 private:
   void get_overlapping_bindings (store2_manager *mgr, region2 *reg,
 				 auto_vec<const binding_key2 *> *out);
@@ -251,6 +255,8 @@ public:
 
   bool escaped_p (const region2 *reg) const;
 
+  tree get_representative_tree (svalue2 *sval) const;
+
 private:
   void remove_overlapping_bindings (store2_manager *mgr, region2 *reg);
 
-- 
2.21.0

