From fea6a0fcc20f9fe113da9adbc229e93f082fc32a Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 1 Aug 2019 14:28:46 -0400
Subject: [PATCH 62/96] FIXME: initial implementation of coarse-grained enodes

---
 gcc/analyzer/impl-4.cc                   | 68 +++++++++++++++++++++++++-------
 gcc/common.opt                           |  4 ++
 gcc/testsuite/gcc.dg/analyzer/malloc-1.c |  2 +
 3 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 36f325b..35a6576 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -108,6 +108,7 @@ along with GCC; see the file COPYING3.  If not see
    then we can detect a double-free of "ptr".  We can then emit a path
    to reach the problem by finding the simplest route through the graph.
 
+FIXME:
    Points in the exploded graph are much more fine-grained than in the
    CFG and supergraph, with points (and thus nodes) for various events,
    including both before and after points for individual statements.
@@ -954,7 +955,7 @@ class exploded_node : public dnode<eg_traits>
   void dump (FILE *fp) const;
   void dump () const;
 
-  void on_stmt (exploded_graph &eg,
+  bool on_stmt (exploded_graph &eg,
 		const supernode *snode,
 		const gimple *stmt,
 		program_state *state) const;
@@ -4375,9 +4376,10 @@ fndecl_has_gimple_body_p (tree fndecl)
 }
 
 /* Modify STATE in place, applying the effects of the stmt at this node's
-   point.  */
+   point.
+   Return true if there were any sm-state changes.  */
 
-void
+bool
 exploded_node::on_stmt (exploded_graph &eg,
 			const supernode *snode,
 			const gimple *stmt,
@@ -4444,6 +4446,7 @@ exploded_node::on_stmt (exploded_graph &eg,
       state->m_region_model->on_call (call, &ctxt);
     }
 
+  bool any_sm_changes = false;
   int sm_idx;
   sm_state_map *smap;
   FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
@@ -4468,7 +4471,10 @@ exploded_node::on_stmt (exploded_graph &eg,
 						    state->m_region_model);
 	    }
 	}
+      if (*old_smap != *new_smap)
+	any_sm_changes = true;
     }
+  return any_sm_changes;
 }
 
 /* Consider the effect of following superedge SUCC from this node.
@@ -6373,17 +6379,51 @@ exploded_graph::process_node (exploded_node *node)
       break;
     case PK_BEFORE_STMT:
       {
-	unsigned next_idx = point.m_stmt_idx + 1;
-	program_point next_point
-	  = (next_idx < point.m_supernode->m_stmts.length ()
-	     ? program_point::before_stmt (point.m_supernode, next_idx,
-					   point.m_call_string)
-	     : program_point::after_supernode (point.m_supernode,
-					       point.m_call_string));
-	program_state next_state (state);
-	node->on_stmt (*this, point.m_supernode, stmt, &next_state);
-	exploded_node *next = get_or_create_node (next_point, next_state);
-	add_edge (node, next, NULL);
+	if (flag_analyzer_fine_grained)
+	  {
+	    /* One exploded_node per stmt.  */
+	    unsigned next_idx = point.m_stmt_idx + 1;
+	    program_point next_point
+	      = (next_idx < point.m_supernode->m_stmts.length ()
+		 ? program_point::before_stmt (point.m_supernode, next_idx,
+					       point.m_call_string)
+		 : program_point::after_supernode (point.m_supernode,
+						   point.m_call_string));
+	    program_state next_state (state);
+	    node->on_stmt (*this, point.m_supernode, stmt, &next_state);
+	    exploded_node *next = get_or_create_node (next_point, next_state);
+	    add_edge (node, next, NULL);
+	  }
+	else
+	  {
+	    /* Generate an enode for the end of the current snode,
+	       combining the effect all remaining stmts within the snode,
+	       updating next_state in place.  */
+	    // FIXME: but stop if there's an sm-state change
+	    program_state next_state (state);
+	    const supernode *snode = point.m_supernode;
+	    unsigned stmt_idx;
+	    for (stmt_idx = point.m_stmt_idx;
+		 stmt_idx < snode->m_stmts.length ();
+		 stmt_idx++)
+	      {
+		const gimple *stmt = snode->m_stmts[stmt_idx];
+		bool any_sm_changes
+		  = node->on_stmt (*this, snode, stmt, &next_state);
+		if (any_sm_changes)
+		  break;
+	      }
+	    unsigned next_idx = stmt_idx + 1;
+	    program_point next_point
+	      = (next_idx < point.m_supernode->m_stmts.length ()
+		 ? program_point::before_stmt (point.m_supernode, next_idx,
+					       point.m_call_string)
+		 : program_point::after_supernode (point.m_supernode,
+						   point.m_call_string));
+	    exploded_node *next = get_or_create_node (next_point,
+						      next_state);
+	    add_edge (node, next, NULL);
+	  }
       }
       break;
     case PK_AFTER_SUPERNODE:
diff --git a/gcc/common.opt b/gcc/common.opt
index b2b15eb..cd7bf42 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1056,6 +1056,10 @@ fanalyzer-checker=
 Common Joined RejectNegative Var(flag_analyzer_checker)
 Restrict the analyzer to run just the named checker (TODO: docs)
 
+fanalyzer-fine-grained
+Common Var(flag_analyzer_fine_grained) Init(1)
+FIXME
+
 fanalyzer-impl=
 Common Joined RejectNegative UInteger Var(flag_analyzer_impl)
 FIXME: for selecting older implementations of the analyzer, to be removed
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
index e50496d..616d079 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-1.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-fine-grained" } */
+
 #include <stdlib.h>
 #include <string.h>
 
-- 
1.8.5.3

