From 11b78f7b99495a538bc376249b5fd56f717a24ff Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 27 Aug 2019 17:57:41 -0400
Subject: [PATCH 103/124] FIXME: start adding an analysis_plan

---
 gcc/analyzer/analyzer-logging.h |   8 +++
 gcc/analyzer/impl-4.cc          | 132 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 131 insertions(+), 9 deletions(-)

diff --git a/gcc/analyzer/analyzer-logging.h b/gcc/analyzer/analyzer-logging.h
index 8f950d9..a4d3dd5 100644
--- a/gcc/analyzer/analyzer-logging.h
+++ b/gcc/analyzer/analyzer-logging.h
@@ -56,6 +56,7 @@ class logger
   void exit_scope (const char *scope_name);
 
   pretty_printer *get_printer () const { return m_pp; }
+  FILE *get_file () const { return m_f_out; }
 
 private:
   int m_refcount;
@@ -168,6 +169,13 @@ class log_user
     return m_logger->get_printer ();
   }
 
+  FILE *get_logger_file () const
+  {
+    if (m_logger == NULL)
+      return NULL;
+    return m_logger->get_file ();
+  }
+
  private:
   logger *m_logger;
 };
diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index be400cb..eabef2e 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -73,6 +73,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "analyzer/pending-diagnostic.h"
 #include "fibonacci_heap.h"
 #include "params.h"
+#include "ipa-utils.h"
 
 /* Overview:
 
@@ -658,6 +659,38 @@ public:
   auto_delete_vec <state_machine> &m_checkers;
 };
 
+////////////////////////////////////////////////////////////////////////////
+
+/* A class to encapsulate decisions about how the analysis should happen.
+   Examples:
+   - the order in which functions should be analyzed, so that function
+     summaries are created before analysis of call sites that might use
+     them
+   - which callgraph edges should use call summaries
+   TODO: the above is a work-in-progress.  */
+
+class analysis_plan : public log_user
+{
+public:
+  analysis_plan (const supergraph &sg, logger *logger);
+  ~analysis_plan ();
+
+  int cmp_function (function *fun_a, function *fun_b) const;
+
+private:
+  const supergraph &m_sg;
+
+  /* Result of ipa_reverse_postorder.  */
+  cgraph_node **m_cgraph_node_postorder;
+  int m_num_cgraph_nodes;
+
+  /* Index of each node within the postorder ordering,
+     accessed via the "m_uid" field.  */
+  auto_vec<int> m_index_by_uid;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
 } // namespace impl_4
 
 using impl_4::pod_hash_traits;
@@ -1368,7 +1401,7 @@ private:
 class worklist
 {
 public:
-  worklist (const exploded_graph &eg);
+  worklist (const exploded_graph &eg, const analysis_plan &plan);
   unsigned length () const;
   exploded_node *take_next ();
   exploded_node *peek_next ();
@@ -1418,6 +1451,7 @@ private:
      calls the ordering fns).  */
   const exploded_graph &m_eg;
   strongly_connected_components m_scc;
+  const analysis_plan &m_plan;
 
   /* Priority queue, backed by a fibonacci_heap.  */
   typedef fibonacci_heap<key_t, exploded_node> queue_t;
@@ -1437,12 +1471,14 @@ public:
   exploded_graph (const supergraph &sg, logger *logger,
 		  const extrinsic_state &ext_state,
 		  const state_purge_map *purge_map,
+		  const analysis_plan &plan,
 		  int verbosity);
   ~exploded_graph ();
 
   const supergraph &get_supergraph () const { return m_sg; }
   const extrinsic_state &get_ext_state () const { return m_ext_state; }
   const state_purge_map *get_purge_map () const { return m_purge_map; }
+  const analysis_plan &get_analysis_plan () const { return m_plan; }
 
   exploded_node *get_origin () const { return m_origin; }
 
@@ -1509,6 +1545,8 @@ private:
 
   const state_purge_map *const m_purge_map;
 
+  const analysis_plan &m_plan;
+
   diagnostic_manager m_diagnostic_manager;
 
   /* Stats.  */
@@ -5934,9 +5972,10 @@ strongly_connected_components::strong_connect (unsigned index)
 
 /* worklist's ctor.  */
 
-worklist::worklist (const exploded_graph &eg)
+worklist::worklist (const exploded_graph &eg, const analysis_plan &plan)
 : m_eg (eg),
   m_scc (eg.get_supergraph (), eg.get_logger ()),
+  m_plan (plan),
   m_queue (key_t (*this, NULL))
 {
 }
