From 6fd540dba516fefaf0a7b6c6d7dd28fbedeb58c8 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 18 Jul 2019 13:09:00 -0400
Subject: [PATCH 103/108] FIXME: add -fdump-analyzer-exploded-nodes-2

---
 gcc/analyzer/impl-4.cc | 227 ++++++++++++++++++++++++++++++-------------------
 gcc/common.opt         |   4 +
 2 files changed, 143 insertions(+), 88 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 6a308d3..fc80ba3 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -815,6 +815,7 @@ public:
 
   void dump_to_pp (const extrinsic_state &ext_state,
 		   pretty_printer *pp) const;
+  void dump_to_file (const extrinsic_state &ext_state, FILE *outf) const;
   void dump (const extrinsic_state &ext_state) const;
 
   program_state prune_for_point (exploded_graph &eg,
@@ -958,6 +959,8 @@ class exploded_node : public dnode<eg_traits>
   const point_and_state *get_ps_key () const { return &m_ps; }
   const program_point *get_point_key () const { return &m_ps.m_point; }
 
+  void dump_succs_and_preds (FILE *outf) const;
+
 private:
   /* The <program_point, program_state> pair.  This is const, as it
      is immutable once the exploded_node has been created.  */
@@ -3510,19 +3513,29 @@ program_state::dump_to_pp (const extrinsic_state &ext_state,
     }
 }
 
-/* Dump a multiline representation of this state to stderr.  */
+/* Dump a multiline representation of this state to OUTF.  */
 
-DEBUG_FUNCTION void
-program_state::dump (const extrinsic_state &ext_state) const
+void
+program_state::dump_to_file (const extrinsic_state &ext_state,
+			     FILE *outf) const
 {
   pretty_printer pp;
   pp_format_decoder (&pp) = default_tree_printer;
-  pp_show_color (&pp) = pp_show_color (global_dc->printer);
-  pp.buffer->stream = stderr;
+  if (outf == stderr)
+    pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp.buffer->stream = outf;
   dump_to_pp (ext_state, &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
+{
+  dump_to_file (ext_state, stderr);
+}
+
 /* Implementation of purge_criteria for using state_purge_map.
 
    Purge state within a path_state using PURGE_MAP for POINT.
@@ -3782,6 +3795,67 @@ program_state::validate (const extrinsic_state &ext_state) const
 
 /* FIXME.  */
 
+static void
+print_run (pretty_printer *pp, int start_idx, int end_idx,
+	   bool *first_run)
+{
+  if (!(*first_run))
+    pp_string (pp, ", ");
+  *first_run = false;
+  if (start_idx == end_idx)
+    pp_printf (pp, "EN: %i", start_idx);
+  else
+    pp_printf (pp, "EN: %i-%i", start_idx, end_idx);
+}
+
+/* Print the indices within ENODES to PP, collecting them as
+   runs/singletons e.g. "EN: 4-7, EN: 20-23, EN: 42".  */
+
+static void
+print_enode_indices (pretty_printer *pp,
+		     const auto_vec<exploded_node *> &enodes)
+{
+  int cur_start_idx = -1;
+  int cur_finish_idx = -1;
+  bool first_run = true;
+  unsigned i;
+  exploded_node *enode;
+  FOR_EACH_VEC_ELT (enodes, i, enode)
+    {
+      if (cur_start_idx == -1)
+	{
+	  gcc_assert (cur_finish_idx == -1);
+	  cur_start_idx = cur_finish_idx = enode->m_index;
+	}
+      else
+	{
+	  if (enode->m_index == cur_finish_idx + 1)
+	    /* Continuation of a run.  */
+	    cur_finish_idx = enode->m_index;
+	  else
+	    {
+	      /* Finish existing run, start a new one.  */
+	      gcc_assert (cur_start_idx >= 0);
+	      gcc_assert (cur_finish_idx >= 0);
+	      print_run (pp, cur_start_idx, cur_finish_idx,
+			 &first_run);
+	      cur_start_idx = cur_finish_idx = enode->m_index;
+	    }
+	}
+    }
+  /* Finish any existing run.  */
+  if (cur_start_idx >= 0)
+    {
+      gcc_assert (cur_finish_idx >= 0);
+      print_run (pp, cur_start_idx, cur_finish_idx,
+		 &first_run);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+/* FIXME.  */
+
 void
 exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &) const
 {
@@ -4132,6 +4206,34 @@ exploded_node::detect_leaks (exploded_graph &eg) const
   new_state.m_region_model->pop_frame (&stats, &ctxt);
 }
 
+/* FIXME.  */
+
+void
+exploded_node::dump_succs_and_preds (FILE *outf) const
+{
+  unsigned i;
+  exploded_edge *e;
+  {
+    auto_vec<exploded_node *> preds;
+    FOR_EACH_VEC_ELT (m_preds, i, e)
+      preds.safe_push (e->m_src);
+    pretty_printer pp;
+    print_enode_indices (&pp, preds);
+    fprintf (outf, "preds: %s\n",
+	     pp_formatted_text (&pp));
+  }
+  {
+    auto_vec<exploded_node *> succs;
+    FOR_EACH_VEC_ELT (m_succs, i, e)
+      succs.safe_push (e->m_dest);
+    pretty_printer pp;
+    print_enode_indices (&pp, succs);
+    fprintf (outf, "succs: %s\n",
+	     pp_formatted_text (&pp));
+  }
+}
+
+
 // TODO: move this fn
 /* Update the call string based on interprocedural
    edges, ensuring that we have interprocedurally valid paths
@@ -7079,68 +7181,9 @@ private:
   exploded_node *m_enode;
 };
 
-/* FIXME.  */
-
-static void
-print_run (pretty_printer *pp, int start_idx, int end_idx,
-	   bool *first_run)
-{
-  if (!(*first_run))
-    pp_string (pp, ", ");
-  *first_run = false;
-  if (start_idx == end_idx)
-    pp_printf (pp, "EN: %i", start_idx);
-  else
-    pp_printf (pp, "EN: %i-%i", start_idx, end_idx);
-}
-
-/* Print the indices within ENODES to PP, collecting them as
-   runs/singletons e.g. "EN: 4-7, EN: 20-23, EN: 42".  */
-
-static void
-print_enode_indices (pretty_printer *pp,
-		     const auto_vec<exploded_node *> &enodes)
-{
-  int cur_start_idx = -1;
-  int cur_finish_idx = -1;
-  bool first_run = true;
-  unsigned i;
-  exploded_node *enode;
-  FOR_EACH_VEC_ELT (enodes, i, enode)
-    {
-      if (cur_start_idx == -1)
-	{
-	  gcc_assert (cur_finish_idx == -1);
-	  cur_start_idx = cur_finish_idx = enode->m_index;
-	}
-      else
-	{
-	  if (enode->m_index == cur_finish_idx + 1)
-	    /* Continuation of a run.  */
-	    cur_finish_idx = enode->m_index;
-	  else
-	    {
-	      /* Finish existing run, start a new one.  */
-	      gcc_assert (cur_start_idx >= 0);
-	      gcc_assert (cur_finish_idx >= 0);
-	      print_run (pp, cur_start_idx, cur_finish_idx,
-			 &first_run);
-	      cur_start_idx = cur_finish_idx = enode->m_index;
-	    }
-	}
-    }
-  /* Finish any existing run.  */
-  if (cur_start_idx >= 0)
-    {
-      gcc_assert (cur_finish_idx >= 0);
-      print_run (pp, cur_start_idx, cur_finish_idx,
-		 &first_run);
-    }
-}
-
-
 /* Postprocessing support for dumping the exploded nodes.
-   Handle -fdump-analyzer-exploded-nodes and the
+   Handle -fdump-analyzer-exploded-nodes,
+   -fdump-analyzer-exploded-nodes-2, and the
    "__analyzer_dump_exploded_nodes" builtin.  */
 
 void
@@ -7192,6 +7235,35 @@ exploded_graph::dump_exploded_nodes () const
 		    "worklist still contains %i nodes", m_worklist.length ());
     }
 
+  /* Dump the egraph in textual form to a dump file.  */
+  if (flag_dump_analyzer_exploded_nodes_2)
+    {
+      auto_client_timevar tv ("-fdump-analyzer-exploded-nodes-2");
+      char *filename
+	= concat (dump_base_name, ".eg.txt", NULL);
+      FILE *outf = fopen (filename, "w");
+      if (!outf)
+	error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
+      free (filename);
+
+      fprintf (outf, "exploded graph for %s\n", dump_base_name);
+
+      unsigned i;
+      exploded_node *enode;
+      FOR_EACH_VEC_ELT (m_nodes, i, enode)
+	{
+	  fprintf (outf, "\n%i of %i: EN %i:\n",
+		   i + 1, m_nodes.length (), enode->m_index);
+	  enode->dump_succs_and_preds (outf);
+	  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);
+	}
+
+      fclose (outf);
+    }
+
   /* Emit a warning at any call to "__analyzer_dump_exploded_nodes",
      giving the number of exploded nodes for "before-stmt", and their
      IDs.  */
