diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2020-11-09 20:35:25 +0100 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2020-11-10 09:28:43 +0100 |
commit | 3d3470e239e8040f642a8852721b4962b4ed36f2 (patch) | |
tree | d88d0a2a5c76c93e728b7e6fb0174d8908059da6 /gcc/value-range.cc | |
parent | fb54c3032b8a554beed779499298ad2554d1ab42 (diff) | |
download | gcc-3d3470e239e8040f642a8852721b4962b4ed36f2.zip gcc-3d3470e239e8040f642a8852721b4962b4ed36f2.tar.gz gcc-3d3470e239e8040f642a8852721b4962b4ed36f2.tar.bz2 |
Normalize VARYING for -fstrict-enums.
The problem here is that the representation for VARYING in
-fstrict-enums is different between value_range and irange.
The helper function irange::normalize_min_max() will normalize to
VARYING only if setting the range to the entire domain of the
underlying type. That is, [0, 0xff..ff], not the domain as defined by
-fstrict-enums. This causes problems because the multi-range version
of varying_p() will return true if the range is the domain as defined
by -fstrict-enums. Thus, normalize_min_max and varying_p have
different concepts of varying for multi-ranges.
(BTW, legacy ranges are different because they never look at the
extremes of a range to determine varying-ness. They only look at the
kind field.)
One approach is to change all the code to limit ranges to the domain
in the -fstrict-enums world, but this won't work because there are
various instances of gimple where the values assigned or compared are
beyond the limits of TYPE_{MIN,MAX}_VALUE. One example is the
addition of 0xffffffff to represent subtraction.
This patch fixes multi-range varying_p() and set_varying() to agree
with the normalization code, using the extremes of the underlying type,
to represent varying.
gcc/ChangeLog:
PR tree-optimization/97767
* value-range.cc (dump_bound_with_infinite_markers): Use
wi::min_value and wi::max_value.
(range_tests_strict_enum): New.
(range_tests): Call range_tests_strict_enum.
* value-range.h (irange::varying_p): Use wi::min_value
and wi::max_value.
(irange::set_varying): Same.
(irange::normalize_min_max): Remove comment.
gcc/testsuite/ChangeLog:
* g++.dg/opt/pr97767.C: New test.
Diffstat (limited to 'gcc/value-range.cc')
-rw-r--r-- | gcc/value-range.cc | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 61f7da2..f83a824 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -1866,12 +1866,17 @@ static void dump_bound_with_infinite_markers (FILE *file, tree bound) { tree type = TREE_TYPE (bound); + wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + if (INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type) - && vrp_val_is_min (bound) + && TREE_CODE (bound) == INTEGER_CST + && wi::to_wide (bound) == type_min && TYPE_PRECISION (type) != 1) fprintf (file, "-INF"); - else if (vrp_val_is_max (bound) + else if (TREE_CODE (bound) == INTEGER_CST + && wi::to_wide (bound) == type_max && TYPE_PRECISION (type) != 1) fprintf (file, "+INF"); else @@ -2241,6 +2246,38 @@ range_tests_legacy () } } +// Simulate -fstrict-enums where the domain of a type is less than the +// underlying type. + +static void +range_tests_strict_enum () +{ + // The enum can only hold [0, 3]. + tree rtype = copy_node (unsigned_type_node); + TYPE_MIN_VALUE (rtype) = build_int_cstu (rtype, 0); + TYPE_MAX_VALUE (rtype) = build_int_cstu (rtype, 3); + + // Test that even though vr1 covers the strict enum domain ([0, 3]), + // it does not cover the domain of the underlying type. + int_range<1> vr1 (build_int_cstu (rtype, 0), build_int_cstu (rtype, 1)); + int_range<1> vr2 (build_int_cstu (rtype, 2), build_int_cstu (rtype, 3)); + vr1.union_ (vr2); + ASSERT_TRUE (vr1 == int_range<1> (build_int_cstu (rtype, 0), + build_int_cstu (rtype, 3))); + ASSERT_FALSE (vr1.varying_p ()); + + // Test that copying to a multi-range does not change things. + int_range<2> ir1 (vr1); + ASSERT_TRUE (ir1 == vr1); + ASSERT_FALSE (ir1.varying_p ()); + + // The same test as above, but using TYPE_{MIN,MAX}_VALUE instead of [0,3]. + vr1 = int_range<1> (TYPE_MIN_VALUE (rtype), TYPE_MAX_VALUE (rtype)); + ir1 = vr1; + ASSERT_TRUE (ir1 == vr1); + ASSERT_FALSE (ir1.varying_p ()); +} + static void range_tests_misc () { @@ -2442,6 +2479,7 @@ range_tests () range_tests_legacy (); range_tests_irange3 (); range_tests_int_range_max (); + range_tests_strict_enum (); range_tests_misc (); } |