From a2a717a7524f13cdf3ce8fbbcf2f366e0af5a1b0 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 20 Feb 2020 16:27:15 -0500
Subject: [PATCH 31/31] FIXME: purge redundant unknown values that have
 constraints on them

---
 gcc/analyzer/constraint-manager.h |  4 ++
 gcc/analyzer/region-model.cc      | 62 ++++++++++++++++++++++++++++---
 2 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h
index a4d179dcdcf..86eec731333 100644
--- a/gcc/analyzer/constraint-manager.h
+++ b/gcc/analyzer/constraint-manager.h
@@ -60,6 +60,8 @@ public:
 
   void print (pretty_printer *pp) const;
 
+  void on_purge (const purge &p);
+
   /* An equivalence class can contain multiple constants (e.g. multiple
      different zeroes, for different types); these are just for the last
      constant added.  */
@@ -231,6 +233,8 @@ public:
 
   void purge (const purge_criteria &p, purge_stats *stats);
 
+  void on_purge (const ana::purge &p);
+
   void remap_svalue_ids (const svalue_id_map &map);
   void remap_equiv_class_ids (const equiv_class_id_map &map);
 
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index b2c76e8731a..32faf6d7a38 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -6413,6 +6413,8 @@ region_model::canonicalize_and_purge (region_model_context *ctxt,
       r->on_purge (p);
     }
 
+  get_constraints ()->on_purge (p);
+
   /* Drop the redundant svalues from the end of the vector.  */
   while ((signed)m_svalues.length () > p.m_first_unused_sid.as_int ())
     {
@@ -6523,6 +6525,29 @@ constraint_manager::delete_redundant_ecs (const equiv_class_id_map &ec_id_map,
     }
 }
 
+// FIXME: move this
+void
+constraint_manager::on_purge (const ana::purge &p)
+{
+  /* Notify surviving ECs about the svalues that we're about to purge.  */
+  for (int i = 0; i < p.m_first_unused_ec_id.as_int (); i++)
+    {
+      equiv_class *ec = m_equiv_classes[i];
+      ec->on_purge (p);
+    }
+}
+
+// FIXME: move this
+void
+equiv_class::on_purge (const purge &p)
+{
+  unsigned read_index, write_index;
+  svalue_id *sid;
+  VEC_ORDERED_REMOVE_IF (m_vars, read_index, write_index, sid,
+			 p.purging_sid_p (*sid));
+  // FIXME: what about constants?
+}
+
 /* Renumber the svalues within this model according to MAP.  */
 
 void
@@ -7271,13 +7296,9 @@ canonicalization::walk_ec_id (equiv_class_id ec_id)
 
   m_ec_id_map.put (ec_id, equiv_class_id::from_int (m_next_ec_id_int++));
 
-  /* Walk the sids in this EC.  FIXME: what order?  */
+  /* We don't walk the sids in the EC, so as to ensure that redundant
+     svalues get purged.  */
   const equiv_class &ec = ec_id.get_obj (*m_model.get_constraints ());
-  unsigned var_idx;
-  svalue_id *var_in_ec;
-  FOR_EACH_VEC_ELT (ec.m_vars, var_idx, var_in_ec)
-    walk_sid (*var_in_ec);
-
   if (!ec.m_cst_sid.null_p ())
     walk_sid (ec.m_cst_sid);
   else
@@ -8277,6 +8298,34 @@ test_canonicalization_7 ()
   ASSERT_EQ (model0, model1);
 }
 
+/* Verify that we purge redundant unknown values, even if we have
+   constraints on them.  */
+
+static void
+test_canonicalization_8 ()
+{
+  tree x = build_global_decl ("x", integer_type_node);
+  tree int_0 = build_int_cst (integer_type_node, 0);
+
+  /* "x = 0;" */
+  region_model model0;
+  model0.set_value (model0.get_lvalue (x, NULL),
+		    model0.get_rvalue (int_0, NULL), NULL);
+
+  region_model model1 (model0);
+
+  /* Add a redundant unknown value, also equal to 0.  */
+  svalue_id sid = model0.add_svalue (new unknown_svalue (integer_type_node));
+  model0.get_constraints ()->add_constraint (sid, EQ_EXPR,
+					     model0.get_rvalue (int_0, NULL));
+
+  purge_stats stats;
+  model0.canonicalize_and_purge (NULL, &stats);
+  // TODO: assert that it is purged
+
+  ASSERT_EQ (model0, model1);
+}
+
 /* Assert that if we have two region_model instances
    with values VAL_A and VAL_B for EXPR that they are
    mergable.  Write the merged model to *OUT_MERGED_MODEL,
@@ -8770,6 +8819,7 @@ analyzer_region_model_cc_tests ()
   test_canonicalization_5 ();
   test_canonicalization_6 ();
   test_canonicalization_7 ();
+  test_canonicalization_8 ();
   test_state_merging ();
   test_constraint_merging ();
   test_constraint_merging_2 ();
-- 
2.21.0

