aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/value-range.cc')
-rw-r--r--gcc/value-range.cc258
1 files changed, 129 insertions, 129 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index d34a262..f93a7e5 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -55,6 +55,93 @@ irange_bitmask::irange_bitmask (tree type,
}
}
+// Return a range in R of TYPE for this bitmask which encompasses
+// a set of valid values which are allowable for this bitmask/value
+// combination. If false is returned, no range was set.
+
+bool
+irange_bitmask::range_from_mask (irange &r, tree type) const
+{
+ if (unknown_p ())
+ return false;
+
+ gcc_checking_assert ((value () & mask ()) == 0);
+ unsigned popcount = wi::popcount (mask ());
+
+ // For 0, 1 or 2 bits set, create a range with only the allowed values.
+ if (popcount <= 2)
+ {
+ // VALUE is always a valid range.
+ r.set (type, value (), value ());
+ // If there are bits in mask, (VALUE | MASK) is also valid.
+ if (popcount >= 1)
+ r.union_ (int_range<1> (type, value () | mask (), value () | mask ()));
+ // If there are 2 bits set, add the other 2 possible values.
+ if (popcount == 2)
+ {
+ // Extract the two 1-bit masks into lb and ub.
+ wide_int lb = mask () & -mask (); // Lowest set bit.
+ wide_int ub = mask () & (mask () - 1); // The other bit.
+ r.union_ (int_range<1> (type, value () | lb, value () | lb));
+ r.union_ (int_range<1> (type, value () | ub, value () | ub));
+ }
+ return true;
+ }
+
+ // Otherwise, calculate the valid range allowed by the bitmask.
+ int prec = TYPE_PRECISION (type);
+ wide_int ub = mask () | value ();
+ wide_int sign_bit = wi::one (prec) << (prec - 1);
+ wide_int sign_mask = mask () & sign_bit;
+ wide_int sign_value = value () & sign_bit;
+ // Create a lower and upper bound.
+ // If unsigned, or the sign is known to be positive, create [lb, ub]
+ if (TYPE_SIGN (type) == UNSIGNED || (sign_mask == 0 && sign_value == 0))
+ r.set (type, value (), mask () | value ());
+ // If the sign bit is KNOWN to be 1, we have a completely negative range.
+ else if (sign_mask == 0 && sign_value != 0)
+ r.set (type, value (), value () | (mask () & ~sign_bit));
+ else
+ {
+ // Otherwise there are 2 ranges, a negative and positive interval.
+ wide_int neg_base = value () | sign_bit;
+ wide_int pos_mask = mask () & ~sign_bit;
+ r.set (type, neg_base , neg_base | pos_mask);
+ r.union_ (int_range<1> (type, value (), value () | pos_mask));
+ }
+
+ // If the mask doesn't have a trailing zero, there is nothing else to filter.
+ int z = wi::ctz (mask ());
+ if (z == 0)
+ return true;
+
+ // Remove the [0, X] values which the trailing-zero mask rules out.
+ // For example, if z == 4, the mask is 0xFFF0, and the lowest 4 bits
+ // define the range [0, 15]. Only (value & low_mask) is allowed.
+ ub = (wi::one (prec) << z) - 1; // Upper bound of range.
+ int_range<4> mask_range (type, wi::zero (prec), ub);
+ // Remove the valid value from the excluded range and form an anti-range.
+ wide_int allow = value () & ub;
+ mask_range.intersect (int_range<2> (type, allow, allow, VR_ANTI_RANGE));
+ mask_range.invert ();
+ r.intersect (mask_range);
+
+ if (TYPE_SIGN (type) == SIGNED)
+ {
+ // For signed negative values, find the lowest value with trailing zeros.
+ // This forms a range such as [-512, -1] for z=9.
+ wide_int lb = -(wi::one (prec) << z);
+ int_range<4> mask_range (type, lb, wi::minus_one (prec));
+ // Remove the one allowed value from that set.
+ wide_int allow = value () | lb;
+ mask_range.intersect (int_range<2> (type, allow, allow, VR_ANTI_RANGE));
+ mask_range.invert ();
+ r.intersect (mask_range);
+ }
+ return true;
+}
+
+
void
irange::accept (const vrange_visitor &v) const
{
@@ -2275,47 +2362,57 @@ irange::invert ()
// This routine will take the bounds [LB, UB], and apply the bitmask to those
// values such that both bounds satisfy the bitmask. TRUE is returned
// if either bound changes, and they are returned as [NEW_LB, NEW_UB].
-// if NEW_UB < NEW_LB, then the entire bound is to be removed as none of
-// the values are valid.
+// If there is an overflow, or if (NEW_UB < NEW_LB), then the entire bound is
+// to be removed as none of the values are valid. This is indicated by
+// teturning TRUE in OVF. False indicates the bounds are fine.
// ie, [4, 14] MASK 0xFFFE VALUE 0x1
-// means all values must be odd, the new bounds returned will be [5, 13].
+// means all values must be odd, the new bounds returned will be [5, 13] with
+// OVF set to FALSE.
// ie, [4, 4] MASK 0xFFFE VALUE 0x1
-// would return [1, 0] and as the LB < UB, the entire subrange is invalid
-// and should be removed.
+// would return TRUE and OVF == TRUE. The entire subrange should be removed.
bool
irange::snap (const wide_int &lb, const wide_int &ub,
- wide_int &new_lb, wide_int &new_ub)
+ wide_int &new_lb, wide_int &new_ub, bool &ovf)
{
+ ovf = false;
int z = wi::ctz (m_bitmask.mask ());
if (z == 0)
return false;
+ // Shortcircuit check for values that are already good.
+ if ((((lb ^ m_bitmask.value ()) | (ub ^ m_bitmask.value ()))
+ & ~m_bitmask.mask ()) == 0)
+ return false;
+
const wide_int step = (wi::one (TYPE_PRECISION (type ())) << z);
const wide_int match_mask = step - 1;
const wide_int value = m_bitmask.value () & match_mask;
- bool ovf = false;
-
wide_int rem_lb = lb & match_mask;
wide_int offset = (value - rem_lb) & match_mask;
new_lb = lb + offset;
// Check for overflows at +INF
if (wi::lt_p (new_lb, lb, TYPE_SIGN (type ())))
- ovf = true;
+ {
+ ovf = true;
+ return true;
+ }
wide_int rem_ub = ub & match_mask;
wide_int offset_ub = (rem_ub - value) & match_mask;
new_ub = ub - offset_ub;
// Check for underflows at -INF
if (wi::gt_p (new_ub, ub, TYPE_SIGN (type ())))
- ovf = true;
+ {
+ ovf = true;
+ return true;
+ }
- // Overflow or inverted range = invalid
- if (ovf || wi::lt_p (new_ub, new_lb, TYPE_SIGN (type ())))
+ // If inverted range is invalid, set overflow to TRUE.
+ if (wi::lt_p (new_ub, new_lb, TYPE_SIGN (type ())))
{
- new_lb = wi::one (lb.get_precision ());
- new_ub = wi::zero (ub.get_precision ());
+ ovf = true;
return true;
}
return (new_lb != lb) || (new_ub != ub);
@@ -2334,11 +2431,12 @@ irange::snap_subranges ()
wide_int lb, ub;
for (x = 0; x < m_num_ranges; x++)
{
- if (snap (lower_bound (x), upper_bound (x), lb, ub))
+ bool ovf;
+ if (snap (lower_bound (x), upper_bound (x), lb, ub, ovf))
{
changed = true;
- // This subrange is to be completely removed.
- if (wi::lt_p (ub, lb, TYPE_SIGN (type ())))
+ // Check if this subrange is to be completely removed.
+ if (ovf)
{
int_range<1> tmp (type (), lower_bound (x), upper_bound (x));
invalid.union_ (tmp);
@@ -2359,109 +2457,25 @@ irange::snap_subranges ()
return changed;
}
-// If the mask can be trivially converted to a range, do so.
-// Otherwise attempt to remove the lower bits from the range.
-// Return true if the range changed in any way.
+// If the bitmask has a range representation, intersect this range with
+// the bitmasks range. Then ensure all enpoints match the bitmask.
+// Return TRUE if the range changes at all.
bool
irange::set_range_from_bitmask ()
{
gcc_checking_assert (!undefined_p ());
- if (m_bitmask.unknown_p ())
- return false;
-
- // If all the bits are known, this is a singleton.
- if (m_bitmask.mask () == 0)
- {
- // Make sure the singleton is within the range.
- if (contains_p (m_bitmask.value ()))
- set (m_type, m_bitmask.value (), m_bitmask.value ());
- else
- set_undefined ();
- return true;
- }
-
- unsigned popcount = wi::popcount (m_bitmask.get_nonzero_bits ());
-
- // If we have only one bit set in the mask, we can figure out the
- // range immediately.
- if (popcount == 1)
- {
- // Make sure we don't pessimize the range.
- if (!contains_p (m_bitmask.get_nonzero_bits ()))
- return false;
-
- bool has_zero = contains_zero_p (*this);
- wide_int nz = m_bitmask.get_nonzero_bits ();
- set (m_type, nz, nz);
- m_bitmask.set_nonzero_bits (nz);
- if (has_zero)
- {
- int_range<2> zero;
- zero.set_zero (m_type);
- union_ (zero);
- }
- if (flag_checking)
- verify_range ();
- return true;
- }
- else if (popcount == 0)
- {
- set_zero (m_type);
- return true;
- }
+ // Snap subranmges when bitmask is first set.
+ snap_subranges ();
+ if (undefined_p ())
+ return true;
- // If the mask doesn't have a trailing zero, theres nothing to filter.
- int z = wi::ctz (m_bitmask.mask ());
- if (!z)
+ // Calculate the set of ranges valid for the bitmask.
+ int_range_max allow;
+ if (!m_bitmask.range_from_mask (allow, m_type))
return false;
-
- int prec = TYPE_PRECISION (m_type);
- wide_int value = m_bitmask.value ();
- wide_int mask = m_bitmask.mask ();
-
- // Remove the [0, X] values which the trailing-zero mask rules out.
- // For example, if z == 4, the mask is 0xFFF0, and the lowest 4 bits
- // define the range [0, 15]. Only one of which (value & low_mask) is allowed.
- wide_int ub = (wi::one (prec) << z) - 1; // Upper bound of affected range.
- int_range_max mask_range (m_type, wi::zero (prec), ub);
-
- // Remove the one valid value from the excluded range and form an anti-range.
- wide_int allow = value & ub;
- mask_range.intersect (int_range<2> (m_type, allow, allow, VR_ANTI_RANGE));
-
- // Invert it to get the allowed values and intersect it with the main range.
- mask_range.invert ();
- bool changed = intersect (mask_range);
-
- // Now handle the rest of the domain — the upper side for positive values,
- // or [-X, -1] for signed negatives.
- // Compute the maximum value representable under the mask/value constraint.
- ub = mask | value;
-
- // If value is non-negative, adjust the upper limit to remove values above
- // UB that conflict with known fixed bits.
- if (TYPE_SIGN (m_type) == UNSIGNED || wi::clz (ub) > 0)
- mask_range = int_range<1> (m_type, wi::zero (prec), ub);
- else
- {
- // For signed negative values, find the lowest value with trailing zeros.
- // This forms a range such as [-512, -1] for z=9.
- wide_int lb = -(wi::one (prec) << z);
- mask_range = int_range<2> (m_type, lb, wi::minus_one (prec));
-
- // Remove the one allowed value from that set.
- allow = value | lb;
- mask_range.intersect (int_range<2> (m_type, allow, allow, VR_ANTI_RANGE));
- mask_range.invert ();
- }
-
- // Make sure we call intersect, so do it first.
- changed = intersect (mask_range) | changed;
- // Now make sure each subrange endpoint matches the bitmask.
- changed |= snap_subranges ();
-
- return changed;
+ // And intersect that set of ranges with the current set.
+ return intersect (allow);
}
void
@@ -2932,7 +2946,7 @@ test_irange_snap_bounds ()
tree u1 = build_nonstandard_integer_type (1, /*unsigned=*/ 1);
// Basic aligned range: even-only
- assert_snap_result (5, 15, 6, 14, 0xFFFFFFFE, 0x0, u32);
+ assert_snap_result (5, 15, 6, 14, 0xE, 0x0, u32);
// Singleton that doesn't match mask: undefined.
assert_snap_result (7, 7, 1, 0, 0xFFFFFFFE, 0x0, u32);
// 8-bit signed char, mask 0xF0 (i.e. step of 16).
@@ -3204,15 +3218,12 @@ range_tests_misc ()
static void
range_tests_nonzero_bits ()
{
- int_range<2> r0, r1;
+ int_range<8> r0, r1;
// Adding nonzero bits to a varying drops the varying.
r0.set_varying (integer_type_node);
r0.set_nonzero_bits (INT (255));
ASSERT_TRUE (!r0.varying_p ());
- // Dropping the nonzero bits brings us back to varying.
- r0.set_nonzero_bits (INT (-1));
- ASSERT_TRUE (r0.varying_p ());
// Test contains_p with nonzero bits.
r0.set_zero (integer_type_node);
@@ -3244,17 +3255,6 @@ range_tests_nonzero_bits ()
r0.intersect (r1);
ASSERT_TRUE (r0.get_nonzero_bits () == 0xff);
- // The union of a mask of 0xff..ffff00 with a mask of 0xff spans the
- // entire domain, and makes the range a varying.
- r0.set_varying (integer_type_node);
- wide_int x = wi::shwi (0xff, TYPE_PRECISION (integer_type_node));
- x = wi::bit_not (x);
- r0.set_nonzero_bits (x); // 0xff..ff00
- r1.set_varying (integer_type_node);
- r1.set_nonzero_bits (INT (0xff));
- r0.union_ (r1);
- ASSERT_TRUE (r0.varying_p ());
-
// Test that setting a nonzero bit of 1 does not pessimize the range.
r0.set_zero (integer_type_node);
r0.set_nonzero_bits (INT (1));