From 6703e9018e6efbc7b8309d24479321fd55723092 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 31 Jul 2019 18:46:11 -0400
Subject: [PATCH 055/124] FIXME: add -fdump-analyzer-callgraph

---
 gcc/analyzer/impl-4.cc    | 208 +++++++++++++++++++++++++++++++++++++++++++++-
 gcc/analyzer/supergraph.h |   3 +
 gcc/common.opt            |   4 +
 3 files changed, 214 insertions(+), 1 deletion(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 6906c5d..25406de 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -7669,6 +7669,209 @@ exploded_graph::dump_exploded_nodes () const
 }
 
 /* FIXME.  */
+class my_callgraph_node;
+class my_callgraph_edge;
+class my_callgraph;
+class my_callgraph_cluster;
+
+/* FIXME.  */
+
+struct my_callgraph_traits
+{
+  typedef my_callgraph_node node_t;
+  typedef my_callgraph_edge edge_t;
+  typedef my_callgraph graph_t;
+  struct dump_args_t {};
+  typedef my_callgraph_cluster cluster_t;
+};
+
+/* FIXME.  */
+
+class my_callgraph_node : public dnode<my_callgraph_traits>
+{
+  friend class my_callgraph;
+
+public:
+  my_callgraph_node (function *fun, int index)
+  : m_fun (fun), m_index (index), m_num_supernodes (0), m_num_superedges (0)
+  {
+    gcc_assert (fun);
+  }
+
+  void dump_dot (graphviz_out *gv, const dump_args_t &) const FINAL OVERRIDE
+  {
+    pretty_printer *pp = gv->m_pp;
+
+    dump_dot_id (pp);
+    pp_printf (pp, " [shape=%s,style=filled,fillcolor=%s,label=\"",
+	       "record", "lightgrey");
+    pp_left_brace (pp);
+    pp_write_text_to_stream (pp);
+
+    pp_printf (pp, "MCG: %i: %s", m_index, function_name (m_fun));
+    pp_newline (pp);
+
+    pp_printf (pp, "supernodes: %i\n", m_num_supernodes);
+    pp_newline (pp);
+    pp_printf (pp, "superedges: %i\n", m_num_superedges);
+    pp_newline (pp);
+
+    pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
+    pp_right_brace (pp);
+    pp_string (pp, "\"];\n\n");
+    pp_flush (pp);
+  }
+
+  void dump_dot_id (pretty_printer *pp) const
+  {
+    pp_printf (pp, "mcg_%i", m_index);
+  }
+
+private:
+  function *m_fun;
+  int m_index;
+  int m_num_supernodes;
+  int m_num_superedges;
+};
+
+/* FIXME.  */
+
+class my_callgraph_edge : public dedge<my_callgraph_traits>
+{
+public:
+  my_callgraph_edge (my_callgraph_node *src, my_callgraph_node *dest,
+		     const call_superedge *call_sedge)
+  : dedge (src, dest),
+    m_call_sedge (call_sedge)
+  {}
+
+  void dump_dot (graphviz_out *gv, const dump_args_t &) const
+    FINAL OVERRIDE
+  {
+    pretty_printer *pp = gv->m_pp;
+
+    const char *style = "\"solid,bold\"";
+    const char *color = "black";
+    int weight = 10;
+    const char *constraint = "true";
+
+    m_src->dump_dot_id (pp);
+    pp_string (pp, " -> ");
+    m_dest->dump_dot_id (pp);
+    pp_printf (pp,
+	       (" [style=%s, color=%s, weight=%d, constraint=%s,"
+		" headlabel=\""),
+	       style, color, weight, constraint);
+    pp_printf (pp, "\"];\n");
+  }
+
+private:
+  const call_superedge * const m_call_sedge;
+};
+
+/* FIXME.  */
+
+class my_callgraph : public digraph<my_callgraph_traits>
+{
+public:
+  my_callgraph (const supergraph &sg);
+
+  my_callgraph_node *get_mcg_node_for_function (function *fun)
+  {
+    return *m_map.get (fun);
+  }
+
+  my_callgraph_node *get_mcg_node_for_snode (supernode *snode)
+  {
+    return get_mcg_node_for_function (snode->m_fun);
+  }
+
+private:
+  const supergraph &m_sg;
+  hash_map<function *, my_callgraph_node *> m_map;
+};
+
+/* FIXME.  */
+
+class my_callgraph_cluster : public cluster<my_callgraph_traits>
+{
+};
+
+/* FIXME.  */
+
+my_callgraph::my_callgraph (const supergraph &sg)
+: m_sg (sg)
+{
+  // within cgraph_edge
+#if 0
+  cgraph_node *caller;
+  cgraph_node *callee;
+#endif
+  // callee->get_fun () gets the function * for a *graph_node
+  /* FIXME:
+     maybe do it using the supergraph; we have the information already.  */
+
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+    {
+      function *fun = node->get_fun ();
+      my_callgraph_node *mcg_node
+	= new my_callgraph_node (fun, m_nodes.length ());
+      m_map.put (fun, mcg_node);
+      add_node (mcg_node);
+    }
+
+  unsigned i;
+  superedge *sedge;
+  FOR_EACH_VEC_ELT (sg.m_edges, i, sedge)
+    {
+      my_callgraph_node *mcg_src = get_mcg_node_for_snode (sedge->m_src);
+      if (mcg_src->m_fun)
+	get_mcg_node_for_function (mcg_src->m_fun)->m_num_superedges++;
+      if (const call_superedge *call_sedge = sedge->dyn_cast_call_superedge ())
+	{
+	  my_callgraph_node *mcg_dest = get_mcg_node_for_snode (sedge->m_dest);
+	  my_callgraph_edge *mcg_edge
+	    = new my_callgraph_edge (mcg_src, mcg_dest, call_sedge);
+	  add_edge (mcg_edge);
+	}
+    }
+
+  supernode *snode;
+  FOR_EACH_VEC_ELT (sg.m_nodes, i, snode)
+    {
+      if (snode->m_fun)
+	get_mcg_node_for_function (snode->m_fun)->m_num_supernodes++;
+    }
+}
+
+/* FIXME.  */
+
+static void
+dump_callgraph (const supergraph &sg, const char *filename)
+{
+  FILE *outf = fopen (filename, "w");
+  if (!outf)
+    return;
+
+  // TODO
+  my_callgraph mcg (sg);
+  mcg.dump_dot (filename, NULL, my_callgraph_traits::dump_args_t ());
+
+  fclose (outf);
+}
+
+/* FIXME.  */
+
+static void
+dump_callgraph (const supergraph &sg)
+{
+  char *filename = concat (dump_base_name, ".callgraph.dot", NULL);
+  dump_callgraph (sg, filename);
+  free (filename);
+}
+
+/* FIXME.  */
 
 void
 impl_run_checkers (logger *logger)
