diff options
author | Andrew MacLeod <amacleod@redhat.com> | 2023-06-09 13:47:09 -0400 |
---|---|---|
committer | Andrew MacLeod <amacleod@redhat.com> | 2023-06-09 20:33:03 -0400 |
commit | a13c4440949f300eacb9918b554ead6a5760dc50 (patch) | |
tree | 7535ccaffd3c0831a8b377942ebaa17087ddcd0b /gcc/range-op-float.cc | |
parent | 56518befc2663ddc082e34dddd66b6334a3d4da5 (diff) | |
download | gcc-a13c4440949f300eacb9918b554ead6a5760dc50.zip gcc-a13c4440949f300eacb9918b554ead6a5760dc50.tar.gz gcc-a13c4440949f300eacb9918b554ead6a5760dc50.tar.bz2 |
Unify MULT_EXPR range operator
Move the declaration of the class to the range-op-mixed header, add the
floating point prototypes as well, and use it in the new unified table.
* range-op-float.cc (foperator_mult_div_base): Delete.
(foperator_mult_div_base::find_range): Make static local function.
(foperator_mult): Remove. Move prototypes to range-op-mixed.h
(operator_mult::op1_range): Rename from foperator_mult.
(operator_mult::op2_range): Ditto.
(operator_mult::rv_fold): Ditto.
(float_table::float_table): Remove MULT_EXPR.
(class foperator_div): Inherit from range_operator.
(float_table::float_table): Delete.
* range-op-mixed.h (class operator_mult): Combined from integer
and float files.
* range-op.cc (float_tree_table): Delete.
(op_mult): New object.
(unified_table::unified_table): Add MULT_EXPR.
(get_op_handler): Do not check float table any longer.
(class cross_product_operator): Move to range-op-mixed.h.
(class operator_mult): Move to range-op-mixed.h.
(integral_table::integral_table): Remove MULT_EXPR.
(pointer_table::pointer_table): Remove MULT_EXPR.
* range-op.h (float_table): Remove.
Diffstat (limited to 'gcc/range-op-float.cc')
-rw-r--r-- | gcc/range-op-float.cc | 349 |
1 files changed, 169 insertions, 180 deletions
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 20b4b9f..757484a 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -2331,188 +2331,182 @@ operator_minus::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, } -class foperator_mult_div_base : public range_operator -{ -protected: - // Given CP[0] to CP[3] floating point values rounded to -INF, - // set LB to the smallest of them (treating -0 as smaller to +0). - // Given CP[4] to CP[7] floating point values rounded to +INF, - // set UB to the largest of them (treating -0 as smaller to +0). - static void find_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - const REAL_VALUE_TYPE (&cp)[8]) - { - lb = cp[0]; - ub = cp[4]; - for (int i = 1; i < 4; ++i) - { - if (real_less (&cp[i], &lb) - || (real_iszero (&lb) && real_isnegzero (&cp[i]))) - lb = cp[i]; - if (real_less (&ub, &cp[i + 4]) - || (real_isnegzero (&ub) && real_iszero (&cp[i + 4]))) - ub = cp[i + 4]; - } - } -}; +// Given CP[0] to CP[3] floating point values rounded to -INF, +// set LB to the smallest of them (treating -0 as smaller to +0). +// Given CP[4] to CP[7] floating point values rounded to +INF, +// set UB to the largest of them (treating -0 as smaller to +0). + +static void +find_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + const REAL_VALUE_TYPE (&cp)[8]) +{ + lb = cp[0]; + ub = cp[4]; + for (int i = 1; i < 4; ++i) + { + if (real_less (&cp[i], &lb) + || (real_iszero (&lb) && real_isnegzero (&cp[i]))) + lb = cp[i]; + if (real_less (&ub, &cp[i + 4]) + || (real_isnegzero (&ub) && real_iszero (&cp[i + 4]))) + ub = cp[i + 4]; + } +} -class foperator_mult : public foperator_mult_div_base +bool +operator_mult::op1_range (frange &r, tree type, + const frange &lhs, const frange &op2, + relation_trio) const { - using range_operator::op1_range; - using range_operator::op2_range; -public: - virtual bool op1_range (frange &r, tree type, - const frange &lhs, - const frange &op2, - relation_trio = TRIO_VARYING) const final override - { - if (lhs.undefined_p ()) - return false; - range_op_handler rdiv (RDIV_EXPR, type); - if (!rdiv) - return false; - frange wlhs = float_widen_lhs_range (type, lhs); - bool ret = rdiv.fold_range (r, type, wlhs, op2); - if (ret == false) - return false; - if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) - return float_binary_op_range_finish (ret, r, type, wlhs); - const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); - const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); - const REAL_VALUE_TYPE &op2_lb = op2.lower_bound (); - const REAL_VALUE_TYPE &op2_ub = op2.upper_bound (); - if ((contains_zero_p (lhs_lb, lhs_ub) && contains_zero_p (op2_lb, op2_ub)) - || ((real_isinf (&lhs_lb) || real_isinf (&lhs_ub)) - && (real_isinf (&op2_lb) || real_isinf (&op2_ub)))) - { - // If both lhs and op2 could be zeros or both could be infinities, - // we don't know anything about op1 except maybe for the sign - // and perhaps if it can be NAN or not. - REAL_VALUE_TYPE lb, ub; - int signbit_known = signbit_known_p (lhs_lb, lhs_ub, op2_lb, op2_ub); - zero_to_inf_range (lb, ub, signbit_known); - r.set (type, lb, ub); - } - // Otherwise, if op2 is a singleton INF and lhs doesn't include INF, - // or if lhs must be zero and op2 doesn't include zero, it would be - // UNDEFINED, while rdiv.fold_range computes a zero or singleton INF - // range. Those are supersets of UNDEFINED, so let's keep that way. + if (lhs.undefined_p ()) + return false; + range_op_handler rdiv (RDIV_EXPR, type); + if (!rdiv) + return false; + frange wlhs = float_widen_lhs_range (type, lhs); + bool ret = rdiv.fold_range (r, type, wlhs, op2); + if (ret == false) + return false; + if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) return float_binary_op_range_finish (ret, r, type, wlhs); - } - virtual bool op2_range (frange &r, tree type, - const frange &lhs, - const frange &op1, - relation_trio = TRIO_VARYING) const final override - { - return op1_range (r, type, lhs, op1); - } -private: - void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, bool &maybe_nan, - tree type, - const REAL_VALUE_TYPE &lh_lb, - const REAL_VALUE_TYPE &lh_ub, - const REAL_VALUE_TYPE &rh_lb, - const REAL_VALUE_TYPE &rh_ub, - relation_kind kind) const final override - { - bool is_square - = (kind == VREL_EQ - && real_equal (&lh_lb, &rh_lb) - && real_equal (&lh_ub, &rh_ub) - && real_isneg (&lh_lb) == real_isneg (&rh_lb) - && real_isneg (&lh_ub) == real_isneg (&rh_ub)); + const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); + const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); + const REAL_VALUE_TYPE &op2_lb = op2.lower_bound (); + const REAL_VALUE_TYPE &op2_ub = op2.upper_bound (); + if ((contains_zero_p (lhs_lb, lhs_ub) && contains_zero_p (op2_lb, op2_ub)) + || ((real_isinf (&lhs_lb) || real_isinf (&lhs_ub)) + && (real_isinf (&op2_lb) || real_isinf (&op2_ub)))) + { + // If both lhs and op2 could be zeros or both could be infinities, + // we don't know anything about op1 except maybe for the sign + // and perhaps if it can be NAN or not. + REAL_VALUE_TYPE lb, ub; + int signbit_known = signbit_known_p (lhs_lb, lhs_ub, op2_lb, op2_ub); + zero_to_inf_range (lb, ub, signbit_known); + r.set (type, lb, ub); + } + // Otherwise, if op2 is a singleton INF and lhs doesn't include INF, + // or if lhs must be zero and op2 doesn't include zero, it would be + // UNDEFINED, while rdiv.fold_range computes a zero or singleton INF + // range. Those are supersets of UNDEFINED, so let's keep that way. + return float_binary_op_range_finish (ret, r, type, wlhs); +} - maybe_nan = false; - // x * x never produces a new NAN and we only multiply the same - // values, so the 0 * INF problematic cases never appear there. - if (!is_square) - { - // [+-0, +-0] * [+INF,+INF] (or [-INF,-INF] or swapped is a known NAN. - if ((zero_p (lh_lb, lh_ub) && singleton_inf_p (rh_lb, rh_ub)) - || (zero_p (rh_lb, rh_ub) && singleton_inf_p (lh_lb, lh_ub))) - { - real_nan (&lb, "", 0, TYPE_MODE (type)); - ub = lb; - maybe_nan = true; - return; - } - - // Otherwise, if one range includes zero and the other ends with +-INF, - // it is a maybe NAN. - if ((contains_zero_p (lh_lb, lh_ub) - && (real_isinf (&rh_lb) || real_isinf (&rh_ub))) - || (contains_zero_p (rh_lb, rh_ub) - && (real_isinf (&lh_lb) || real_isinf (&lh_ub)))) - { - maybe_nan = true; - - int signbit_known = signbit_known_p (lh_lb, lh_ub, rh_lb, rh_ub); - - // If one of the ranges that includes INF is singleton - // and the other range includes zero, the resulting - // range is INF and NAN, because the 0 * INF boundary - // case will be NAN, but already nextafter (0, 1) * INF - // is INF. - if (singleton_inf_p (lh_lb, lh_ub) - || singleton_inf_p (rh_lb, rh_ub)) - return inf_range (lb, ub, signbit_known); - - // If one of the multiplicands must be zero, the resulting - // range is +-0 and NAN. - if (zero_p (lh_lb, lh_ub) || zero_p (rh_lb, rh_ub)) - return zero_range (lb, ub, signbit_known); - - // Otherwise one of the multiplicands could be - // [0.0, nextafter (0.0, 1.0)] and the [DBL_MAX, INF] - // or similarly with different signs. 0.0 * DBL_MAX - // is still 0.0, nextafter (0.0, 1.0) * INF is still INF, - // so if the signs are always the same or always different, - // result is [+0.0, +INF] or [-INF, -0.0], otherwise VARYING. - return zero_to_inf_range (lb, ub, signbit_known); - } - } +bool +operator_mult::op2_range (frange &r, tree type, + const frange &lhs, const frange &op1, + relation_trio) const +{ + return op1_range (r, type, lhs, op1); +} - REAL_VALUE_TYPE cp[8]; - // Do a cross-product. At this point none of the multiplications - // should produce a NAN. - frange_arithmetic (MULT_EXPR, type, cp[0], lh_lb, rh_lb, dconstninf); - frange_arithmetic (MULT_EXPR, type, cp[4], lh_lb, rh_lb, dconstinf); - if (is_square) - { - // For x * x we can just do max (lh_lb * lh_lb, lh_ub * lh_ub) - // as maximum and -0.0 as minimum if 0.0 is in the range, - // otherwise min (lh_lb * lh_lb, lh_ub * lh_ub). - // -0.0 rather than 0.0 because VREL_EQ doesn't prove that - // x and y are bitwise equal, just that they compare equal. - if (contains_zero_p (lh_lb, lh_ub)) - { - if (real_isneg (&lh_lb) == real_isneg (&lh_ub)) - cp[1] = dconst0; - else - cp[1] = dconstm0; - } - else - cp[1] = cp[0]; - cp[2] = cp[0]; - cp[5] = cp[4]; - cp[6] = cp[4]; - } - else - { - frange_arithmetic (MULT_EXPR, type, cp[1], lh_lb, rh_ub, dconstninf); - frange_arithmetic (MULT_EXPR, type, cp[5], lh_lb, rh_ub, dconstinf); - frange_arithmetic (MULT_EXPR, type, cp[2], lh_ub, rh_lb, dconstninf); - frange_arithmetic (MULT_EXPR, type, cp[6], lh_ub, rh_lb, dconstinf); - } - frange_arithmetic (MULT_EXPR, type, cp[3], lh_ub, rh_ub, dconstninf); - frange_arithmetic (MULT_EXPR, type, cp[7], lh_ub, rh_ub, dconstinf); +void +operator_mult::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, tree type, + const REAL_VALUE_TYPE &lh_lb, + const REAL_VALUE_TYPE &lh_ub, + const REAL_VALUE_TYPE &rh_lb, + const REAL_VALUE_TYPE &rh_ub, + relation_kind kind) const +{ + bool is_square + = (kind == VREL_EQ + && real_equal (&lh_lb, &rh_lb) + && real_equal (&lh_ub, &rh_ub) + && real_isneg (&lh_lb) == real_isneg (&rh_lb) + && real_isneg (&lh_ub) == real_isneg (&rh_ub)); + + maybe_nan = false; + // x * x never produces a new NAN and we only multiply the same + // values, so the 0 * INF problematic cases never appear there. + if (!is_square) + { + // [+-0, +-0] * [+INF,+INF] (or [-INF,-INF] or swapped is a known NAN. + if ((zero_p (lh_lb, lh_ub) && singleton_inf_p (rh_lb, rh_ub)) + || (zero_p (rh_lb, rh_ub) && singleton_inf_p (lh_lb, lh_ub))) + { + real_nan (&lb, "", 0, TYPE_MODE (type)); + ub = lb; + maybe_nan = true; + return; + } - find_range (lb, ub, cp); - } -} fop_mult; + // Otherwise, if one range includes zero and the other ends with +-INF, + // it is a maybe NAN. + if ((contains_zero_p (lh_lb, lh_ub) + && (real_isinf (&rh_lb) || real_isinf (&rh_ub))) + || (contains_zero_p (rh_lb, rh_ub) + && (real_isinf (&lh_lb) || real_isinf (&lh_ub)))) + { + maybe_nan = true; + + int signbit_known = signbit_known_p (lh_lb, lh_ub, rh_lb, rh_ub); + + // If one of the ranges that includes INF is singleton + // and the other range includes zero, the resulting + // range is INF and NAN, because the 0 * INF boundary + // case will be NAN, but already nextafter (0, 1) * INF + // is INF. + if (singleton_inf_p (lh_lb, lh_ub) + || singleton_inf_p (rh_lb, rh_ub)) + return inf_range (lb, ub, signbit_known); + + // If one of the multiplicands must be zero, the resulting + // range is +-0 and NAN. + if (zero_p (lh_lb, lh_ub) || zero_p (rh_lb, rh_ub)) + return zero_range (lb, ub, signbit_known); + + // Otherwise one of the multiplicands could be + // [0.0, nextafter (0.0, 1.0)] and the [DBL_MAX, INF] + // or similarly with different signs. 0.0 * DBL_MAX + // is still 0.0, nextafter (0.0, 1.0) * INF is still INF, + // so if the signs are always the same or always different, + // result is [+0.0, +INF] or [-INF, -0.0], otherwise VARYING. + return zero_to_inf_range (lb, ub, signbit_known); + } + } + REAL_VALUE_TYPE cp[8]; + // Do a cross-product. At this point none of the multiplications + // should produce a NAN. + frange_arithmetic (MULT_EXPR, type, cp[0], lh_lb, rh_lb, dconstninf); + frange_arithmetic (MULT_EXPR, type, cp[4], lh_lb, rh_lb, dconstinf); + if (is_square) + { + // For x * x we can just do max (lh_lb * lh_lb, lh_ub * lh_ub) + // as maximum and -0.0 as minimum if 0.0 is in the range, + // otherwise min (lh_lb * lh_lb, lh_ub * lh_ub). + // -0.0 rather than 0.0 because VREL_EQ doesn't prove that + // x and y are bitwise equal, just that they compare equal. + if (contains_zero_p (lh_lb, lh_ub)) + { + if (real_isneg (&lh_lb) == real_isneg (&lh_ub)) + cp[1] = dconst0; + else + cp[1] = dconstm0; + } + else + cp[1] = cp[0]; + cp[2] = cp[0]; + cp[5] = cp[4]; + cp[6] = cp[4]; + } + else + { + frange_arithmetic (MULT_EXPR, type, cp[1], lh_lb, rh_ub, dconstninf); + frange_arithmetic (MULT_EXPR, type, cp[5], lh_lb, rh_ub, dconstinf); + frange_arithmetic (MULT_EXPR, type, cp[2], lh_ub, rh_lb, dconstninf); + frange_arithmetic (MULT_EXPR, type, cp[6], lh_ub, rh_lb, dconstinf); + } + frange_arithmetic (MULT_EXPR, type, cp[3], lh_ub, rh_ub, dconstninf); + frange_arithmetic (MULT_EXPR, type, cp[7], lh_ub, rh_ub, dconstinf); -class foperator_div : public foperator_mult_div_base + find_range (lb, ub, cp); +} + + +class foperator_div : public range_operator { using range_operator::op1_range; using range_operator::op2_range; @@ -2525,7 +2519,7 @@ public: if (lhs.undefined_p ()) return false; frange wlhs = float_widen_lhs_range (type, lhs); - bool ret = fop_mult.fold_range (r, type, wlhs, op2); + bool ret = range_op_handler (MULT_EXPR).fold_range (r, type, wlhs, op2); if (!ret) return ret; if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) @@ -2669,12 +2663,7 @@ private: } fop_div; -float_table::float_table () -{ - set (MULT_EXPR, fop_mult); -} - -// Initialize any pointer operators to the primary table +// Initialize any float operators to the primary table void range_op_table::initialize_float_ops () |