diff options
Diffstat (limited to 'gcc/value-range.cc')
-rw-r--r-- | gcc/value-range.cc | 93 |
1 files changed, 61 insertions, 32 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc index a770b41..ed3760f 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -31,25 +31,28 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "gimple-range.h" -// Return the bitmask inherent in a range. +// Return the bitmask inherent in a range : TYPE [MIN, MAX]. +// This use to be get_bitmask_from_range (). -static irange_bitmask -get_bitmask_from_range (tree type, - const wide_int &min, const wide_int &max) +irange_bitmask::irange_bitmask (tree type, + const wide_int &min, const wide_int &max) { unsigned prec = TYPE_PRECISION (type); - // All the bits of a singleton are known. if (min == max) { - wide_int mask = wi::zero (prec); - wide_int value = min; - return irange_bitmask (value, mask); + m_mask = wi::zero (prec); + m_value = min; + } + else + { + wide_int xorv = min ^ max; + // Mask will have leading zeros for all leading bits that are + // common, both zeros and ones. + m_mask = wi::mask (prec - wi::clz (xorv), false, prec); + // Now set value to those bits which are known, and zero the rest. + m_value = ~m_mask & min; } - - wide_int xorv = min ^ max; - xorv = wi::mask (prec - wi::clz (xorv), false, prec); - return irange_bitmask (wi::zero (prec), min | xorv); } void @@ -469,7 +472,7 @@ prange::set (tree type, const wide_int &min, const wide_int &max, } m_kind = VR_RANGE; - m_bitmask = get_bitmask_from_range (type, min, max); + m_bitmask = irange_bitmask (type, min, max); if (flag_checking) verify_range (); } @@ -583,7 +586,7 @@ prange::intersect (const vrange &v) } // Intersect all bitmasks: the old one, the new one, and the other operand's. - irange_bitmask new_bitmask = get_bitmask_from_range (m_type, m_min, m_max); + irange_bitmask new_bitmask (m_type, m_min, m_max); m_bitmask.intersect (new_bitmask); m_bitmask.intersect (r.m_bitmask); if (varying_compatible_p ()) @@ -2286,7 +2289,7 @@ irange::set_range_from_bitmask () if (has_zero) { int_range<2> zero; - zero.set_zero (type ()); + zero.set_zero (m_type); union_ (zero); } if (flag_checking) @@ -2295,31 +2298,58 @@ irange::set_range_from_bitmask () } else if (popcount == 0) { - set_zero (type ()); + set_zero (m_type); return true; } - // If the mask doesn't have any trailing zero, return. + // If the mask doesn't have a trailing zero, theres nothing to filter. int z = wi::ctz (m_bitmask.mask ()); if (!z) return false; - // Remove trailing ranges that this bitmask indicates can't exist. - int_range_max mask_range; - int prec = TYPE_PRECISION (type ()); - wide_int ub = (wi::one (prec) << z) - 1; - mask_range = int_range<2> (type (), wi::zero (prec), ub); + 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); - // Then remove the specific value these bits contain from the range. - wide_int value = m_bitmask.value () & ub; - mask_range.intersect (int_range<2> (type (), value, value, VR_ANTI_RANGE)); + // 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)); - // Inverting produces a list of ranges which can be valid. + // Invert it to get the allowed values and intersect it with the main range. mask_range.invert (); + bool changed = intersect (mask_range); - // And finally select R from only those valid values. - intersect (mask_range); - return true; + // 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; + return changed; } void @@ -2369,8 +2399,7 @@ irange::get_bitmask () const // in the mask. // // See also the note in irange_bitmask::intersect. - irange_bitmask bm - = get_bitmask_from_range (type (), lower_bound (), upper_bound ()); + irange_bitmask bm (type (), lower_bound (), upper_bound ()); if (!m_bitmask.unknown_p ()) bm.intersect (m_bitmask); return bm; @@ -2405,7 +2434,7 @@ irange::intersect_bitmask (const irange &r) { gcc_checking_assert (!undefined_p () && !r.undefined_p ()); - if (r.m_bitmask.unknown_p () || m_bitmask == r.m_bitmask) + if (m_bitmask == r.m_bitmask) return false; irange_bitmask bm = get_bitmask (); |