From edb05c13f3734064f189144ae44a56efa95d2ecb Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 9 May 2019 14:41:35 -0400
Subject: [PATCH 26/66] FIXME: ensure that we can't have empty ECs

---
 gcc/analyzer/constraints.cc | 102 ++++++++++++++++++++++++--------------------
 gcc/analyzer/constraints.h  |   2 -
 gcc/analyzer/impl-4.cc      |  15 +++++++
 3 files changed, 71 insertions(+), 48 deletions(-)

diff --git a/gcc/analyzer/constraints.cc b/gcc/analyzer/constraints.cc
index 3f2738f..c4b1f41 100644
--- a/gcc/analyzer/constraints.cc
+++ b/gcc/analyzer/constraints.cc
@@ -41,6 +41,22 @@
 #include "constraints.h"
 #include "supergraph.h"
 
+/* A subclass of purge_criteria: purge a specific path_var.  */
+
+class purge_one_path_var : public purge_criteria
+{
+public:
+  purge_one_path_var (path_var victim) : m_victim (victim) {}
+
+  bool should_purge_p (path_var pv) const FINAL OVERRIDE
+  {
+    return pv == m_victim;
+  }
+
+private:
+  path_var m_victim;
+};
+
 /* FIXME.  */
 
 std::string
@@ -220,18 +236,6 @@ equiv_class::get_min_stack_depth () const
   return result;
 }
 
-/* FIXME.  */
-
-void
-equiv_class::purge_stack_frame (int callee_stack_depth)
-{
-  unsigned ix, ix2;
-  path_var *iv;
-  VEC_ORDERED_REMOVE_IF (m_vars, ix, ix2, iv,
-			 iv->m_stack_depth >= callee_stack_depth);
-  // FIXME: doesn't need to preserve order
-}
-
 /* Get a representative member of this class, for handling cases
    where the IDs can change mid-traversal.  */
 
@@ -475,13 +479,8 @@ void
 path_state::on_assignment (path_var lhs, path_var rhs)
 {
   /* Clear LHS.  */
-  {
-    equiv_class_id lhs_ec_id (-1);
-    if (get_equiv_class (lhs, &lhs_ec_id))
-      {
-	lhs_ec_id.get_obj (*this).del (lhs); // TODO
-      }
-  }
+  purge_one_path_var p (lhs);
+  purge (p);
 
   add_constraint (lhs, EQ_EXPR, rhs);
 }
@@ -551,25 +550,36 @@ path_state::apply_constraints_for_return (const return_superedge&)
   return true;
 }
 
+/* A subclass of purge_criteria: purge anything above a given stack depth.  */
+
+class purge_above_stack_frame : public purge_criteria
+{
+public:
+  purge_above_stack_frame (int max_stack_depth)
+  : m_max_stack_depth (max_stack_depth) {}
+
+  bool should_purge_p (path_var pv) const FINAL OVERRIDE
+  {
+    return pv.m_stack_depth > m_max_stack_depth;
+  }
+
+private:
+  int m_max_stack_depth;
+};
+
+
 /* Decrement the stack depth, purging vars at the old stack depth (and beyond).
    This is broken out as a subroutine so it can be unit-tested.  */
 
 void
 path_state::pop_stack_frame ()
 {
-  int callee_stack_depth = m_stack_depth--;
+  int caller_stack_depth = --m_stack_depth;
 
-  int i;
-  equiv_class *ec;
-  FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
-    {
-      ec->purge_stack_frame (callee_stack_depth);
-      /* This can lead to empty equiv classes (possibly without
-	 constants).  Perhaps we ought to purge them?  */
-    }
+  purge_above_stack_frame p (caller_stack_depth);
+  purge (p);
 }
 
-
 /* FIXME.  */
 
 bool
@@ -1336,6 +1346,8 @@ path_state::validate () const
 	}
       if (ec->m_constant)
 	gcc_assert (CONSTANT_CLASS_P (ec->m_constant));
+      else
+	gcc_assert (ec->m_vars.length () > 0);
     }
 
   constraint *c;
@@ -2039,7 +2051,21 @@ test_constraint_impl ()
 static void
 test_assignment ()
 {
-  // TODO
+  path_var int_0 (build_int_cst (integer_type_node, 0), 0);
+
+  path_var x (build_decl (UNKNOWN_LOCATION, PARM_DECL,
+			  get_identifier ("x"),
+			  integer_type_node), 0);
+  path_var y (build_decl (UNKNOWN_LOCATION, PARM_DECL,
+			  get_identifier ("y"),
+			  integer_type_node), 0);
+  /* "x == 0", then use of y, then "y = 0".  */
+  path_state ps;
+  ADD_SAT_CONSTRAINT (ps, x, EQ_EXPR, int_0);
+  ASSERT_CONDITION_UNKNOWN (ps, y, EQ_EXPR, int_0);
+  ps.on_assignment (y, int_0);
+  ASSERT_CONDITION_TRUE (ps, y, EQ_EXPR, int_0);
+  ASSERT_CONDITION_TRUE (ps, y, EQ_EXPR, x);
 }
 
 /* FIXME.  */
@@ -2111,22 +2137,6 @@ test_equality ()
   }
 }
 
-/* A subclass of purge_criteria for selftests: purge a specific path_var.  */
-
-class purge_one_path_var : public purge_criteria
-{
-public:
-  purge_one_path_var (path_var victim) : m_victim (victim) {}
-
-  bool should_purge_p (path_var pv) const FINAL OVERRIDE
-  {
-    return pv == m_victim;
-  }
-
-private:
-  path_var m_victim;
-};
-
 /* A subclass of purge_criteria for selftests: purge all path_var instances.  */
 
 class purge_all_path_vars : public purge_criteria
diff --git a/gcc/analyzer/constraints.h b/gcc/analyzer/constraints.h
index 9ab7f93..d6abfd8 100644
--- a/gcc/analyzer/constraints.h
+++ b/gcc/analyzer/constraints.h
@@ -122,8 +122,6 @@ public:
 
   int get_min_stack_depth () const;
 
-  void purge_stack_frame (int callee_stack_depth);
-
   path_var get_representative () const;
 
   /* An equivalence class can contain at most one constant.  */
diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index f78b0bf..37e4658 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -678,6 +678,8 @@ public:
 		const exploded_node &enode,
 		const superedge *succ);
 
+  void validate () const;
+
   //private:
   path_state m_path_state;
 
@@ -2209,6 +2211,15 @@ program_state::prune_for_point (const exploded_graph &eg,
 
 }
 
+/* FIXME.  */
+
+void
+program_state::validate () const
+{
+  m_path_state.validate ();
+}
+
+
 ////////////////////////////////////////////////////////////////////////////
 
 /* FIXME.  */
@@ -3109,6 +3120,8 @@ exploded_graph::get_or_create_node (const program_point &point,
 
   auto_cfun sentinel (point.get_function ());
 
+  state.validate ();
+
   /* Prune state to try to improve the chances of a cache hit,
      avoiding generating redundant nodes.  */
   program_state pruned_state = state.prune_for_point (*this, point);
@@ -3203,6 +3216,8 @@ exploded_graph::process_node (exploded_node *node)
 {
   JIT_LOG_FUNC_1 (get_logger (), "EN: %i", node->m_index);
 
+  auto_cfun sentinel (node->get_function ());
+
   const program_point &point = node->get_point ();
   const program_state &state = node->get_state ();
   if (get_logger ())
-- 
1.8.5.3

