From 227956d88770b6ff2aee15fa8192d02f2d47c493 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 18 Feb 2020 21:52:10 -0500
Subject: [PATCH 21/31] FIXME: more WIP on canonicalization/purging

---
 gcc/analyzer/region-model.cc | 65 +++++++++++++++++++++++++++++++++---
 1 file changed, 61 insertions(+), 4 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index bbeeb54ae95..0e21b576c47 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -6080,6 +6080,20 @@ constraint_cmp (const void *p1, const void *p2)
   return 0; // FIXME
 }
 
+/* FIXME Comparator for constraints to impose a deterministic ordering
+   during canonicalization.  */
+
+static int
+svalue_id_cmp (const void *p1, const void *p2)
+{
+  const svalue_id *sid1 = (const svalue_id *)p1;
+  const svalue_id *sid2 = (const svalue_id *)p2;
+
+  gcc_assert (!sid1->null_p ());
+  gcc_assert (!sid2->null_p ());
+  return sid1->as_int () - sid2->as_int ();
+}
+
 /* Walk the regions and svalues, reordering those that are expressible
    from user code into a deterministic "canonical" order, and deleting
    any that aren't reachable, in both cases to maximize the chance of
@@ -6231,10 +6245,20 @@ region_model::canonicalize_and_purge (region_model_context *ctxt,
 
   /* Some ECs could now be newly redundant; find them and purge them.  */
   {
-    /* Find the ECs that are referenced by constraints.  */
     equiv_class_id_map ec_id_map (get_constraints ()->get_num_equiv_classes ());
     int next_ec_id_int = 0;
     int i;
+
+    /* Mark any ECs that have more than element.  */
+    equiv_class *ec;
+    FOR_EACH_VEC_ELT (get_constraints ()->m_equiv_classes, i, ec)
+      if (ec->m_vars.length () > 1)
+	{
+	  equiv_class_id ec_id = equiv_class_id::from_int (i);
+	  ec_id_map.put (ec_id, next_ec_id_int++);
+	}
+
+    /* Mark ECs that are referenced by constraints.  */
     constraint *con;
     FOR_EACH_VEC_ELT (get_constraints ()->m_constraints, i, con)
       {
@@ -6243,13 +6267,11 @@ region_model::canonicalize_and_purge (region_model_context *ctxt,
 	if (ec_id_map.get_dst_for_src (con->m_rhs).null_p ())
 	  ec_id_map.put (con->m_rhs, next_ec_id_int++);
       }
-    // FIXME: also, any that have more than one element!!
 
     equiv_class_id first_unused_ec_id
       = equiv_class_id::from_int (next_ec_id_int);
 
-    /* Move the rest.  */
-    equiv_class *ec;
+    /* Move the rest to the end.  */
     FOR_EACH_VEC_ELT (get_constraints ()->m_equiv_classes, i, ec)
       {
 	equiv_class_id ec_id (i);
@@ -6263,6 +6285,14 @@ region_model::canonicalize_and_purge (region_model_context *ctxt,
 					      stats, logger);
   }
 
+  /* Sort the sids within the remaining ECs. */
+  {
+    int i;
+    equiv_class *ec;
+    FOR_EACH_VEC_ELT (get_constraints ()->m_equiv_classes, i, ec)
+      ec->m_vars.qsort (svalue_id_cmp);
+  }
+
   validate ();
 }
 
@@ -7925,6 +7955,32 @@ test_canonicalization_5 ()
   ASSERT_EQ (model0, model1);
 }
 
+/* Verify that constraints for
+     x == y
+   and
+     y == x
+   are equal after canonicalization.  */
+
+static void
+test_canonicalization_6 ()
+{
+  tree x = build_global_decl ("x", integer_type_node);
+  tree y = build_global_decl ("y", integer_type_node);
+
+  region_model model0;
+  model0.add_constraint (x, EQ_EXPR, y, NULL);
+  ASSERT_CONDITION_TRUE (model0, x, EQ_EXPR, y);
+
+  region_model model1;
+  model1.add_constraint (y, EQ_EXPR, x, NULL);
+  ASSERT_CONDITION_TRUE (model1, x, EQ_EXPR, y);
+
+  model0.canonicalize_and_purge (NULL);
+  model1.canonicalize_and_purge (NULL);
+  ASSERT_EQ (model0, model1);
+  ASSERT_CONDITION_TRUE (model0, x, EQ_EXPR, y);
+}
+
 /* 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,
@@ -8379,6 +8435,7 @@ analyzer_region_model_cc_tests ()
   test_canonicalization_3 ();
   test_canonicalization_4 ();
   test_canonicalization_5 ();
+  test_canonicalization_6 ();
   test_state_merging ();
   test_constraint_merging ();
 }
-- 
2.21.0