@@ -7678,10 +7881,13 @@ impl_run_checkers (logger *logger)
   /* Create the supergraph.  */
   supergraph sg (logger);
 
+  if (flag_dump_analyzer_callgraph)
+    dump_callgraph (sg);
+
   state_purge_map *purge_map = NULL;
 
   if (flag_analyzer_state_purge)
-      purge_map = new state_purge_map (sg, logger);
+    purge_map = new state_purge_map (sg, logger);
 
   if (flag_dump_analyzer_supergraph)
     {
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index 4988d74..8ab8f22 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -285,6 +285,9 @@ class superedge : public dedge<supergraph_traits>
 
   virtual void dump_label_to_pp (pretty_printer *pp,
 				 bool user_facing) const = 0;
+
+  enum edge_kind get_kind () const { return m_kind; }
+
   virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
   virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
   virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
diff --git a/gcc/common.opt b/gcc/common.opt
index 2a5de40..d0dbcb0 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1453,6 +1453,10 @@ fdump-analyzer-supergraph
 Common RejectNegative Var(flag_dump_analyzer_supergraph)
 FIXME
 
+fdump-analyzer-callgraph
+Common RejectNegative Var(flag_dump_analyzer_callgraph)
+FIXME
+
 fdump-analyzer-exploded-graph
 Common RejectNegative Var(flag_dump_analyzer_exploded_graph)
 FIXME
-- 
1.8.5.3

