From 93ad0b69351a78610c07ed39e3ba9dc9782fd171 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 26 Apr 2019 19:19:55 -0400
Subject: [PATCH 205/217] FIXME: start adding path_state to program_state

---
 gcc/analyzer/constraints.cc |  21 ++++++++
 gcc/analyzer/constraints.h  |   2 +
 gcc/analyzer/impl-4.cc      | 118 ++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 138 insertions(+), 3 deletions(-)

diff --git a/gcc/analyzer/constraints.cc b/gcc/analyzer/constraints.cc
index 5750c17..cad4dab 100644
--- a/gcc/analyzer/constraints.cc
+++ b/gcc/analyzer/constraints.cc
@@ -305,6 +305,27 @@ path_state::~path_state ()
 
 /* FIXME.  */
 
+path_state&
+path_state::operator= (const path_state &other)
+{
+  m_stack_depth = other.m_stack_depth;
+
+  gcc_assert (m_equiv_classes.length () == 0);
+  gcc_assert (m_constraints.length () == 0);
+
+  int i;
+  equiv_class *ec;
+  FOR_EACH_VEC_ELT (other.m_equiv_classes, i, ec)
+    m_equiv_classes.safe_push (new equiv_class (*ec));
+  constraint *c;
+  FOR_EACH_VEC_ELT (other.m_constraints, i, c)
+    m_constraints.safe_push (*c);
+
+  return *this;
+}
+
+/* FIXME.  */
+
 std::string
 path_state::to_str () const
 {
diff --git a/gcc/analyzer/constraints.h b/gcc/analyzer/constraints.h
index b8ef4ed..2d114c3 100644
--- a/gcc/analyzer/constraints.h
+++ b/gcc/analyzer/constraints.h
@@ -189,6 +189,8 @@ public:
   path_state (const path_state &other);
   ~path_state ();
 
+  path_state& operator= (const path_state &other);
+
   std::string to_str () const;
 
   const equiv_class &get_equiv_class_by_index (unsigned idx) const
diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index c369764..1c0c6a0 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -302,7 +302,7 @@ public:
 	      pretty_printer *pp) const;
   std::string to_str (const extrinsic_state &ext_state) const;
 
-#if 0
+#if 1
   path_state m_path_state;
 #endif
 
@@ -1162,6 +1162,7 @@ public:
 ////////////////////////////////////////////////////////////////////////////
 
 program_state::program_state (const extrinsic_state &ext_state)
+: m_path_state ()
 {
   int num_states = ext_state.m_checkers.length ();
   for (int i = 0; i < num_states; i++)
@@ -1169,12 +1170,14 @@ program_state::program_state (const extrinsic_state &ext_state)
 }
 
 program_state::program_state (int num_states)
+: m_path_state ()
 {
   for (int i = 0; i < num_states; i++)
     m_checker_states.safe_push (new sm_state_map ());
 }
 
 program_state::program_state (const program_state &other)
