From a8d2bd1799b14133d1b4c00af3877b367c0cb4d8 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 27 Aug 2019 10:41:20 -0400
Subject: [PATCH 102/124] FIXME: start adding call summaries

---
 gcc/analyzer/impl-4.cc | 121 ++++++++++++++++++++++++++++++++++++++++---------
 gcc/common.opt         |   4 ++
 2 files changed, 103 insertions(+), 22 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index e407f58..be400cb 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -1446,8 +1446,9 @@ public:
 
   exploded_node *get_origin () const { return m_origin; }
 
-  void add_function_entry (function *fun);
+  exploded_node *add_function_entry (function *fun);
 
+  void build_initial_worklist ();
   void process_worklist ();
   void process_node (exploded_node *node);
 
@@ -2730,9 +2731,21 @@ program_point::on_edge (exploded_graph &eg,
       break;
 
     case SUPEREDGE_INTRAPROCEDURAL_CALL:
-      /* We ignore these edges.  FIXME: why have them?  */
-      eg.log ("rejecting interprocedural edge");
-      return false;
+      {
+	if (flag_analyzer_call_summaries)
+	  {
+	    const callgraph_superedge *cg_sedge
+	      = (const callgraph_superedge *)succ;
+	    eg.log ("would use function summary for %qE in %qE",
+		    cg_sedge->get_callee_decl (),
+		    cg_sedge->get_caller_decl ());
+	  }
+
+	/* We ignore these edges.  FIXME: why have them?  */
+	eg.log ("rejecting interprocedural edge");
+
+	return false;
+      }
     }
 
   return true;
@@ -6105,16 +6118,22 @@ exploded_graph::~exploded_graph ()
    FUN, adding it to the worklist if creating it.
 
    Add an edge from the origin exploded_node to the function entrypoint
-   exploded_node.  */
+   exploded_node.
 
-void
+   Return the exploded_node for the entrypoint to the function.  */
+
+exploded_node *
 exploded_graph::add_function_entry (function *fun)
 {
   program_point point = program_point::from_function_entry (m_sg, fun);
   program_state state (m_ext_state);
   state.m_region_model->push_frame (fun, NULL);
 
-  add_edge (m_origin, get_or_create_node (point, state), NULL);
+  exploded_node *enode = get_or_create_node (point, state);
+  /* We should never fail to add such a node.  */
+  gcc_assert (enode);
+  add_edge (m_origin, enode, NULL);
+  return enode;
 }
 
 /* Get or create an exploded_node for (POINT, STATE).
@@ -6306,6 +6325,66 @@ exploded_graph::get_or_create_per_call_string_data (const call_string &cs)
   return data;
 }
 
+/* Return true if NODE and FUN should be traversed directly, rather than
+   called via other functions.  */
+
+static bool
+toplevel_function_p (cgraph_node *node, function *fun, logger *logger)
+{
+  /* FIXME: better logic here
+     e.g. only if more than one caller, and significantly complicated.
+     Perhaps some whole-callgraph analysis to decide if it's worth summarizing
+     an edge, and if so, we need summaries.  */
+  if (flag_analyzer_call_summaries)
+    {
+      int num_callers = 0;
+      for (cgraph_edge *edge = node->callers; edge; edge = edge->next_caller)
+	++num_callers;
+
+      /* FIXME: For now, if there's more than one in-edge, and we want
+	 call summaries, do it at the top level so that there's a chance
+	 we'll have a summary when we need one.  */
+      if (num_callers > 1)
+	{
+	  if (logger)
+	    logger->log ("traversing %qE (%i callers)", fun->decl, num_callers);
+	  return true;
+	}
+    }
+
+  if (!TREE_PUBLIC (fun->decl))
+    {
+      if (logger)
+	logger->log ("not traversing %qE (static)", fun->decl);
+      return false;
+    }
+
+  if (logger)
+    logger->log ("traversing %qE (all checks passed)", fun->decl);
+
+  return true;
+}
+
+/* Add initial nodes to EG, with entrypoints for externally-callable
+   functions.  */
+
+void
+exploded_graph::build_initial_worklist ()
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  cgraph_node *node;
+  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+  {
+    function *fun = node->get_fun ();
+    if (!toplevel_function_p (node, fun, get_logger ()))
+      continue;
+    exploded_node *enode = add_function_entry (fun);
+    if (get_logger ())
+      log ("created EN %i for %qE entrypoint", enode->m_index, fun->decl);
+  }
+}
+
 /* 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.
@@ -6705,10 +6784,19 @@ exploded_graph::process_node (exploded_node *node)
       break;
     case PK_AFTER_SUPERNODE:
       {
-	/* If this is an EXIT BB, detect leaks.  */
+	/* If this is an EXIT BB, detect leaks, and potentially
+	   create a function summary.  */
 	if (point.m_supernode->return_p ())
-	  node->detect_leaks (*this);
-
+	  {
+	    node->detect_leaks (*this);
+	    if (flag_analyzer_call_summaries
+		&& point.m_call_string.empty_p ())
+	      {
+		// TODO: create function summary
+		log ("would create function summary for %qE",
+		     point.get_function ()->decl);
+	      }
+	  }
 	/* Traverse into successors of the supernode.  */
 	int i;
 	superedge *succ;
@@ -8383,18 +8471,7 @@ impl_run_checkers (logger *logger)
 			     analyzer_verbosity);
 
   /* Add entrypoints to the graph for externally-callable functions.  */
-  cgraph_node *node;
-  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
-  {
-    function *fun = node->get_fun ();
-    if (!TREE_PUBLIC (fun->decl))
-      {
-	if (logger)
-	  logger->log ("not traversing %qE (static)", fun->decl);
-	continue;
-      }
-    eg.add_function_entry (fun);
-  }
+  eg.build_initial_worklist ();
 
   /* Now process the worklist, exploring the <point, state> graph.  */
   eg.process_worklist ();
diff --git a/gcc/common.opt b/gcc/common.opt
index 8c20f69..6dde0c2 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1080,6 +1080,10 @@ fanalyzer-state-merge
 Common Var(flag_analyzer_state_merge) Init(1)
 FIXME: merge similar-enough states during analysis (TODO: docs)
 
+fanalyzer-call-summaries
+Common Var(flag_analyzer_call_summaries) Init(0)
+FIXME: approximate the effect of function calls to simplify analysis (TODO: docs)
+
 fargument-alias
 Common Ignore
 Does nothing. Preserved for backward compatibility.
-- 
1.8.5.3

