From b64d199747a27b3ef77e0542f0bfa271e8ec3143 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 16 Aug 2019 14:54:13 -0400
Subject: [PATCH 082/124] FIXME: add 'summarize' bool to region_model dumping

---
 gcc/analyzer/impl-4.cc       |  35 ++++---
 gcc/analyzer/region-model.cc | 225 +++++++++++++++++++++++++++++++++++++------
 gcc/analyzer/region-model.h  |  13 ++-
 3 files changed, 229 insertions(+), 44 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index daed361..f2cfc3f 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -837,10 +837,11 @@ public:
 	      pretty_printer *pp) const;
   std::string to_str (const extrinsic_state &ext_state) const;
 
-  void dump_to_pp (const extrinsic_state &ext_state,
+  void dump_to_pp (const extrinsic_state &ext_state, bool summarize,
 		   pretty_printer *pp) const;
-  void dump_to_file (const extrinsic_state &ext_state, FILE *outf) const;
-  void dump (const extrinsic_state &ext_state) const;
+  void dump_to_file (const extrinsic_state &ext_state, bool summarize,
+		     FILE *outf) const;
+  void dump (const extrinsic_state &ext_state, bool summarize) const;
 
   bool on_edge (exploded_graph &eg,
 		const exploded_node &enode,
@@ -3716,10 +3717,11 @@ program_state::to_str (const extrinsic_state &ext_state) const
 
 void
 program_state::dump_to_pp (const extrinsic_state &ext_state,
+			   bool summarize,
 			   pretty_printer *pp) const
 {
   pp_printf (pp, "rmodel: ");
-  m_region_model->dump_to_pp (pp);
+  m_region_model->dump_to_pp (pp, summarize);
 
   int i;
   sm_state_map *smap;
@@ -3738,6 +3740,7 @@ program_state::dump_to_pp (const extrinsic_state &ext_state,
 
 void
 program_state::dump_to_file (const extrinsic_state &ext_state,
+			     bool summarize,
 			     FILE *outf) const
 {
   pretty_printer pp;
@@ -3745,16 +3748,17 @@ program_state::dump_to_file (const extrinsic_state &ext_state,
   if (outf == stderr)
     pp_show_color (&pp) = pp_show_color (global_dc->printer);
   pp.buffer->stream = outf;
-  dump_to_pp (ext_state, &pp);
+  dump_to_pp (ext_state, summarize, &pp);
   pp_flush (&pp);
 }
 
 /* Dump a multiline representation of this state to stderr.  */
 
 DEBUG_FUNCTION void
-program_state::dump (const extrinsic_state &ext_state) const
+program_state::dump (const extrinsic_state &ext_state,
+		     bool summarize) const
 {
-  dump_to_file (ext_state, stderr);
+  dump_to_file (ext_state, summarize, stderr);
 }
 
 /* Determine if following edge SUCC from ENODE is valid within the graph EG
@@ -4214,6 +4218,11 @@ exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &) const
 #endif
 
 #if 1
+  m_ps.m_state.dump_to_pp (m_ext_state, true, pp);
+  pp_newline (pp);
+#endif
+
+#if 1
   // FIXME: copied-and-pasted from program_state::dump_dot
   {
   int i;
@@ -4347,7 +4356,7 @@ exploded_node::dump_to_pp (pretty_printer *pp) const
   m_ps.m_point.print (pp, f);
   pp_newline (pp);
 
-  m_ps.m_state.dump_to_pp (m_ext_state, pp);
+  m_ps.m_state.dump_to_pp (m_ext_state, false, pp);
   pp_newline (pp);
 }
 
@@ -4435,7 +4444,7 @@ exploded_node::on_stmt (exploded_graph &eg,
 	{
 	  /* Handle the builtin "__analyzer_dump_region_model" by dumping
 	     the region model's state to stderr.  */
-	  state->m_region_model->dump ();
+	  state->m_region_model->dump (false);
 	}
       else if (is_named_call_p (call, "__analyzer_eval", 1))
 	{
@@ -6037,7 +6046,7 @@ exploded_graph::get_or_create_node (const program_point &point,
   if (get_logger ())
     {
       log ("pruned_state: %s", pruned_state.to_str (m_ext_state).c_str ());
-      pruned_state.m_region_model->dump_to_pp (get_logger_pp ());
+      pruned_state.m_region_model->dump_to_pp (get_logger_pp (), true);
     }
 
   stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
@@ -6808,7 +6817,7 @@ exploded_path::feasible_p (logger *logger) const
 		       i,
 		       eedge->m_src->m_index,
 		       eedge->m_dest->m_index);
-	  model.dump_to_pp (logger->get_printer ());
+	  model.dump_to_pp (logger->get_printer (), true);
 	  pp_newline (logger->get_printer ());
 	}
     }
@@ -7819,7 +7828,7 @@ exploded_graph::dump_exploded_nodes () const
 	  pretty_printer pp;
 	  enode->get_point ().print (&pp, format (true));
 	  fprintf (outf, "%s\n", pp_formatted_text (&pp));
-	  enode->get_state ().dump_to_file (m_ext_state, outf);
+	  enode->get_state ().dump_to_file (m_ext_state, false, outf);
 	}
 
       fclose (outf);
@@ -7884,7 +7893,7 @@ exploded_graph::dump_exploded_nodes () const
 			       j + 1, enodes.length (), other_enode->m_index);
 		      other_enode->dump_succs_and_preds (stderr);
 		      /* Dump state.  */
-		      other_enode->get_state ().dump (m_ext_state);
+		      other_enode->get_state ().dump (m_ext_state, false);
 		    }
 		}
 	    }
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 2400252..5448b8f 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -70,6 +70,18 @@ along with GCC; see the file COPYING3.  If not see
 
 /* FIXME.  */
 