@@ -7249,28 +7321,7 @@ exploded_graph::dump_exploded_nodes () const
 		    {
 		      fprintf (stderr, "%i of %i: EN %i:\n",
 			       j + 1, enodes.length (), other_enode->m_index);
-		      /* Dump preds and succs.  */
-		      unsigned k;
-		      exploded_edge *e;
-		      {
-			auto_vec<exploded_node *> preds;
-			FOR_EACH_VEC_ELT (other_enode->m_preds, k, e)
-			  preds.safe_push (e->m_src);
-			pretty_printer pp;
-			print_enode_indices (&pp, preds);
-			fprintf (stderr, "preds: %s\n",
-				 pp_formatted_text (&pp));
-		      }
-		      {
-			auto_vec<exploded_node *> succs;
-			FOR_EACH_VEC_ELT (other_enode->m_succs, k, e)
-			  succs.safe_push (e->m_dest);
-			pretty_printer pp;
-			print_enode_indices (&pp, succs);
-			fprintf (stderr, "succs: %s\n",
-				 pp_formatted_text (&pp));
-		      }
-
+		      other_enode->dump_succs_and_preds (stderr);
 		      /* Dump state.  */
 		      other_enode->get_state ().dump (m_ext_state);
 		    }
diff --git a/gcc/common.opt b/gcc/common.opt
index 84125b0..5c71554 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1457,6 +1457,10 @@ fdump-analyzer-exploded-nodes
 Common RejectNegative Var(flag_dump_analyzer_exploded_nodes)
 FIXME
 
+fdump-analyzer-exploded-nodes-2
+Common RejectNegative Var(flag_dump_analyzer_exploded_nodes_2)
+FIXME
+
 fanalyzer-verbosity=
 Common Joined UInteger Var(analyzer_verbosity) Init(2)
 FIXME
-- 
1.8.5.3