+: m_path_state (other.m_path_state)
 {
   int i;
   sm_state_map *smap;
@@ -1185,6 +1188,8 @@ program_state::program_state (const program_state &other)
 program_state&
 program_state::operator= (const program_state &other)
 {
+  m_path_state = other.m_path_state;
+
   // TODO: eliminate existing things
   gcc_assert (m_checker_states.length () == 0);
 
@@ -1198,6 +1203,9 @@ void
 program_state::print (const extrinsic_state &ext_state,
 		      pretty_printer *pp) const
 {
+  pp_printf (pp, "ps: %s", m_path_state.to_str ().c_str ());
+  pp_newline (pp);
+
   int i;
   sm_state_map *smap;
   FOR_EACH_VEC_ELT (m_checker_states, i, smap)
@@ -1355,8 +1363,12 @@ exploded_node::on_stmt (const exploded_graph &eg) const
 {
   const program_point &point = m_ps.m_point;
   const program_state &old_state = m_ps.m_state;
+  const path_state &old_ps = old_state.m_path_state;
 
   program_state new_state (old_state);
+  path_state &new_ps = new_state.m_path_state;
+
+  const gimple *stmt = point.get_stmt ();
 
   int i;
   sm_state_map *smap;
@@ -1366,9 +1378,109 @@ exploded_node::on_stmt (const exploded_graph &eg) const
       impl_sm_context ctxt (eg, sm, this,
 			    *old_state.m_checker_states[i],
 			    new_state.m_checker_states[i]);
-      sm.on_stmt (&ctxt, point.m_supernode, point.get_stmt ());
+      sm.on_stmt (&ctxt, point.m_supernode, stmt);
+    }
+
+  if (const gassign *assign = dyn_cast <const gassign *> (stmt))
+    {
+      tree lhs = gimple_assign_lhs (assign);
+      tree rhs1 = gimple_assign_rhs1 (assign);
+      enum tree_code op = gimple_assign_rhs_code (assign);
+      switch (op)
+	{
+	default:
+	  break;
+
+	case NOP_EXPR:
+	case SSA_NAME:
+	case INTEGER_CST:
+	  {
+#if 0
+	    /* Direct assignment of the form LHS = RHS;  */
+	    on_assignment (node, assign, sm_inst, old_sm_inst,
+			   ps->make_path_var (lhs),
+			   ps->make_path_var (rhs1),
+			   b, ps);
+#endif
+	  }
+	  break;
+
+	case EQ_EXPR:
+	case NE_EXPR:
+	case GE_EXPR:
+	case LE_EXPR:
+	case GT_EXPR:
+	case LT_EXPR:
+	  {
+	    /* If we see a comparison, evaluate it based on what we know along
+	       this path, and record the result, if known.  */
+#if 1
+	    tree rhs2 = gimple_assign_rhs2 (assign);
+	    // FIXME: stack depths:
+	    equiv_class_id rhs1_ec_id
+	      = new_ps.get_or_add_equiv_class (path_var (rhs1, 0));
+	    equiv_class_id rhs2_ec_id
+	      = new_ps.get_or_add_equiv_class (path_var (rhs2, 0));
+	    tristate t = new_ps.eval_condition (rhs1_ec_id, op, rhs2_ec_id);
+	    if (eg.get_logger ())
+	      eg.log ("eval condition: %s", t.as_string ());
+	    if (t.is_known ())
+	      // FIXME: stack depth:
+	      new_ps.add_constraint (path_var (lhs, 0),
+				     t.is_true () ? NE_EXPR : EQ_EXPR,
+				     path_var (integer_zero_node, 0));
+#endif
+	  }
+	  break;
+
+	case COMPONENT_REF:
+#if 0
+	  // TODO: propagate state
+	  {
+	    /* Copy the state of RHS to LHS.  */
+	    for (set_of_vars::iterator iter = old_sm_inst->m_active_vars.begin ();
+		 iter != old_sm_inst->m_active_vars.end ();
+		 ++iter)
+	      {
+		if ((*iter).m_var == TREE_OPERAND (rhs1, 0))
+		  {
+		    log ("got match for COMPONENT_REF");
+		    engine_sm_context ctxt (this, b, sm_inst, old_sm_inst,
+					    path, ps);
+		    // FIXME: we want to overwrite any old states
+		    // (but respect the gstate, I think):
+		    ctxt.on_transition (node, stmt, lhs, 0/* FIXME */,
+					(*iter).m_state, (*iter).m_var);
+		  }
+	      }
+	  }
+#endif
+	  break;
+	}
     }
 
+
+  if (const gcall *call = dyn_cast <const gcall *> (stmt))
+    {
+      /* Debugging/test support.  */
+      if (is_named_call_p (call, "__dump_constraints", 0))
+	inform (stmt->location, "__dump_constraints: %s",
+		new_ps.to_str ().c_str ());
+
+      /* Handle the builtin "__analyzer_eval" by evaluating the input
+	 and dumping as a dummy warning, so that test cases can use dg-warning
+	 to validate the result (and so unexpected warnings will lead to DejaGnu
+	 failures.  */
+      if (is_named_call_p (call, "__analyzer_eval", 1))
+	{
+	  tree t_arg = gimple_call_arg (call, 0);
+	  tristate t
+	    = new_ps.dump_condition (t_arg, NE_EXPR, integer_zero_node);
+	  warning_at (call->location, 0, "%s", t.as_string ());
+	}
+    }
+
+
   return new_state;
 }
 
@@ -1631,7 +1743,7 @@ exploded_graph::process_node (exploded_node *node)
 
 	    // TODO: what about state transitions on edges?
 	    program_state next_state = node->on_edge (*this, succ);
-#if 0
+#if 1
 	   /* For conditionals and switch statements, add the
 	      relevant conditions (for the specific edge) to new_state;
 	      skip edges for which the resulting constraints
-- 
1.8.5.3