+static void
+dump_separator (pretty_printer *pp, bool *is_first)
+{
+  if (!*is_first)
+    pp_string (pp, ", ");
+  *is_first = false;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+/* FIXME.  */
+
 class impl_constraint_manager : public constraint_manager
 {
  public:
@@ -1415,6 +1427,16 @@ map_region::get_or_create (region_model *model,
   return child_rid;
 }
 
+/* FIXME.  */
+
+region_id *
+map_region::get (tree expr)
+{
+  gcc_assert (expr);
+  region_id *slot = m_map.get (expr);
+  return slot;
+}
+
 /* Implementation of region::add_to_hash vfunc for map_region.  */
 
 void
@@ -2810,10 +2832,74 @@ region_model::dump_dot (const char *path) const
 
 /* Dump a multiline representation of this model to PP, showing the
    region hierarchy, the svalues, and any contraints.  */
+// FIXME
 
 void
-region_model::dump_to_pp (pretty_printer *pp) const
+region_model::dump_to_pp (pretty_printer *pp, bool summarize) const
 {
+  if (summarize)
+    {
+      bool is_first = true;
+      region_id frame_id = get_current_frame_id ();
+      frame_region *frame = get_region <frame_region> (frame_id);
+      if (frame)
+	dump_summary_of_map (pp, frame, &is_first);
+
+      region_id globals_id = get_globals_region_id ();
+      map_region *globals = get_region <map_region> (globals_id);
+      if (globals)
+	dump_summary_of_map (pp, globals, &is_first);
+
+      // FIXME
+      unsigned i;
+
+      equiv_class *ec;
+      FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
+	{
+	  for (unsigned j = 0; j < ec->m_vars.length (); j++)
+	    {
+	      svalue_id lhs_sid = ec->m_vars[j];
+	      tree lhs_tree = get_representative_tree (lhs_sid);
+	      for (unsigned k = j + 1; k < ec->m_vars.length (); k++)
+		{
+		  svalue_id rhs_sid = ec->m_vars[k];
+		  tree rhs_tree = get_representative_tree (rhs_sid);
+		  if (rhs_tree
+		      && !(CONSTANT_CLASS_P (lhs_tree)
+			   && CONSTANT_CLASS_P (rhs_tree)))
+		    {
+		      dump_separator (pp, &is_first);
+		      PUSH_IGNORE_WFORMAT
+			pp_printf (pp, "%E == %E", lhs_tree, rhs_tree);
+		      POP_IGNORE_WFORMAT
+		    }
+		}
+	    }
+	}
+
+      constraint *c;
+      FOR_EACH_VEC_ELT (m_constraints->m_constraints, i, c)
+	{
+	  const equiv_class &lhs = c->m_lhs.get_obj (*m_constraints);
+	  const equiv_class &rhs = c->m_rhs.get_obj (*m_constraints);
+	  svalue_id lhs_sid = lhs.get_representative ();
+	  svalue_id rhs_sid = rhs.get_representative ();
+	  tree lhs_tree = get_representative_tree (lhs_sid);
+	  tree rhs_tree = get_representative_tree (rhs_sid);
+	  if (lhs_tree && rhs_tree
+	      && !(CONSTANT_CLASS_P (lhs_tree) && CONSTANT_CLASS_P (rhs_tree)))
+	    {
+	      dump_separator (pp, &is_first);
+	      PUSH_IGNORE_WFORMAT
+		pp_printf (pp, "%E %s %E",
+			   lhs_tree, constraint_op_code (c->m_op), rhs_tree);
+	      POP_IGNORE_WFORMAT
+	   }
+	}
+
+      return;
+    }
+
   get_region (m_root_rid)->dump_to_pp (*this, m_root_rid, pp, "", true);
 
   pp_string (pp, "svalues:");
@@ -2836,22 +2922,84 @@ region_model::dump_to_pp (pretty_printer *pp) const
 /* Dump a multiline representation of this model to FILE.  */
 
 void
-region_model::dump (FILE *fp) const
+region_model::dump (FILE *fp, bool summarize) 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, summarize);
   pp_flush (&pp);
 }
 
 /* Dump a multiline representation of this model to stderr.  */
 
 DEBUG_FUNCTION void
-region_model::dump () const
+region_model::dump (bool summarize) const
 {
-  dump (stderr);
+  dump (stderr, summarize);
+}
+
+/* FIXME.  */
+
+void
+region_model::dump_summary_of_map (pretty_printer *pp,
+				   map_region *map_region,
+				   bool *is_first) const
+{
+  auto_vec<tree> keys (map_region->elements ());
+  for (map_region::iterator_t iter = map_region->begin ();
+       iter != map_region->end ();
+       ++iter)
+    {
+      tree key_a = (*iter).first;
+      keys.quick_push (key_a);
+    }
+  keys.qsort (tree_cmp);
+
+  unsigned i;
+  tree key;
+  FOR_EACH_VEC_ELT (keys, i, key)
+    {
+      region_id child_rid = *map_region->get (key);
+
+      region *child_region = get_region (child_rid);
+      if (!child_region)
+	continue;
+      svalue_id sid = child_region->get_value_direct ();
+      if (sid.null_p ())
+	continue;
+      svalue *sval = get_svalue (sid);
+      switch (sval->get_kind ())
+	{
+	default:
+	  gcc_unreachable ();
+	case SK_REGION:
+	  {
+	    region_svalue *region_sval = as_a <region_svalue *> (sval);
+	    region_id pointee_rid = region_sval->get_pointee ();
+	    tree pointee = get_representative_path_var (pointee_rid).m_tree;
+	    dump_separator (pp, is_first);
+	    PUSH_IGNORE_WFORMAT
+	      pp_printf (pp, "%E: &%E", key, pointee);
+	    POP_IGNORE_WFORMAT
+	  }
+	  break;
+	case SK_CONSTANT:
+	  dump_separator (pp, is_first);
+	  PUSH_IGNORE_WFORMAT
+	    pp_printf (pp, "%E: %E", key,
+		       sval->dyn_cast_constant_svalue ()->get_constant ());
+	  POP_IGNORE_WFORMAT
+	  break;
+	case SK_POISONED:
+	  // TODO
+	  break;
+	case SK_UNKNOWN:
+	  /* Don't print anything for unknown values.  */
+	  break;
+	}
+    }
 }
 
 /* Assert that this object is valid.  */
@@ -3979,7 +4127,7 @@ region_model::eval_condition (tree lhs,
    Otherwise, return NULL_TREE.  */
 
 tree
-region_model::maybe_get_constant (svalue_id sid)
+region_model::maybe_get_constant (svalue_id sid) const
 {
   gcc_assert (!sid.null_p ());
   svalue *sval = get_svalue (sid);
@@ -4018,7 +4166,7 @@ region_model::get_representative_tree (svalue_id sid) const
 	  return pv.m_tree;
       }
 
-  return NULL_TREE; // FIXME
+  return maybe_get_constant (sid);
 }
 
 /* FIXME.  */
@@ -4872,17 +5020,17 @@ model_merger::dump_to_pp (pretty_printer *pp) const
 {
   pp_string (pp, "model A:");
   pp_newline (pp);
-  m_model_a->dump_to_pp (pp);
+  m_model_a->dump_to_pp (pp, false);
   pp_newline (pp);
 
   pp_string (pp, "model B:");
   pp_newline (pp);
-  m_model_b->dump_to_pp (pp);
+  m_model_b->dump_to_pp (pp, false);
   pp_newline (pp);
 
   pp_string (pp, "merged model:");
   pp_newline (pp);
-  m_merged_model->dump_to_pp (pp);
+  m_merged_model->dump_to_pp (pp, false);
   pp_newline (pp);
 
   pp_string (pp, "region map: model A to merged model:");
@@ -5238,6 +5386,28 @@ assert_condition (const location &loc,
   ASSERT_EQ_AT (loc, actual, expected);
 }
 
+/* FIXME.  */
+
+static void
+assert_dump_eq (const location &loc,
+		const region_model &model,
+		bool summarize,
+		const char *expected)
+{
+  auto_fix_quotes sentinel;
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  model.dump_to_pp (&pp, summarize);
+  ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
+}
+
+/* FIXME.  */
+
+#define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
+  SELFTEST_BEGIN_STMT							\
+  assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
+  SELFTEST_END_STMT
+
 /* Smoketest for region_model::dump_to_pp.  */
 
 static void
@@ -5248,23 +5418,20 @@ test_dump ()
   model.get_root_region ()->ensure_globals_region (&model);
   model.get_root_region ()->ensure_heap_region (&model);
 
-  auto_fix_quotes sentinel;
-  pretty_printer pp;
-  pp_format_decoder (&pp) = default_tree_printer;
-  model.dump_to_pp (&pp);
-  ASSERT_STREQ (pp_formatted_text (&pp),
-		"r0: {kind: `root', parent: null, sval: null}\n"
-		"|-stack: r1: {kind: `stack', parent: r0, sval: sv0}\n"
-		"|  |: sval: sv0: {poisoned: uninit}\n"
-		"|-globals: r2: {kind: `map', parent: r0, sval: null, map: {}}\n"
-		"`-heap: r3: {kind: `heap', parent: r0, sval: sv1}\n"
-		"  |: sval: sv1: {poisoned: uninit}\n"
-		"svalues:\n"
-		"  sv0: {poisoned: uninit}\n"
-		"  sv1: {poisoned: uninit}\n"
-		"constraint manager:\n"
-		"  equiv classes:\n"
-		"  constraints:\n");
+  ASSERT_DUMP_EQ (model, false,
+		  "r0: {kind: `root', parent: null, sval: null}\n"
+		  "|-stack: r1: {kind: `stack', parent: r0, sval: sv0}\n"
+		  "|  |: sval: sv0: {poisoned: uninit}\n"
+		  "|-globals: r2: {kind: `map', parent: r0, sval: null, map: {}}\n"
+		  "`-heap: r3: {kind: `heap', parent: r0, sval: sv1}\n"
+		  "  |: sval: sv1: {poisoned: uninit}\n"
+		  "svalues:\n"
+		  "  sv0: {poisoned: uninit}\n"
+		  "  sv1: {poisoned: uninit}\n"
+		  "constraint manager:\n"
+		  "  equiv classes:\n"
+		  "  constraints:\n");
+  ASSERT_DUMP_EQ (model, true, "");
 }
 
 /* Verify that calling region_model::get_rvalue repeatedly on the same
@@ -5569,6 +5736,8 @@ test_assignment ()
 		   model.get_rvalue (int_0, NULL));
   ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0);
   ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
+
+  ASSERT_DUMP_EQ (model, true, "y: 0, x == y");
 }
 
 /* Verify the details of pushing and popping stack frames.  */
@@ -5660,6 +5829,8 @@ test_stack_frames ()
   ASSERT_FALSE (descendents.region_p (a_in_parent_rid));
   ASSERT_EQ (descendents.num_regions (), 3);
 
+  ASSERT_DUMP_EQ (model, true, "x: 0, p: &x, q: &p, b < 10, y != 5");
+
   /* Pop the "child_fn" frame from the stack.  */
   purge_stats purged;
   model.pop_frame (&purged, &ctxt);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 1021cb2..07ba388 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -845,6 +845,7 @@ public:
 			   region_id this_rid,
 			   tree expr, tree type);
   void unbind (tree expr);