@@ -5981,6 +6020,27 @@ worklist::add_node (exploded_node *enode)
 int
 worklist::key_t::cmp_1 (const worklist::key_t &ka, const worklist::key_t &kb)
 {
+  const program_point &point_a = ka.m_enode->get_point ();
+  const program_point &point_b = kb.m_enode->get_point ();
+  const call_string &call_string_a = point_a.m_call_string;
+  const call_string &call_string_b = point_b.m_call_string;
+
+  /* Order empty-callstring points with different functions based on the
+     analysis_plan, so that we generate summaries before they are used.  */
+  /* FIXME: this isn't quite right, in that I'm seeing some uses before
+     creations, but it seems close.  */
+  if (flag_analyzer_call_summaries
+      && call_string_a.empty_p ()
+      && call_string_b.empty_p ()
+      && point_a.get_function () != NULL
+      && point_b.get_function () != NULL
+      && point_a.get_function () != point_b.get_function ())
+    {
+      return ka.m_worklist.m_plan.cmp_function (point_a.get_function (),
+						point_b.get_function ());
+    }
+
+  // FIXME:
   /* First, order by SCC.  */
   int scc_id_a = ka.get_scc_id (ka.m_enode);
   int scc_id_b = kb.get_scc_id (kb.m_enode);
@@ -6011,15 +6071,11 @@ worklist::key_t::cmp_1 (const worklist::key_t &ka, const worklist::key_t &kb)
   gcc_assert (snode_a == snode_b);
 
   /* Order within supernode via program point.  */
-  const program_point &point_a = ka.m_enode->get_point ();
-  const program_point &point_b = kb.m_enode->get_point ();
   int within_snode_cmp = program_point::cmp_within_supernode (point_a, point_b);
   if (within_snode_cmp)
     return within_snode_cmp;
 
   /* The points might vary by callstring; try sorting by callstring.  */
-  const call_string &call_string_a = point_a.m_call_string;
-  const call_string &call_string_b = point_b.m_call_string;
   int cs_cmp = call_string::cmp (call_string_a, call_string_b);
   if (cs_cmp)
     return cs_cmp;
@@ -6082,11 +6138,13 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
 exploded_graph::exploded_graph (const supergraph &sg, logger *logger,
 				const extrinsic_state &ext_state,
 				const state_purge_map *purge_map,
+				const analysis_plan &plan,
 				int verbosity)
 : log_user (logger), m_sg (sg),
-  m_worklist (*this),
+  m_worklist (*this, plan),
   m_ext_state (ext_state),
   m_purge_map (purge_map),
+  m_plan (plan),
   m_diagnostic_manager (logger, verbosity),
   m_global_stats (m_sg.num_nodes ()),
   m_functionless_stats (m_sg.num_nodes ()),
@@ -6792,7 +6850,9 @@ exploded_graph::process_node (exploded_node *node)
 	    if (flag_analyzer_call_summaries
 		&& point.m_call_string.empty_p ())
 	      {
-		// TODO: create function summary
+		/* TODO: create function summary
+		   There can be more than one; each corresponds to a different
+		   final enode in the function.  */
 		log ("would create function summary for %qE",
 		     point.get_function ()->decl);
 	      }
@@ -7951,6 +8011,58 @@ private:
 
 ////////////////////////////////////////////////////////////////////////////
 
+/* class analysis_plan.  */
+
+/* FIXME.  */
+
+analysis_plan::analysis_plan (const supergraph &sg, logger *logger)
+: log_user (logger), m_sg (sg),
+  m_cgraph_node_postorder (XCNEWVEC (struct cgraph_node *,
+				     symtab->cgraph_count)),
+  m_index_by_uid (symtab->cgraph_max_uid)
+{
+  JIT_LOG_SCOPE (logger);
+  m_num_cgraph_nodes = ipa_reverse_postorder (m_cgraph_node_postorder);
+  gcc_assert (m_num_cgraph_nodes == symtab->cgraph_count);
+  if (get_logger_file ())
+    ipa_print_order (get_logger_file (),
+		     "FIXME", m_cgraph_node_postorder,
+		     m_num_cgraph_nodes);
+
+  /* Populate m_index_by_uid.  */
+  for (int i = 0; i < symtab->cgraph_max_uid; i++)
+    m_index_by_uid.quick_push (-1);
+  for (int i = 0; i < m_num_cgraph_nodes; i++)
+    {
+      gcc_assert (m_cgraph_node_postorder[i]->get_uid ()
+		  < symtab->cgraph_max_uid);
+      m_index_by_uid[m_cgraph_node_postorder[i]->get_uid ()] = i;
+    }
+}
+
+/* FIXME.  */
+
+analysis_plan::~analysis_plan ()
+{
+  free (m_cgraph_node_postorder);
+}
+
+/* FIXME.  */
+
+int
+analysis_plan::cmp_function (function *fun_a, function *fun_b) const
+{
+  cgraph_node *node_a = cgraph_node::get (fun_a->decl);
+  cgraph_node *node_b = cgraph_node::get (fun_b->decl);
+
+  int idx_a = m_index_by_uid[node_a->get_uid ()];
+  int idx_b = m_index_by_uid[node_b->get_uid ()];
+
+  return idx_b - idx_a; // FIXME
+}
+
+////////////////////////////////////////////////////////////////////////////
+
 #if 0
 /* FIXME.  */
 
@@ -8466,8 +8578,10 @@ impl_run_checkers (logger *logger)
   /* Extrinsic state shared by nodes in the graph.  */
   const extrinsic_state ext_state (checkers);
 
+  const analysis_plan plan (sg, logger);
+
   /* The exploded graph.  */
-  impl_4::exploded_graph eg (sg, logger, ext_state, purge_map,
+  impl_4::exploded_graph eg (sg, logger, ext_state, purge_map, plan,
 			     analyzer_verbosity);
 
   /* Add entrypoints to the graph for externally-callable functions.  */
-- 
1.8.5.3

