From 3988e5db115fbd70395878d66e3ae2bc4f179d93 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 26 Aug 2019 18:00:46 -0400
Subject: [PATCH 100/124] FIXME: add per-callstring-data to callgraph dump

---
 gcc/analyzer/impl-4.cc | 124 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 120 insertions(+), 4 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index e821424..df4acaa 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -1158,6 +1158,72 @@ struct eg_point_hash_map_traits
   }
 };
 
+/* FIXME.  */
+
+struct per_call_string_data
+{
+  per_call_string_data (const call_string &key, int num_supernodes)
+  : m_key (key), m_stats (num_supernodes)
+  {}
+
+  call_string m_key;
+  stats m_stats;
+};
+
+/* Traits class for storing per-call_string data within
+   an exploded_graph.  */
+
+struct eg_call_string_hash_map_traits
+{
+  typedef const call_string *key_type;
+  typedef per_call_string_data *value_type;
+  typedef per_call_string_data *compare_type;
+
+  static inline hashval_t hash (const key_type &k)
+  {
+    gcc_assert (k != NULL);
+    gcc_assert (k != reinterpret_cast<key_type> (1));
+    return k->hash ();
+  }
+  static inline bool equal_keys (const key_type &k1, const key_type &k2)
+  {
+    gcc_assert (k1 != NULL);
+    gcc_assert (k2 != NULL);
+    gcc_assert (k1 != reinterpret_cast<key_type> (1));
+    gcc_assert (k2 != reinterpret_cast<key_type> (1));
+    if (k1 && k2)
+      return *k1 == *k2;
+    else
+      /* Otherwise they must both be non-NULL.  */
+      return k1 == k2;
+  }
+  template <typename T>
+  static inline void remove (T &)
+  {
+    /* empty; the nodes are handled elsewhere.  */
+  }
+  template <typename T>
+  static inline void mark_deleted (T &entry)
+  {
+    entry.m_key = reinterpret_cast<key_type> (1);
+  }
+  template <typename T>
+  static inline void mark_empty (T &entry)
+  {
+    entry.m_key = NULL;
+  }
+  template <typename T>
+  static inline bool is_deleted (const T &entry)
+  {
+    return entry.m_key == reinterpret_cast<key_type> (1);
+  }
+  template <typename T>
+  static inline bool is_empty (const T &entry)
+  {
+    return entry.m_key == NULL;
+  }
+};
+
 /* A to-be-emitted diagnostic stored within diagnostic_manager.  */
 
 class saved_diagnostic