+  region_id *get (tree expr);
 
   void remap_region_ids (const region_id_map &map) FINAL OVERRIDE;
 
@@ -863,6 +864,7 @@ public:
 
   iterator_t begin () { return m_map.begin (); }
   iterator_t end () { return m_map.end (); }
+  size_t elements () const { return m_map.elements (); }
 
  protected:
   void add_to_hash (inchash::hash &hstate) const OVERRIDE;
@@ -1127,9 +1129,9 @@ class region_model
   void dump_dot_to_file (FILE *fp) const;
   void dump_dot (const char *path) const;
 
-  void dump_to_pp (pretty_printer *pp) const;
-  void dump (FILE *fp) const;
-  void dump () const;
+  void dump_to_pp (pretty_printer *pp, bool summarize) const;
+  void dump (FILE *fp, bool summarize) const;
+  void dump (bool summarize) const;
 
   void validate () const;
 
@@ -1204,7 +1206,7 @@ class region_model
   bool add_constraint (tree lhs, enum tree_code op, tree rhs,
 		       region_model_context *ctxt);
 
-  tree maybe_get_constant (svalue_id sid);
+  tree maybe_get_constant (svalue_id sid) const;
 
   region_id add_new_malloc_region ();
 
@@ -1266,6 +1268,9 @@ class region_model
   void poison_any_pointers_to_bad_regions (const region_id_set &bad_regions,
 					   enum poison_kind pkind);
 
+  void dump_summary_of_map (pretty_printer *pp, map_region *map_region,
+			    bool *is_first) const;
+
   auto_delete_vec<svalue> m_svalues;
   auto_delete_vec<region> m_regions;
   region_id m_root_rid;
-- 
1.8.5.3

