From 1ca6b7987513cff74f4bbb644e1732c2c2906ee6 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 28 Aug 2019 20:12:09 -0400
Subject: [PATCH 110/124] FIXME: implement simplistic prototype of call
 summaries

---
 gcc/analyzer/impl-4.cc                             | 26 +++++++++++++---------
 gcc/analyzer/region-model.cc                       | 23 +++++++++++++++++++
 gcc/analyzer/region-model.h                        |  2 ++
 gcc/analyzer/supergraph.cc                         |  3 +++
 gcc/analyzer/supergraph.h                          | 10 +++++++++
 gcc/params.def                                     |  5 +++++
 .../analyzer/NOT_FOR_UPSTREAM-zlib-1.1.3-gzio.c    |  2 +-
 gcc/testsuite/gcc.dg/analyzer/call-summaries-1.c   |  3 +--
 8 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 1677ba3..17197c7 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -3967,15 +3967,6 @@ program_state::on_edge (exploded_graph &eg,
 			const superedge *succ)
 {
   /* Update state.  */
-
-  if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL)
-    {
-      // TODO: handle call summary!
-      /* We ignore these edges.  FIXME: why have them?  */
-      eg.log ("rejecting interprocedural edge");
-      return false;
-    }
-
   const program_point &point = enode.get_point ();
   const gimple *last_stmt = point.m_supernode->get_last_stmt ();
 
@@ -5482,7 +5473,16 @@ diagnostic_manager::add_events_for_superedge (const exploded_edge &eedge,
       break;
 
     case SUPEREDGE_INTRAPROCEDURAL_CALL:
-      gcc_unreachable ();
+      {
+	// FIXME:
+	emission_path->add_event
+	  (new debug_event ((last_stmt
+			     ? last_stmt->location
+			     : UNKNOWN_LOCATION),
+			    src_point.m_supernode->m_fun->decl,
+			    src_stack_depth,
+			    "call summary"));
+      }
       break;
 
     case SUPEREDGE_RETURN:
@@ -8150,6 +8150,12 @@ analysis_plan::use_summary_p (const cgraph_edge *edge) const
   if (num_call_sites <= 1)
     return false;
 
+  /* Require the callee to be sufficiently complex to be worth
+     summarizing.  */
+  if ((int)m_sg.get_num_snodes (callee->get_fun ())
+      < PARAM_VALUE (PARAM_ANALYZER_MIN_SNODES_FOR_CALL_SUMMARY))
+    return false;
+
   return true; // TODO
 }
 
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 9562b6f..a1aa8ab 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -4382,6 +4382,14 @@ region_model::maybe_update_for_edge (const superedge &edge,
 	update_for_return_superedge (*return_edge, ctxt);
       }
       break;
+
+    case SUPEREDGE_INTRAPROCEDURAL_CALL:
+      {
+	const callgraph_superedge &cg_sedge = (const callgraph_superedge &)edge;
+	// FIXME: should be an as_a
+	update_for_call_summary (cg_sedge, ctxt);
+      }
+      break;
     }
 
   // TODO: update constraints
@@ -4465,6 +4473,21 @@ region_model::update_for_return_superedge (const return_superedge &return_edge,
     }
 }
 
+/* FIXME.  */
+
+void
+region_model::update_for_call_summary (const callgraph_superedge &cg_sedge,
+				       region_model_context *ctxt)
+{
+  /* For now, set any return value to "unknown".  */
+  gcall *call_stmt = cg_sedge.get_call_stmt ();
+  tree lhs = gimple_call_lhs (call_stmt);
+  if (lhs)
+    set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs));
+
+  // TODO: actually implement some kind of summary here
+}
+
 /* Given a true or false edge guarded by conditional statement COND_STMT,
    determine appropriate constraints for the edge to be taken.
 
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 37c06c5..36ad1b0 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -1259,6 +1259,8 @@ class region_model
 				  region_model_context *ctxt);
   void update_for_return_superedge (const return_superedge &return_edge,
 				    region_model_context *ctxt);
+  void update_for_call_summary (const callgraph_superedge &cg_sedge,
+				region_model_context *ctxt);
   bool apply_constraints_for_gcond (const cfg_superedge &edge,
 				    const gcond *cond_stmt,
 				    region_model_context *ctxt);
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index b6ef813..18fd055 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -133,6 +133,9 @@ supergraph::supergraph (logger *logger)
 	  m_bb_to_final_node.put (bb, node_for_stmts);
 	}
 
+      const unsigned num_snodes = m_nodes.length () - start_idx;
+      m_function_to_num_snodes.put (fun, num_snodes);
+
       if (logger)
 	{
 	  const int end_idx = m_nodes.length () - 1;
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index 8ab8f22..e1ff49f 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -168,6 +168,13 @@ public:
     return m_nodes[idx];
   }
 
+  unsigned get_num_snodes (function *fun) const
+  {
+    function_to_num_snodes_t &map
+      = const_cast <function_to_num_snodes_t &>(m_function_to_num_snodes);
+    return *map.get (fun);
+  }
+
 private:
   supernode *add_node (function *fun, basic_block bb, gcall *returning_call,
 		       gimple_seq phi_nodes);
@@ -201,6 +208,9 @@ private:
 
   typedef ordered_hash_map<gimple *, supernode *> stmt_to_node_t;
   stmt_to_node_t m_stmt_to_node_t;
+
+  typedef hash_map<function *, unsigned> function_to_num_snodes_t;
+  function_to_num_snodes_t m_function_to_num_snodes;
 };
 
 /* A node within a supergraph.  */
diff --git a/gcc/params.def b/gcc/params.def
index 68c015c..e2a5ad8 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1461,6 +1461,11 @@ DEFPARAM(PARAM_ANALYZER_MAX_ENODES_PER_PROGRAM_POINT,
 	 "FIXME.",
 	 8, 1, 0)
 
+DEFPARAM(PARAM_ANALYZER_MIN_SNODES_FOR_CALL_SUMMARY,
+	 "analyzer-min-snodes-for-call-summary",
+	 "FIXME.",
+	 10, 1, 0)
+
 /*
 
 Local variables:
diff --git a/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-zlib-1.1.3-gzio.c b/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-zlib-1.1.3-gzio.c
index 61d6de1..d0dcfcf 100644
--- a/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-zlib-1.1.3-gzio.c
+++ b/gcc/testsuite/gcc.dg/analyzer/NOT_FOR_UPSTREAM-zlib-1.1.3-gzio.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-O3 -Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-O3 -Wno-analyzer-too-complex -fanalyzer-call-summaries" } */
 
 typedef long unsigned int size_t;
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-1.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-1.c
index 9f6c85e..c00f993 100644
--- a/gcc/testsuite/gcc.dg/analyzer/call-summaries-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-1.c
@@ -4,8 +4,7 @@
 
 void calls_free (void *p)
 {
-  free (p); /* { dg-warning "double-free of 'p'" "" { xfail *-*-*} } */
-  /* TODO: make this pass with call summaries.  */
+  free (p); /* { dg-warning "double-free of 'p'" } */
 }
 
 void test (void *q)
-- 
1.8.5.3

