diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c752e61600e..dbe9c080c94 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2005-11-06 Diego Novillo + + PR 24670 + * tree-vrp.c (fix_equivalence_set): New. + (extract_range_from_assert): Call it. + 2005-11-05 Ian Lance Taylor PR target/22432 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9fc72af22ba..79c7ac7d032 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-11-06 Diego Novillo + + PR 24670 + * gcc.dg/tree-ssa/pr24670.c: New test. + 2005-11-05 Ian Lance Taylor PR target/22432 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr24670.c b/gcc/testsuite/gcc.dg/tree-ssa/pr24670.c new file mode 100644 index 00000000000..a5ff800d925 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr24670.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +__inline__ void +shift128Right (int count, long long int *z1Ptr) +{ + long long int z1; + if (count == 0); + else if (count < 64); + else + z1 = (count < 64) ? count : 0; + *z1Ptr = z1; +} + +float128_rem () +{ + signed int expDiff; + long long int aSig1; + long long int sigMean1; + if (-64 < expDiff) + shift128Right (-expDiff, &aSig1); + add128 (&sigMean1); +} diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 7269fb5029a..929908bf473 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -632,6 +632,81 @@ range_includes_zero_p (value_range_t *vr) } +/* When extracting ranges from X_i = ASSERT_EXPR , we will + initially consider X_i and Y_j equivalent, so the equivalence set + of Y_j is added to the equivalence set of X_i. However, it is + possible to have a chain of ASSERT_EXPRs whose predicates are + actually incompatible. This is usually the result of nesting of + contradictory if-then-else statements. For instance, in PR 24670: + + count_4 has range [-INF, 63] + + if (count_4 != 0) + { + count_19 = ASSERT_EXPR + if (count_19 > 63) + { + count_18 = ASSERT_EXPR 63> + if (count_18 <= 63) + ... + } + } + + Notice that 'if (count_19 > 63)' is trivially false and will be + folded out at the end. However, during propagation, the flowgraph + is not cleaned up and so, VRP will evaluate predicates more + predicates than necessary, so it must support these + inconsistencies. The problem here is that because of the chaining + of ASSERT_EXPRs, the equivalency set for count_18 includes count_4. + Since count_4 has an incompatible range, we ICE when evaluating the + ranges in the equivalency set. So, we need to remove count_4 from + it. */ + +static void +fix_equivalence_set (value_range_t *vr_p) +{ + bitmap_iterator bi; + unsigned i; + bitmap e = vr_p->equiv; + bitmap to_remove = BITMAP_ALLOC (NULL); + + /* Only detect inconsistencies on numeric ranges. */ + if (vr_p->type == VR_VARYING + || vr_p->type == VR_UNDEFINED + || symbolic_range_p (vr_p)) + return; + + EXECUTE_IF_SET_IN_BITMAP (e, 0, i, bi) + { + value_range_t *equiv_vr = vr_value[i]; + + if (equiv_vr->type == VR_VARYING + || equiv_vr->type == VR_UNDEFINED + || symbolic_range_p (equiv_vr)) + continue; + + if (equiv_vr->type == VR_RANGE + && vr_p->type == VR_RANGE + && !value_ranges_intersect_p (vr_p, equiv_vr)) + bitmap_set_bit (to_remove, i); + else if ((equiv_vr->type == VR_RANGE && vr_p->type == VR_ANTI_RANGE) + || (equiv_vr->type == VR_ANTI_RANGE && vr_p->type == VR_RANGE)) + { + /* A range and an anti-range have an empty intersection if + their end points are the same. FIXME, + value_ranges_intersect_p should handle this + automatically. */ + if (compare_values (equiv_vr->min, vr_p->min) == 0 + && compare_values (equiv_vr->max, vr_p->max) == 0) + bitmap_set_bit (to_remove, i); + } + } + + bitmap_and_compl_into (vr_p->equiv, to_remove); + BITMAP_FREE (to_remove); +} + + /* Extract value range information from an ASSERT_EXPR EXPR and store it in *VR_P. */ @@ -747,7 +822,11 @@ extract_range_from_assert (value_range_t *vr_p, tree expr) } } - /* The new range has the same set of equivalences of VAR's range. */ + /* Initially, the new range has the same set of equivalences of + VAR's range. This will be revised before returning the final + value. Since assertions may be chained via mutually exclusive + predicates, we will need to trim the set of equivalences before + we are done. */ gcc_assert (vr_p->equiv == NULL); vr_p->equiv = BITMAP_ALLOC (NULL); add_equivalence (vr_p->equiv, var); @@ -924,7 +1003,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr) || var_vr->type == VR_UNDEFINED || symbolic_range_p (vr_p) || symbolic_range_p (var_vr)) - return; + goto done; if (var_vr->type == VR_RANGE && vr_p->type == VR_RANGE) { @@ -968,6 +1047,11 @@ extract_range_from_assert (value_range_t *vr_p, tree expr) && compare_values (var_vr->max, vr_p->max) == 0) set_value_range_to_varying (vr_p); } + + /* Remove names from the equivalence set that have ranges + incompatible with VR_P. */ +done: + fix_equivalence_set (vr_p); }