aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-09-13 10:37:49 -0700
committerIan Lance Taylor <iant@golang.org>2021-09-13 10:37:49 -0700
commite252b51ccde010cbd2a146485d8045103cd99533 (patch)
treee060f101cdc32bf5e520de8e5275db9d4236b74c /gcc/value-range.cc
parentf10c7c4596dda99d2ee872c995ae4aeda65adbdf (diff)
parent104c05c5284b7822d770ee51a7d91946c7e56d50 (diff)
downloadgcc-e252b51ccde010cbd2a146485d8045103cd99533.zip
gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.gz
gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.bz2
Merge from trunk revision 104c05c5284b7822d770ee51a7d91946c7e56d50.
Diffstat (limited to 'gcc/value-range.cc')
-rw-r--r--gcc/value-range.cc224
1 files changed, 116 insertions, 108 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 9c42f82..f113fd7 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "ssa.h"
#include "tree-pretty-print.h"
#include "fold-const.h"
+#include "gimple-range.h"
// Here we copy between any two irange's. The ranges can be legacy or
// multi-ranges, and copying between any combination works correctly.
@@ -59,6 +60,7 @@ irange::operator= (const irange &src)
m_base[x - 1] = src.m_base[src.m_num_ranges * 2 - 1];
m_num_ranges = lim;
+ m_kind = src.m_kind;
return *this;
}
@@ -106,8 +108,8 @@ void
irange::copy_to_legacy (const irange &src)
{
gcc_checking_assert (legacy_mode_p ());
- // Copy legacy to legacy.
- if (src.legacy_mode_p ())
+ // Handle legacy to legacy and other things that are easy to copy.
+ if (src.legacy_mode_p () || src.varying_p () || src.undefined_p ())
{
m_num_ranges = src.m_num_ranges;
m_base[0] = src.m_base[0];
@@ -116,11 +118,7 @@ irange::copy_to_legacy (const irange &src)
return;
}
// Copy multi-range to legacy.
- if (src.undefined_p ())
- set_undefined ();
- else if (src.varying_p ())
- set_varying (src.type ());
- else if (src.maybe_anti_range ())
+ if (src.maybe_anti_range ())
{
int_range<3> r (src);
r.invert ();
@@ -180,6 +178,36 @@ irange::irange_set (tree min, tree max)
m_base[0] = min;
m_base[1] = max;
m_num_ranges = 1;
+ m_kind = VR_RANGE;
+ normalize_kind ();
+
+ if (flag_checking)
+ verify_range ();
+}
+
+void
+irange::irange_set_1bit_anti_range (tree min, tree max)
+{
+ tree type = TREE_TYPE (min);
+ gcc_checking_assert (TYPE_PRECISION (type) == 1);
+
+ if (operand_equal_p (min, max))
+ {
+ // Since these are 1-bit quantities, they can only be [MIN,MIN]
+ // or [MAX,MAX].
+ if (vrp_val_is_min (min))
+ min = max = vrp_val_max (type);
+ else
+ min = max = vrp_val_min (type);
+ set (min, max);
+ }
+ else
+ {
+ // The only alternative is [MIN,MAX], which is the empty range.
+ gcc_checking_assert (vrp_val_is_min (min));
+ gcc_checking_assert (vrp_val_is_max (max));
+ set_undefined ();
+ }
if (flag_checking)
verify_range ();
}
@@ -190,6 +218,12 @@ irange::irange_set_anti_range (tree min, tree max)
gcc_checking_assert (!POLY_INT_CST_P (min));
gcc_checking_assert (!POLY_INT_CST_P (max));
+ if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
+ {
+ irange_set_1bit_anti_range (min, max);
+ return;
+ }
+
// set an anti-range
tree type = TREE_TYPE (min);
signop sign = TYPE_SIGN (type);
@@ -216,6 +250,10 @@ irange::irange_set_anti_range (tree min, tree max)
m_base[m_num_ranges * 2 + 1] = type_range.tree_upper_bound (0);
++m_num_ranges;
}
+
+ m_kind = VR_RANGE;
+ normalize_kind ();
+
if (flag_checking)
verify_range ();
}
@@ -278,29 +316,21 @@ irange::set (tree min, tree max, value_range_kind kind)
// Anti-ranges that can be represented as ranges should be so.
if (kind == VR_ANTI_RANGE)
{
- /* For -fstrict-enums we may receive out-of-range ranges so consider
- values < -INF and values > INF as -INF/INF as well. */
bool is_min = vrp_val_is_min (min);
bool is_max = vrp_val_is_max (max);
- tree type = TREE_TYPE (min);
if (is_min && is_max)
{
- /* We cannot deal with empty ranges, drop to varying.
- ??? This could be VR_UNDEFINED instead. */
- set_varying (type);
- return;
+ // Fall through. This will either be normalized as
+ // VR_UNDEFINED if the anti-range spans the entire
+ // precision, or it will remain an VR_ANTI_RANGE in the case
+ // of an -fstrict-enum where [MIN,MAX] is less than the span
+ // of underlying precision.
}
- else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
- && (is_min || is_max))
+ else if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
{
- /* Non-empty boolean ranges can always be represented
- as a singleton range. */
- if (is_min)
- min = max = vrp_val_max (TREE_TYPE (min));
- else
- min = max = vrp_val_min (TREE_TYPE (min));
- kind = VR_RANGE;
+ irange_set_1bit_anti_range (min, max);
+ return;
}
else if (is_min)
{
@@ -322,7 +352,7 @@ irange::set (tree min, tree max, value_range_kind kind)
m_base[0] = min;
m_base[1] = max;
m_num_ranges = 1;
- normalize_min_max ();
+ normalize_kind ();
if (flag_checking)
verify_range ();
}
@@ -332,71 +362,38 @@ irange::set (tree min, tree max, value_range_kind kind)
void
irange::verify_range ()
{
+ if (m_kind == VR_UNDEFINED)
+ {
+ gcc_checking_assert (m_num_ranges == 0);
+ return;
+ }
+ if (m_kind == VR_VARYING)
+ {
+ gcc_checking_assert (m_num_ranges == 1);
+ gcc_checking_assert (varying_compatible_p ());
+ return;
+ }
if (!legacy_mode_p ())
{
- gcc_checking_assert (m_kind == VR_RANGE);
+ gcc_checking_assert (m_num_ranges != 0);
+ gcc_checking_assert (!varying_compatible_p ());
for (unsigned i = 0; i < m_num_ranges; ++i)
{
tree lb = tree_lower_bound (i);
tree ub = tree_upper_bound (i);
int c = compare_values (lb, ub);
- gcc_assert (c == 0 || c == -1);
+ gcc_checking_assert (c == 0 || c == -1);
}
return;
}
-
- switch (m_kind)
+ if (m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
{
- case VR_UNDEFINED:
- gcc_assert (m_num_ranges == 0);
- break;
-
- case VR_VARYING:
- gcc_assert (m_num_ranges == 1);
- break;
-
- case VR_ANTI_RANGE:
- case VR_RANGE:
- {
- gcc_assert (m_num_ranges == 1);
- int cmp = compare_values (tree_lower_bound (0), tree_upper_bound (0));
- gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
- return;
- }
-
- default:
- gcc_unreachable ();
+ gcc_checking_assert (m_num_ranges == 1);
+ int cmp = compare_values (tree_lower_bound (0), tree_upper_bound (0));
+ gcc_checking_assert (cmp == 0 || cmp == -1 || cmp == -2);
}
}
-unsigned
-irange::legacy_num_pairs () const
-{
- gcc_checking_assert (legacy_mode_p ());
-
- if (undefined_p ())
- return 0;
- if (varying_p ())
- return 1;
- // Inlined symbolic_p for performance:
- if (!is_gimple_min_invariant (min ()) || !is_gimple_min_invariant (max ()))
- {
- value_range numeric_range (*this);
- numeric_range.normalize_symbolics ();
- return numeric_range.num_pairs ();
- }
- if (m_kind == VR_ANTI_RANGE)
- {
- // ~[MIN, X] has one sub-range of [X+1, MAX], and
- // ~[X, MAX] has one sub-range of [MIN, X-1].
- if (vrp_val_is_min (min ()) || vrp_val_is_max (max ()))
- return 1;
- return 2;
- }
- gcc_checking_assert (m_num_ranges == 1);
- return 1;
-}
-
// Return the lower bound for a sub-range. PAIR is the sub-range in
// question.
@@ -410,7 +407,7 @@ irange::legacy_lower_bound (unsigned pair) const
numeric_range.normalize_symbolics ();
return numeric_range.legacy_lower_bound (pair);
}
- gcc_checking_assert (!undefined_p ());
+ gcc_checking_assert (m_num_ranges > 0);
gcc_checking_assert (pair + 1 <= num_pairs ());
if (m_kind == VR_ANTI_RANGE)
{
@@ -437,7 +434,7 @@ irange::legacy_upper_bound (unsigned pair) const
numeric_range.normalize_symbolics ();
return numeric_range.legacy_upper_bound (pair);
}
- gcc_checking_assert (!undefined_p ());
+ gcc_checking_assert (m_num_ranges > 0);
gcc_checking_assert (pair + 1 <= num_pairs ());
if (m_kind == VR_ANTI_RANGE)
{
@@ -458,8 +455,10 @@ irange::legacy_equal_p (const irange &other) const
if (m_kind != other.m_kind)
return false;
- if (m_kind == VR_UNDEFINED || m_kind == VR_VARYING)
+ if (m_kind == VR_UNDEFINED)
return true;
+ if (m_kind == VR_VARYING)
+ return range_compatible_p (type (), other.type ());
return (vrp_operand_equal_p (tree_lower_bound (0),
other.tree_lower_bound (0))
&& vrp_operand_equal_p (tree_upper_bound (0),
@@ -503,22 +502,17 @@ irange::equal_p (const irange &other) const
bool
irange::symbolic_p () const
{
- return (!varying_p ()
- && !undefined_p ()
+ return (m_num_ranges > 0
&& (!is_gimple_min_invariant (min ())
|| !is_gimple_min_invariant (max ())));
}
-/* NOTE: This is not the inverse of symbolic_p because the range
- could also be varying or undefined. Ideally they should be inverse
- of each other, with varying only applying to symbolics. Varying of
- constants would be represented as [-MIN, +MAX]. */
+/* Return TRUE if this is a constant range. */
bool
irange::constant_p () const
{
- return (!varying_p ()
- && !undefined_p ()
+ return (m_num_ranges > 0
&& TREE_CODE (min ()) == INTEGER_CST
&& TREE_CODE (max ()) == INTEGER_CST);
}
@@ -1641,6 +1635,9 @@ irange::irange_union (const irange &r)
m_base[j] = res [j];
m_num_ranges = i / 2;
+ m_kind = VR_RANGE;
+ normalize_kind ();
+
if (flag_checking)
verify_range ();
}
@@ -1732,6 +1729,10 @@ irange::irange_intersect (const irange &r)
// At the exit of this loop, it is one of 2 things:
// ran out of r1, or r2, but either means we are done.
m_num_ranges = bld_pair;
+
+ m_kind = VR_RANGE;
+ normalize_kind ();
+
if (flag_checking)
verify_range ();
}
@@ -1777,7 +1778,7 @@ irange::invert ()
return;
}
- gcc_assert (!undefined_p () && !varying_p ());
+ gcc_checking_assert (!undefined_p () && !varying_p ());
// We always need one more set of bounds to represent an inverse, so
// if we're at the limit, we can't properly represent things.
@@ -1864,6 +1865,10 @@ irange::invert ()
}
m_num_ranges = nitems / 2;
+ // We disallow undefined or varying coming in, so the result can
+ // only be a VR_RANGE.
+ gcc_checking_assert (m_kind == VR_RANGE);
+
if (flag_checking)
verify_range ();
}
@@ -2042,26 +2047,20 @@ vrp_operand_equal_p (const_tree val1, const_tree val2)
return true;
}
-#define DEFINE_INT_RANGE_GC_STUBS(N) \
- void \
- gt_pch_nx (int_range<N> *&x) \
- { \
- for (unsigned i = 0; i < N; ++i) \
- { \
- gt_pch_nx (x->m_ranges[i * 2]); \
- gt_pch_nx (x->m_ranges[i * 2 + 1]); \
- } \
- } \
- \
- void \
- gt_ggc_mx (int_range<N> *&x) \
- { \
- for (unsigned i = 0; i < N; ++i) \
- { \
- gt_ggc_mx (x->m_ranges[i * 2]); \
- gt_ggc_mx (x->m_ranges[i * 2 + 1]); \
- } \
- }
+// ?? These stubs are for ipa-prop.c which use a value_range in a
+// hash_traits. hash-traits.h defines an extern of gt_ggc_mx (T &)
+// instead of picking up the gt_ggc_mx (T *) version.
+void
+gt_pch_nx (int_range<1> *&x)
+{
+ return gt_pch_nx ((irange *) x);
+}
+
+void
+gt_ggc_mx (int_range<1> *&x)
+{
+ return gt_ggc_mx ((irange *) x);
+}
#define DEFINE_INT_RANGE_INSTANCE(N) \
template int_range<N>::int_range(tree, tree, value_range_kind); \
@@ -2078,7 +2077,6 @@ DEFINE_INT_RANGE_INSTANCE(1)
DEFINE_INT_RANGE_INSTANCE(2)
DEFINE_INT_RANGE_INSTANCE(3)
DEFINE_INT_RANGE_INSTANCE(255)
-DEFINE_INT_RANGE_GC_STUBS(1)
#if CHECKING_P
#include "selftest.h"
@@ -2250,6 +2248,16 @@ range_tests_legacy ()
copy = legacy_range;
ASSERT_TRUE (copy.varying_p ());
}
+
+ // VARYING of different sizes should not be equal.
+ tree big_type = build_nonstandard_integer_type (32, 1);
+ tree small_type = build_nonstandard_integer_type (16, 1);
+ int_range_max r0 (big_type);
+ int_range_max r1 (small_type);
+ ASSERT_TRUE (r0 != r1);
+ value_range vr0 (big_type);
+ int_range_max vr1 (small_type);
+ ASSERT_TRUE (vr0 != vr1);
}
// Simulate -fstrict-enums where the domain of a type is less than the