diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/range-op-float.cc | 79 | ||||
-rw-r--r-- | gcc/value-query.cc | 9 | ||||
-rw-r--r-- | gcc/value-range-pretty-print.cc | 14 | ||||
-rw-r--r-- | gcc/value-range-storage.cc | 12 | ||||
-rw-r--r-- | gcc/value-range.cc | 462 | ||||
-rw-r--r-- | gcc/value-range.h | 88 |
6 files changed, 585 insertions, 79 deletions
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index ff9fe31..ca41136 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -150,6 +150,18 @@ range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) cons return VREL_VARYING; } +// Set R to [NAN, NAN]. + +static inline void +frange_set_nan (frange &r, tree type) +{ + REAL_VALUE_TYPE rv; + bool res = real_nan (&rv, "", 1, TYPE_MODE (type)); + if (flag_checking) + gcc_assert (res); + r.set (type, rv, rv); +} + // Return TRUE if OP1 and OP2 are known to be free of NANs. static inline bool @@ -178,6 +190,40 @@ frelop_early_resolve (irange &r, tree type, && relop_early_resolve (r, type, op1, op2, rel, my_rel)); } +// Crop R to [-INF, MAX] where MAX is the maximum representable number +// for TYPE. + +static inline void +frange_drop_inf (frange &r, tree type) +{ + // FIXME: build_real() bails on decimal float modes when called with + // a max representable endpoint. + if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))) + return; + + REAL_VALUE_TYPE max; + real_max_representable (&max, type); + frange tmp (type, r.lower_bound (), max); + r.intersect (tmp); +} + +// Crop R to [MIN, +INF] where MIN is the minimum representable number +// for TYPE. + +static inline void +frange_drop_ninf (frange &r, tree type) +{ + // FIXME: build_real() bails on decimal float modes when called with + // a max representable endpoint. + if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))) + return; + + REAL_VALUE_TYPE min; + real_min_representable (&min, type); + frange tmp (type, min, r.upper_bound ()); + r.intersect (tmp); +} + // Default implementation of fold_range for relational operators. // This amounts to passing on any known relations from the oracle, iff // we know the operands are not NAN or -ffinite-math-only holds. @@ -252,21 +298,8 @@ foperator_equal::op1_range (frange &r, tree type, switch (get_bool_state (r, lhs, type)) { case BRS_TRUE: - if (HONOR_SIGNED_ZEROS (type) - && op2.contains_p (build_zero_cst (type))) - { - // With signed zeros, x == -0.0 does not mean we can replace - // x with -0.0, because x may be either +0.0 or -0.0. - r.set_varying (type); - } - else - { - // If it's true, the result is the same as OP2. - // - // If the range does not actually contain zeros, this should - // always be OK. - r = op2; - } + // If it's true, the result is the same as OP2. + r = op2; // The TRUE side of op1 == op2 implies op1 is !NAN. r.set_nan (fp_prop::NO); break; @@ -275,7 +308,7 @@ foperator_equal::op1_range (frange &r, tree type, r.set_varying (type); // The FALSE side of op1 == op1 implies op1 is a NAN. if (rel == VREL_EQ) - r.set_nan (fp_prop::YES); + frange_set_nan (r, type); break; default: @@ -365,7 +398,8 @@ foperator_lt::op1_range (frange &r, r.set_varying (type); // The TRUE side of op1 < op2 implies op1 is !NAN and !INF. r.set_nan (fp_prop::NO); - r.set_inf (fp_prop::NO); + // x < y implies x is not +INF. + frange_drop_inf (r, type); break; case BRS_FALSE: @@ -391,7 +425,8 @@ foperator_lt::op2_range (frange &r, r.set_varying (type); // The TRUE side of op1 < op2 implies op2 is !NAN and !NINF. r.set_nan (fp_prop::NO); - r.set_ninf (fp_prop::NO); + // x < y implies y is not -INF. + frange_drop_ninf (r, type); break; case BRS_FALSE: @@ -493,7 +528,8 @@ foperator_gt::op1_range (frange &r, r.set_varying (type); // The TRUE side of op1 > op2 implies op1 is !NAN and !NINF. r.set_nan (fp_prop::NO); - r.set_ninf (fp_prop::NO); + // x > y implies x is not -INF. + frange_drop_ninf (r, type); break; case BRS_FALSE: @@ -519,7 +555,8 @@ foperator_gt::op2_range (frange &r, r.set_varying (type); // The TRUE side of op1 > op2 implies op2 is !NAN and !INF. r.set_nan (fp_prop::NO); - r.set_inf (fp_prop::NO); + // x > y implies y is not +INF. + frange_drop_inf (r, type); break; case BRS_FALSE: @@ -636,7 +673,7 @@ foperator_unordered::op1_range (frange &r, tree type, // Since at least one operand must be NAN, if one of them is // not, the other must be. if (op2.get_nan ().no_p ()) - r.set_nan (fp_prop::YES); + frange_set_nan (r, type); break; case BRS_FALSE: diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 4af8eca..4637fb4 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -211,10 +211,19 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt) switch (TREE_CODE (expr)) { case INTEGER_CST: + if (TREE_OVERFLOW_P (expr)) + expr = drop_tree_overflow (expr); + r.set (expr, expr); + return true; + case REAL_CST: if (TREE_OVERFLOW_P (expr)) expr = drop_tree_overflow (expr); r.set (expr, expr); + if (real_isnan (TREE_REAL_CST_PTR (expr))) + as_a <frange> (r).set_nan (fp_prop::YES); + else + as_a <frange> (r).set_nan (fp_prop::NO); return true; case SSA_NAME: diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc index cbf50d3..e66d56d 100644 --- a/gcc/value-range-pretty-print.cc +++ b/gcc/value-range-pretty-print.cc @@ -122,22 +122,30 @@ vrange_printer::print_irange_bitmasks (const irange &r) const void vrange_printer::visit (const frange &r) const { + tree type = r.type (); + pp_string (pp, "[frange] "); if (r.undefined_p ()) { pp_string (pp, "UNDEFINED"); return; } - dump_generic_node (pp, r.type (), 0, TDF_NONE, false); + dump_generic_node (pp, type, 0, TDF_NONE, false); pp_string (pp, " "); if (r.varying_p ()) { pp_string (pp, "VARYING"); return; } + pp_character (pp, '['); + dump_generic_node (pp, + build_real (type, r.lower_bound ()), 0, TDF_NONE, false); + pp_string (pp, ", "); + dump_generic_node (pp, + build_real (type, r.upper_bound ()), 0, TDF_NONE, false); + pp_string (pp, "] "); + print_frange_prop ("NAN", r.get_nan ()); - print_frange_prop ("INF", r.get_inf ()); - print_frange_prop ("NINF", r.get_ninf ()); } // Print the FP properties in an frange. diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index ea3b83c..adf23c3 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -261,6 +261,18 @@ frange_storage_slot::get_frange (frange &r, tree type) const { gcc_checking_assert (r.supports_type_p (type)); + // FIXME: NANs get special treatment, because we need [NAN, NAN] in + // the range to properly represent it, not just the NAN flag in the + // property bits. This will go away when we stream out the + // endpoints. + if (m_props.get_nan ().yes_p ()) + { + REAL_VALUE_TYPE rv; + real_nan (&rv, "", 1, TYPE_MODE (type)); + r.set (type, rv, rv); + return; + } + r.set_varying (type); r.m_props = m_props; r.normalize_kind (); diff --git a/gcc/value-range.cc b/gcc/value-range.cc index edd10bf..bcc6651 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -291,41 +291,20 @@ frange::set (tree min, tree max, value_range_kind kind) m_kind = kind; m_type = TREE_TYPE (min); m_props.set_varying (); + m_min = *TREE_REAL_CST_PTR (min); + m_max = *TREE_REAL_CST_PTR (max); - bool is_min = vrp_val_is_min (min); - bool is_max = vrp_val_is_max (max); bool is_nan = (real_isnan (TREE_REAL_CST_PTR (min)) || real_isnan (TREE_REAL_CST_PTR (max))); // Ranges with a NAN and a non-NAN endpoint are nonsensical. gcc_checking_assert (!is_nan || operand_equal_p (min, max)); - // The properties for singletons can be all set ahead of time. - if (operand_equal_p (min, max)) - { - // Set INF properties. - if (is_min) - m_props.ninf_set_yes (); - else - m_props.ninf_set_no (); - if (is_max) - m_props.inf_set_yes (); - else - m_props.inf_set_no (); - // Set NAN property. - if (is_nan) - m_props.nan_set_yes (); - else - m_props.nan_set_no (); - } - else - { - // Mark when the endpoints can't be +-INF. - if (!is_min) - m_props.ninf_set_no (); - if (!is_max) - m_props.inf_set_no (); - } + // Set NAN property if we're absolutely sure. + if (is_nan && operand_equal_p (min, max)) + m_props.nan_set_yes (); + else if (!HONOR_NANS (m_type)) + m_props.nan_set_no (); // Check for swapped ranges. gcc_checking_assert (is_nan || tree_compare (LE_EXPR, min, max)); @@ -336,6 +315,16 @@ frange::set (tree min, tree max, value_range_kind kind) verify_range (); } +// Setter for frange from REAL_VALUE_TYPE endpoints. + +void +frange::set (tree type, + const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max, + value_range_kind kind) +{ + set (build_real (type, min), build_real (type, max), kind); +} + // Normalize range to VARYING or UNDEFINED, or vice versa. Return // TRUE if anything changed. // @@ -347,7 +336,15 @@ frange::set (tree min, tree max, value_range_kind kind) bool frange::normalize_kind () { - if (m_kind == VR_RANGE) + // Undefined is viral. + if (m_props.nan_undefined_p ()) + { + set_undefined (); + return true; + } + if (m_kind == VR_RANGE + && real_isinf (&m_min, 1) + && real_isinf (&m_max, 0)) { // No FP properties set means varying. if (m_props.varying_p ()) @@ -355,14 +352,6 @@ frange::normalize_kind () set_varying (m_type); return true; } - // Undefined is viral. - if (m_props.nan_undefined_p () - || m_props.inf_undefined_p () - || m_props.ninf_undefined_p ()) - { - set_undefined (); - return true; - } } else if (m_kind == VR_VARYING) { @@ -370,12 +359,32 @@ frange::normalize_kind () if (!m_props.varying_p ()) { m_kind = VR_RANGE; + real_inf (&m_min, 1); + real_inf (&m_max, 0); return true; } } return false; } +// If both operands are definitely NAN, do nothing as they combine +// perfectly. If OTOH, only one is a NAN, set R to VARYING as they +// can't be neither unioned nor intersected. Return TRUE if we +// changed anything. + +static inline bool +early_nan_resolve (frange &r, const frange &other) +{ + gcc_checking_assert (r.get_nan ().yes_p () || other.get_nan ().yes_p ()); + + // There's nothing to do for both NANs. + if (r.get_nan ().yes_p () == other.get_nan ().yes_p ()) + return false; + // But only one NAN complicates things. + r.set_varying (r.type ()); + return true; +} + bool frange::union_ (const vrange &v) { @@ -388,13 +397,34 @@ frange::union_ (const vrange &v) *this = r; return true; } + // ?? We could do better here. [5,6] U NAN should be [5,6] with the + // NAN maybe bits set. For now, this is conservatively correct. + if (get_nan ().yes_p () || r.get_nan ().yes_p ()) + return early_nan_resolve (*this, r); - bool ret = m_props.union_ (r.m_props); - ret |= normalize_kind (); + bool changed = m_props.union_ (r.m_props); + + // Note: for the combination of zeros that differ in sign we keep + // the endpoints untouched. This means that for -0.0 U +0.0, the + // result will be -0.0. Ultimately this doesn't matter, because we + // keep singleton zeros ambiguous throughout to avoid propagating + // them. See frange::singleton_p(). + + if (real_less (&r.m_min, &m_min)) + { + m_min = r.m_min; + changed = true; + } + if (real_less (&m_max, &r.m_max)) + { + m_max = r.m_max; + changed = true; + } + changed |= normalize_kind (); if (flag_checking) verify_range (); - return ret; + return changed; } bool @@ -414,13 +444,38 @@ frange::intersect (const vrange &v) *this = r; return true; } + if (get_nan ().yes_p () || r.get_nan ().yes_p ()) + return early_nan_resolve (*this, r); + + bool changed = m_props.intersect (r.m_props); + + // Note: for the combination of zeros that differ in sign we keep + // the endpoints untouched. This means that for -0.0 ^ +0.0, the + // result will be -0.0. Ultimately this doesn't matter, because we + // keep singleton zeros ambiguous throughout to avoid propagating + // them. See frange::singleton_p(). - bool ret = m_props.intersect (r.m_props); - ret |= normalize_kind (); + if (real_less (&m_min, &r.m_min)) + { + m_min = r.m_min; + changed = true; + } + if (real_less (&r.m_max, &m_max)) + { + m_max = r.m_max; + changed = true; + } + // If the endpoints are swapped, the ranges are disjoint. + if (real_less (&m_max, &m_min)) + { + set_undefined (); + return true; + } + changed |= normalize_kind (); if (flag_checking) verify_range (); - return ret; + return changed; } frange & @@ -428,6 +483,8 @@ frange::operator= (const frange &src) { m_kind = src.m_kind; m_type = src.m_type; + m_min = src.m_min; + m_max = src.m_max; m_props = src.m_props; if (flag_checking) @@ -446,7 +503,59 @@ frange::operator== (const frange &src) const if (varying_p ()) return types_compatible_p (m_type, src.m_type); - return m_props == src.m_props; + if (m_props.get_nan ().yes_p () + || src.m_props.get_nan ().yes_p ()) + return false; + + return (real_identical (&m_min, &src.m_min) + && real_identical (&m_max, &src.m_max) + && m_props == src.m_props + && types_compatible_p (m_type, src.m_type)); + } + return false; +} + +// Return TRUE if range contains the TREE_REAL_CST_PTR in CST. + +bool +frange::contains_p (tree cst) const +{ + if (undefined_p ()) + return false; + + if (varying_p ()) + return true; + + gcc_checking_assert (m_kind == VR_RANGE); + + return (real_compare (GE_EXPR, TREE_REAL_CST_PTR (cst), &m_min) + && real_compare (LE_EXPR, TREE_REAL_CST_PTR (cst), &m_max)); +} + +// If range is a singleton, place it in RESULT and return TRUE. If +// RESULT is NULL, just return TRUE. +// +// A NAN can never be a singleton, and neither can a 0.0 if we're +// honoring signed zeros because we have no way of telling which zero +// it is. + +bool +frange::singleton_p (tree *result) const +{ + if (m_kind == VR_RANGE && real_identical (&m_min, &m_max)) + { + // If we're honoring signed zeros, fail because we don't know + // which zero we have. This avoids propagating the wrong zero. + if (HONOR_SIGNED_ZEROS (m_type) && zero_p ()) + return false; + + // Return false for any singleton that may be a NAN. + if (HONOR_NANS (m_type) && !get_nan ().no_p ()) + return false; + + if (result) + *result = build_real (m_type, m_min); + return true; } return false; } @@ -465,13 +574,82 @@ frange::verify_range () gcc_checking_assert (m_props.undefined_p ()); return; } + gcc_checking_assert (!m_props.undefined_p ()); + if (varying_p ()) { gcc_checking_assert (m_props.varying_p ()); return; } + + // We don't support the inverse of an frange (yet). gcc_checking_assert (m_kind == VR_RANGE); - gcc_checking_assert (!m_props.varying_p () && !m_props.undefined_p ()); + + bool is_nan = real_isnan (&m_min) || real_isnan (&m_max); + if (is_nan) + { + // If either is a NAN, both must be a NAN. + gcc_checking_assert (real_identical (&m_min, &m_max)); + gcc_checking_assert (get_nan ().yes_p ()); + } + else + // Make sure we don't have swapped ranges. + gcc_checking_assert (!real_less (&m_max, &m_min)); + + // If we're absolutely sure we have a NAN, the endpoints should + // reflect this, otherwise we'd have more than one way to represent + // a NAN. + if (m_props.get_nan ().yes_p ()) + { + gcc_checking_assert (real_isnan (&m_min)); + gcc_checking_assert (real_isnan (&m_max)); + } + + // If all the properties are clear, we better not span the entire + // domain, because that would make us varying. + if (m_props.varying_p ()) + gcc_checking_assert (!real_isinf (&m_min, 1) || !real_isinf (&m_max, 0)); +} + +// We can't do much with nonzeros yet. +void +frange::set_nonzero (tree type) +{ + set_varying (type); +} + +// We can't do much with nonzeros yet. +bool +frange::nonzero_p () const +{ + return false; +} + +// Set range to [+0.0, +0.0]. + +void +frange::set_zero (tree type) +{ + tree zero = build_zero_cst (type); + set (zero, zero); +} + +// Return TRUE for any [0.0, 0.0] regardless of sign. + +bool +frange::zero_p () const +{ + return (m_kind == VR_RANGE + && real_iszero (&m_min) + && real_iszero (&m_max)); +} + +void +frange::set_nonnegative (tree type) +{ + tree zero = build_zero_cst (type); + tree inf = vrp_val_max (type); + set (zero, inf); } // Here we copy between any two irange's. The ranges can be legacy or @@ -3304,6 +3482,199 @@ range_tests_nonzero_bits () ASSERT_TRUE (r0.varying_p ()); } +// Build an frange from string endpoints. + +static inline frange +frange_float (const char *lb, const char *ub, tree type = float_type_node) +{ + REAL_VALUE_TYPE min, max; + gcc_assert (real_from_string (&min, lb) == 0); + gcc_assert (real_from_string (&max, ub) == 0); + return frange (type, min, max); +} + +// Build a NAN of type TYPE. + +static inline frange +frange_nan (tree type = float_type_node) +{ + REAL_VALUE_TYPE r; + + gcc_assert (real_nan (&r, "", 1, TYPE_MODE (type))); + return frange (type, r, r); +} + +static void +range_tests_nan () +{ + frange r0, r1; + + // Equal ranges but with differing NAN bits are not equal. + r1 = frange_float ("10", "12"); + r0 = r1; + ASSERT_EQ (r0, r1); + r0.set_nan (fp_prop::NO); + ASSERT_NE (r0, r1); + r0.set_nan (fp_prop::YES); + ASSERT_NE (r0, r1); + r0.set_nan (fp_prop::VARYING); + ASSERT_EQ (r0, r1); + + // NAN ranges are not equal to each other. + r0 = frange_nan (); + r1 = r0; + ASSERT_FALSE (r0 == r1); + ASSERT_FALSE (r0 == r0); + ASSERT_TRUE (r0 != r0); + + // Make sure that combining NAN and INF doesn't give any crazy results. + r0 = frange_nan (); + ASSERT_TRUE (r0.get_nan ().yes_p ()); + r1 = frange_float ("+Inf", "+Inf"); + r0.union_ (r1); + // [INF, INF] U NAN = VARYING + ASSERT_TRUE (r0.varying_p ()); + + // [INF, INF] ^ NAN = VARYING + r0 = frange_nan (); + r1 = frange_float ("+Inf", "+Inf"); + r0.intersect (r1); + ASSERT_TRUE (r0.varying_p ()); + + // NAN ^ NAN = NAN + r0 = frange_nan (); + r1 = frange_nan (); + r0.intersect (r1); + ASSERT_TRUE (r0.get_nan ().yes_p ()); + + // VARYING ^ NAN = NAN. + r0 = frange_nan (); + r1.set_varying (float_type_node); + r0.intersect (r1); + ASSERT_TRUE (r0.get_nan ().yes_p ()); +} + +static void +range_tests_signed_zeros () +{ + tree zero = build_zero_cst (float_type_node); + tree neg_zero = fold_build1 (NEGATE_EXPR, float_type_node, zero); + frange r0, r1; + + // ?? If -0.0 == +0.0, then a range of [-0.0, -0.0] should + // contain +0.0 and vice versa. We probably need a property to + // track signed zeros in the frange like we do for NAN, to + // properly model all this. + r0 = frange (zero, zero); + r1 = frange (neg_zero, neg_zero); + ASSERT_TRUE (r0.contains_p (zero)); + ASSERT_TRUE (r0.contains_p (neg_zero)); + ASSERT_TRUE (r1.contains_p (zero)); + ASSERT_TRUE (r1.contains_p (neg_zero)); +} + +static void +range_tests_floats () +{ + frange r0, r1; + + range_tests_nan (); + + if (HONOR_SIGNED_ZEROS (float_type_node)) + range_tests_signed_zeros (); + + // A range of [-INF,+INF] is actually VARYING... + r0 = frange_float ("-Inf", "+Inf"); + ASSERT_TRUE (r0.varying_p ()); + // ...unless it has some special property... + r0.set_nan (fp_prop::NO); + ASSERT_FALSE (r0.varying_p ()); + + // The endpoints of a VARYING are +-INF. + REAL_VALUE_TYPE inf, ninf; + real_inf (&inf, 0); + real_inf (&ninf, 1); + r0.set_varying (float_type_node); + ASSERT_TRUE (real_identical (&r0.lower_bound (), &ninf)); + ASSERT_TRUE (real_identical (&r0.upper_bound (), &inf)); + + // The maximum representable range for a type is still a subset of VARYING. + REAL_VALUE_TYPE q, r; + real_min_representable (&q, float_type_node); + real_max_representable (&r, float_type_node); + r0 = frange (float_type_node, q, r); + // r0 is not a varying, because it does not include -INF/+INF. + ASSERT_FALSE (r0.varying_p ()); + // The upper bound of r0 must be less than +INF. + ASSERT_TRUE (real_less (&r0.upper_bound (), &inf)); + // The lower bound of r0 must be greater than -INF. + ASSERT_TRUE (real_less (&ninf, &r0.lower_bound ())); + + // For most architectures, where float and double are different + // sizes, having the same endpoints does not necessarily mean the + // ranges are equal. + if (!types_compatible_p (float_type_node, double_type_node)) + { + r0 = frange_float ("3.0", "3.0", float_type_node); + r1 = frange_float ("3.0", "3.0", double_type_node); + ASSERT_NE (r0, r1); + } + + // [3,5] U [10,12] = [3,12]. + r0 = frange_float ("3", "5"); + r1 = frange_float ("10", "12"); + r0.union_ (r1); + ASSERT_EQ (r0, frange_float ("3", "12")); + + // [5,10] U [4,8] = [4,10] + r0 = frange_float ("5", "10"); + r1 = frange_float ("4", "8"); + r0.union_ (r1); + ASSERT_EQ (r0, frange_float ("4", "10")); + + // [3,5] U [4,10] = [3,10] + r0 = frange_float ("3", "5"); + r1 = frange_float ("4", "10"); + r0.union_ (r1); + ASSERT_EQ (r0, frange_float ("3", "10")); + + // [4,10] U [5,11] = [4,11] + r0 = frange_float ("4", "10"); + r1 = frange_float ("5", "11"); + r0.union_ (r1); + ASSERT_EQ (r0, frange_float ("4", "11")); + + // [3,12] ^ [10,12] = [10,12]. + r0 = frange_float ("3", "12"); + r1 = frange_float ("10", "12"); + r0.intersect (r1); + ASSERT_EQ (r0, frange_float ("10", "12")); + + // [10,12] ^ [11,11] = [11,11] + r0 = frange_float ("10", "12"); + r1 = frange_float ("11", "11"); + r0.intersect (r1); + ASSERT_EQ (r0, frange_float ("11", "11")); + + // [10,20] ^ [5,15] = [10,15] + r0 = frange_float ("10", "20"); + r1 = frange_float ("5", "15"); + r0.intersect (r1); + ASSERT_EQ (r0, frange_float ("10", "15")); + + // [10,20] ^ [15,25] = [15,20] + r0 = frange_float ("10", "20"); + r1 = frange_float ("15", "25"); + r0.intersect (r1); + ASSERT_EQ (r0, frange_float ("15", "20")); + + // [10,20] ^ [21,25] = [] + r0 = frange_float ("10", "20"); + r1 = frange_float ("21", "25"); + r0.intersect (r1); + ASSERT_TRUE (r0.undefined_p ()); +} + void range_tests () { @@ -3312,6 +3683,7 @@ range_tests () range_tests_int_range_max (); range_tests_strict_enum (); range_tests_nonzero_bits (); + range_tests_floats (); range_tests_misc (); } diff --git a/gcc/value-range.h b/gcc/value-range.h index f0075d0..43b231b 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -314,14 +314,10 @@ public: bool intersect (const frange_props &other); bool operator== (const frange_props &other) const; FP_PROP_ACCESSOR(nan) - FP_PROP_ACCESSOR(inf) - FP_PROP_ACCESSOR(ninf) private: union { struct { unsigned char nan : 2; - unsigned char inf : 2; - unsigned char ninf : 2; } bits; unsigned char bytes; } u; @@ -345,34 +341,62 @@ class frange : public vrange public: frange (); frange (const frange &); + frange (tree, tree, value_range_kind = VR_RANGE); + frange (tree type, const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max, + value_range_kind = VR_RANGE); static bool supports_p (const_tree type) { return SCALAR_FLOAT_TYPE_P (type); } virtual tree type () const override; virtual void set (tree, tree, value_range_kind = VR_RANGE) override; + void set (tree type, const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &, + value_range_kind = VR_RANGE); virtual void set_varying (tree type) override; virtual void set_undefined () override; virtual bool union_ (const vrange &) override; virtual bool intersect (const vrange &) override; + virtual bool contains_p (tree) const override; + virtual bool singleton_p (tree *result = NULL) const override; virtual bool supports_type_p (const_tree type) const override; virtual void accept (const vrange_visitor &v) const override; + virtual bool zero_p () const; + virtual bool nonzero_p () const; + virtual void set_nonzero (tree type); + virtual void set_zero (tree type); + virtual void set_nonnegative (tree type); frange& operator= (const frange &); bool operator== (const frange &) const; bool operator!= (const frange &r) const { return !(*this == r); } + const REAL_VALUE_TYPE &lower_bound () const; + const REAL_VALUE_TYPE &upper_bound () const; // Each fp_prop can be accessed with get_PROP() and set_PROP(). FRANGE_PROP_ACCESSOR(nan) - FRANGE_PROP_ACCESSOR(inf) - FRANGE_PROP_ACCESSOR(ninf) private: void verify_range (); bool normalize_kind (); frange_props m_props; tree m_type; + REAL_VALUE_TYPE m_min; + REAL_VALUE_TYPE m_max; }; +inline const REAL_VALUE_TYPE & +frange::lower_bound () const +{ + gcc_checking_assert (!undefined_p ()); + return m_min; +} + +inline const REAL_VALUE_TYPE & +frange::upper_bound () const +{ + gcc_checking_assert (!undefined_p ()); + return m_max; +} + // is_a<> and as_a<> implementation for vrange. // Anything we haven't specialized is a hard fail. @@ -1050,10 +1074,9 @@ vrp_val_min (const_tree type) return build_zero_cst (const_cast<tree> (type)); if (frange::supports_p (type)) { - REAL_VALUE_TYPE real, real_ninf; - real_inf (&real); - real_ninf = real_value_negate (&real); - return build_real (const_cast <tree> (type), real_ninf); + REAL_VALUE_TYPE ninf; + real_inf (&ninf, 1); + return build_real (const_cast <tree> (type), ninf); } return NULL_TREE; } @@ -1096,6 +1119,26 @@ frange::frange (const frange &src) *this = src; } +// frange constructor from REAL_VALUE_TYPE endpoints. + +inline +frange::frange (tree type, + const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max, + value_range_kind kind) +{ + m_discriminator = VR_FRANGE; + set (type, min, max, kind); +} + +// frange constructor from trees. + +inline +frange::frange (tree min, tree max, value_range_kind kind) +{ + m_discriminator = VR_FRANGE; + set (min, max, kind); +} + inline tree frange::type () const { @@ -1107,6 +1150,8 @@ frange::set_varying (tree type) { m_kind = VR_VARYING; m_type = type; + real_inf (&m_min, 1); + real_inf (&m_max, 0); m_props.set_varying (); } @@ -1116,6 +1161,29 @@ frange::set_undefined () m_kind = VR_UNDEFINED; m_type = NULL; m_props.set_undefined (); + memset (&m_min, 0, sizeof (m_min)); + memset (&m_max, 0, sizeof (m_max)); +} + +// Set R to maximum representable value for TYPE. + +inline void +real_max_representable (REAL_VALUE_TYPE *r, tree type) +{ + char buf[128]; + get_max_float (REAL_MODE_FORMAT (TYPE_MODE (type)), + buf, sizeof (buf), false); + int res = real_from_string (r, buf); + gcc_checking_assert (!res); +} + +// Set R to minimum representable value for TYPE. + +inline void +real_min_representable (REAL_VALUE_TYPE *r, tree type) +{ + real_max_representable (r, type); + *r = real_value_negate (r); } #endif // GCC_VALUE_RANGE_H |