@@ -1145,6 +1145,30 @@ equiv_class::canonicalize ()
1145
1145
m_vars.qsort (svalue::cmp_ptr_ptr);
1146
1146
}
1147
1147
1148
+ /* Return true if this EC contains a variable, false if it merely
1149
+ contains constants.
1150
+ Subroutine of constraint_manager::canonicalize, for removing
1151
+ redundant ECs. */
1152
+
1153
+ bool
1154
+ equiv_class::contains_non_constant_p () const
1155
+ {
1156
+ if (m_constant)
1157
+ {
1158
+ for (auto iter : m_vars)
1159
+ if (iter->maybe_get_constant ())
1160
+ continue ;
1161
+ else
1162
+ /* We have {non-constant == constant}. */
1163
+ return true ;
1164
+ /* We only have constants. */
1165
+ return false ;
1166
+ }
1167
+ else
1168
+ /* Return true if we have {non-constant == non-constant}. */
1169
+ return m_vars.length () > 1 ;
1170
+ }
1171
+
1148
1172
/* Get a debug string for C_OP. */
1149
1173
1150
1174
const char *
@@ -2718,8 +2742,7 @@ constraint_manager::canonicalize ()
2718
2742
{
2719
2743
equiv_class *ec = m_equiv_classes[i];
2720
2744
if (!used_ecs.contains (ec)
2721
- && ((ec->m_vars .length () < 2 && ec->m_constant == NULL_TREE)
2722
- || (ec->m_vars .length () == 0 )))
2745
+ && !ec->contains_non_constant_p ())
2723
2746
{
2724
2747
m_equiv_classes.unordered_remove (i);
2725
2748
delete ec;
@@ -3704,6 +3727,127 @@ test_many_constants ()
3704
3727
}
3705
3728
}
3706
3729
3730
+ /* Verify that purging state relating to a variable doesn't leave stray
3731
+ equivalence classes (after canonicalization). */
3732
+
3733
+ static void
3734
+ test_purging (void )
3735
+ {
3736
+ tree int_0 = build_int_cst (integer_type_node, 0 );
3737
+ tree a = build_global_decl (" a" , integer_type_node);
3738
+ tree b = build_global_decl (" b" , integer_type_node);
3739
+
3740
+ /* "a != 0". */
3741
+ {
3742
+ region_model_manager mgr;
3743
+ region_model model (&mgr);
3744
+ ADD_SAT_CONSTRAINT (model, a, NE_EXPR, int_0);
3745
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 2 );
3746
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 1 );
3747
+
3748
+ /* Purge state for "a". */
3749
+ const svalue *sval_a = model.get_rvalue (a, NULL );
3750
+ model.purge_state_involving (sval_a, NULL );
3751
+ model.canonicalize ();
3752
+ /* We should have an empty constraint_manager. */
3753
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 0 );
3754
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 0 );
3755
+ }
3756
+
3757
+ /* "a != 0" && "b != 0". */
3758
+ {
3759
+ region_model_manager mgr;
3760
+ region_model model (&mgr);
3761
+ ADD_SAT_CONSTRAINT (model, a, NE_EXPR, int_0);
3762
+ ADD_SAT_CONSTRAINT (model, b, NE_EXPR, int_0);
3763
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 3 );
3764
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 2 );
3765
+
3766
+ /* Purge state for "a". */
3767
+ const svalue *sval_a = model.get_rvalue (a, NULL );
3768
+ model.purge_state_involving (sval_a, NULL );
3769
+ model.canonicalize ();
3770
+ /* We should just have the constraint/ECs involving b != 0. */
3771
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 2 );
3772
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 1 );
3773
+ ASSERT_CONDITION_TRUE (model, b, NE_EXPR, int_0);
3774
+ }
3775
+
3776
+ /* "a != 0" && "b == 0". */
3777
+ {
3778
+ region_model_manager mgr;
3779
+ region_model model (&mgr);
3780
+ ADD_SAT_CONSTRAINT (model, a, NE_EXPR, int_0);
3781
+ ADD_SAT_CONSTRAINT (model, b, EQ_EXPR, int_0);
3782
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 2 );
3783
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 1 );
3784
+
3785
+ /* Purge state for "a". */
3786
+ const svalue *sval_a = model.get_rvalue (a, NULL );
3787
+ model.purge_state_involving (sval_a, NULL );
3788
+ model.canonicalize ();
3789
+ /* We should just have the EC involving b == 0. */
3790
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 1 );
3791
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 0 );
3792
+ ASSERT_CONDITION_TRUE (model, b, EQ_EXPR, int_0);
3793
+ }
3794
+
3795
+ /* "a == 0". */
3796
+ {
3797
+ region_model_manager mgr;
3798
+ region_model model (&mgr);
3799
+ ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_0);
3800
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 1 );
3801
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 0 );
3802
+
3803
+ /* Purge state for "a". */
3804
+ const svalue *sval_a = model.get_rvalue (a, NULL );
3805
+ model.purge_state_involving (sval_a, NULL );
3806
+ model.canonicalize ();
3807
+ /* We should have an empty constraint_manager. */
3808
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 0 );
3809
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 0 );
3810
+ }
3811
+
3812
+ /* "a == 0" && "b != 0". */
3813
+ {
3814
+ region_model_manager mgr;
3815
+ region_model model (&mgr);
3816
+ ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_0);
3817
+ ADD_SAT_CONSTRAINT (model, b, NE_EXPR, int_0);
3818
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 2 );
3819
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 1 );
3820
+
3821
+ /* Purge state for "a". */
3822
+ const svalue *sval_a = model.get_rvalue (a, NULL );
3823
+ model.purge_state_involving (sval_a, NULL );
3824
+ model.canonicalize ();
3825
+ /* We should just have the constraint/ECs involving b != 0. */
3826
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 2 );
3827
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 1 );
3828
+ ASSERT_CONDITION_TRUE (model, b, NE_EXPR, int_0);
3829
+ }
3830
+
3831
+ /* "a == 0" && "b == 0". */
3832
+ {
3833
+ region_model_manager mgr;
3834
+ region_model model (&mgr);
3835
+ ADD_SAT_CONSTRAINT (model, a, EQ_EXPR, int_0);
3836
+ ADD_SAT_CONSTRAINT (model, b, EQ_EXPR, int_0);
3837
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 1 );
3838
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 0 );
3839
+
3840
+ /* Purge state for "a". */
3841
+ const svalue *sval_a = model.get_rvalue (a, NULL );
3842
+ model.purge_state_involving (sval_a, NULL );
3843
+ model.canonicalize ();
3844
+ /* We should just have the EC involving b == 0. */
3845
+ ASSERT_EQ (model.get_constraints ()->m_equiv_classes .length (), 1 );
3846
+ ASSERT_EQ (model.get_constraints ()->m_constraints .length (), 0 );
3847
+ ASSERT_CONDITION_TRUE (model, b, EQ_EXPR, int_0);
3848
+ }
3849
+ }
3850
+
3707
3851
/* Implementation detail of ASSERT_DUMP_BOUNDED_RANGES_EQ. */
3708
3852
3709
3853
static void
@@ -4035,6 +4179,7 @@ run_constraint_manager_tests (bool transitivity)
4035
4179
test_constraint_impl ();
4036
4180
test_equality ();
4037
4181
test_many_constants ();
4182
+ test_purging ();
4038
4183
test_bounded_range ();
4039
4184
test_bounded_ranges ();
4040
4185
0 commit comments