aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range.h
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2020-11-09 20:35:25 +0100
committerAldy Hernandez <aldyh@redhat.com>2020-11-10 09:28:43 +0100
commit3d3470e239e8040f642a8852721b4962b4ed36f2 (patch)
treed88d0a2a5c76c93e728b7e6fb0174d8908059da6 /gcc/value-range.h
parentfb54c3032b8a554beed779499298ad2554d1ab42 (diff)
downloadgcc-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.h')
-rw-r--r--gcc/value-range.h23
1 files changed, 10 insertions, 13 deletions
diff --git a/gcc/value-range.h b/gcc/value-range.h
index a483fc8..7428c91 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -280,12 +280,14 @@ irange::varying_p () const
tree l = m_base[0];
tree u = m_base[1];
tree t = TREE_TYPE (l);
+ unsigned prec = TYPE_PRECISION (t);
+ signop sign = TYPE_SIGN (t);
if (INTEGRAL_TYPE_P (t))
- return l == TYPE_MIN_VALUE (t) && u == TYPE_MAX_VALUE (t);
+ return (wi::to_wide (l) == wi::min_value (prec, sign)
+ && wi::to_wide (u) == wi::max_value (prec, sign));
if (POINTER_TYPE_P (t))
- return wi::to_wide (l) == 0
- && wi::to_wide (u) == wi::max_value (TYPE_PRECISION (t),
- TYPE_SIGN (t));
+ return (wi::to_wide (l) == 0
+ && wi::to_wide (u) == wi::max_value (prec, sign));
return true;
}
@@ -469,8 +471,10 @@ irange::set_varying (tree type)
m_num_ranges = 1;
if (INTEGRAL_TYPE_P (type))
{
- m_base[0] = TYPE_MIN_VALUE (type);
- m_base[1] = TYPE_MAX_VALUE (type);
+ wide_int min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ m_base[0] = wide_int_to_tree (type, min);
+ m_base[1] = wide_int_to_tree (type, max);
}
else if (POINTER_TYPE_P (type))
{
@@ -566,13 +570,6 @@ irange::set_zero (tree type)
}
// Normalize a range to VARYING or UNDEFINED if possible.
-//
-// Avoid using TYPE_{MIN,MAX}_VALUE because -fstrict-enums can
-// restrict those to a subset of what actually fits in the type.
-// Instead use the extremes of the type precision which will allow
-// compare_range_with_value() to check if a value is inside a range,
-// whereas if we used TYPE_*_VAL, said function would just punt upon
-// seeing a VARYING.
inline void
irange::normalize_min_max ()