@@ -1365,6 +1431,9 @@ private:
 class exploded_graph : public digraph<eg_traits>, public log_user
 {
 public:
+  typedef hash_map <const call_string *, per_call_string_data *,
+		    eg_call_string_hash_map_traits> call_string_data_map_t;
+
   exploded_graph (const supergraph &sg, logger *logger,
 		  const extrinsic_state &ext_state,
 		  const state_purge_map *purge_map,
@@ -1390,6 +1459,9 @@ public:
   per_program_point_data *
   get_or_create_per_program_point_data (const program_point &);
 
+  per_call_string_data *
+  get_or_create_per_call_string_data (const call_string &);
+
   void save_diagnostic (const state_machine &sm,
 			const exploded_node *enode,
 			const supernode *node, const gimple *stmt,
@@ -1409,6 +1481,9 @@ public:
   void dump_states_for_supernode (FILE *, const supernode *snode) const;
   void dump_exploded_nodes () const;
 
+  const call_string_data_map_t *get_per_call_string_data () const
+  { return &m_per_call_string_data; }
+
 private:
   const supergraph &m_sg;
 
@@ -1420,10 +1495,7 @@ private:
 		    eg_hash_map_traits> map_t;
   map_t m_point_and_state_to_node;
 
-  /* Map from program_point to the first exploded_node at
-     that point.
-     FIXME: generalize
-     FIXME: why?*/
+  /* Map from program_point to per-program_point data.  */
   typedef hash_map <const program_point *, per_program_point_data *,
 		    eg_point_hash_map_traits> point_map_t;
   point_map_t m_per_point_data;
@@ -1443,6 +1515,10 @@ private:
   typedef ordered_hash_map<function *, stats *> function_stat_map_t;
   function_stat_map_t m_per_function_stats;
   stats m_functionless_stats;
+
+  call_string_data_map_t m_per_call_string_data;
+
+
   auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode;
 };
 
@@ -6079,6 +6155,9 @@ exploded_graph::get_or_create_node (const program_point &point,
 
   stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
 
+  stats *per_cs_stats
+    = &get_or_create_per_call_string_data (point.m_call_string)->m_stats;
+
   point_and_state ps (point, pruned_state);
   if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
     {
@@ -6086,6 +6165,7 @@ exploded_graph::get_or_create_node (const program_point &point,
       log ("reused EN: %i", (*slot)->m_index);
       m_global_stats.m_node_reuse_count++;
       per_fn_stats->m_node_reuse_count++;
+      per_cs_stats->m_node_reuse_count++;
       return *slot;
     }
 
@@ -6127,6 +6207,7 @@ exploded_graph::get_or_create_node (const program_point &point,
 		  log ("reused EN: %i", (*slot)->m_index);
 		  m_global_stats.m_node_reuse_after_merge_count++;
 		  per_fn_stats->m_node_reuse_after_merge_count++;
+		  per_cs_stats->m_node_reuse_after_merge_count++;
 		  return *slot;
 		}
 
@@ -6159,6 +6240,7 @@ exploded_graph::get_or_create_node (const program_point &point,
 
   m_global_stats.m_num_nodes[node->get_point ().m_kind]++;
   per_fn_stats->m_num_nodes[node->get_point ().m_kind]++;
+  per_cs_stats->m_num_nodes[node->get_point ().m_kind]++;
 
   if (node->get_point ().m_kind == PK_AFTER_SUPERNODE)
     m_PK_AFTER_SUPERNODE_per_snode[point.get_supernode ()->m_index]++;
@@ -6210,6 +6292,20 @@ get_or_create_per_program_point_data (const program_point &point)
   return per_point_data;
 }
 
+/* FIXME.  */
+
+per_call_string_data *
+exploded_graph::get_or_create_per_call_string_data (const call_string &cs)
+{
+  if (per_call_string_data **slot = m_per_call_string_data.get (&cs))
+    return *slot;
+
+  per_call_string_data *data = new per_call_string_data (cs, m_sg.num_nodes ());
+  m_per_call_string_data.put (&data->m_key,
+			      data);
+  return data;
+}
+
 /* The main loop of the analysis.
    Take freshly-created exploded_nodes from the worklist, calling
    process_node on them to explore the <point, state> graph.
@@ -8051,7 +8147,27 @@ public:
 	  }
 	pp_printf (pp, "enodes: %i\n", num_enodes);
 	pp_newline (pp);
+
 	// TODO: also show the per-callstring breakdown
+	const exploded_graph::call_string_data_map_t *per_cs_data
+	  = args.m_eg->get_per_call_string_data ();
+	for (typename exploded_graph::call_string_data_map_t::iterator iter
+	       = per_cs_data->begin ();
+	     iter != per_cs_data->end ();
+	     ++iter)
+	  {
+	    const call_string *cs = (*iter).first;
+	    //per_call_string_data *data = (*iter).second;
+	    num_enodes = 0;
+	    FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
+	      {
+		if (enode->get_point ().get_function () == m_fun
+		    && enode->get_point ().m_call_string == *cs)
+		  num_enodes++;
+	      }
+	    if (num_enodes > 0)
+	      pp_printf (pp, "%s: %i\n", cs->to_str ().c_str (), num_enodes);
+	  }
       }
 
     pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
-- 
1.8.5.3

