diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2023-10-01 16:54:27 -0400 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2023-10-26 12:52:14 -0400 |
commit | 24e97ac46c24060a1a5a2ce8ebc842239006c405 (patch) | |
tree | 00c8c780abb2c0d26eb78aac7795a216f6932bad /gcc | |
parent | 4d49685d671e4e604b2b873ada65aaac89348794 (diff) | |
download | gcc-24e97ac46c24060a1a5a2ce8ebc842239006c405.zip gcc-24e97ac46c24060a1a5a2ce8ebc842239006c405.tar.gz gcc-24e97ac46c24060a1a5a2ce8ebc842239006c405.tar.bz2 |
[range-ops] Add frange& argument to rv_fold.
The floating point version of rv_fold returns its result in 3 pieces:
the lower bound, the upper bound, and a maybe_nan bit. It is cleaner
to return everything in an frange, thus bringing the floating point
version of rv_fold in line with the integer version.
This first patch adds an frange argument, while keeping the current
functionality, and asserting that we get the same results. In a
follow-up patch I will nuke the now useless 3 arguments. Splitting
this into two patches makes it easier to bisect any problems if any
should arise.
gcc/ChangeLog:
* range-op-float.cc (range_operator::fold_range): Pass frange
argument to rv_fold.
(range_operator::rv_fold): Add frange argument.
(operator_plus::rv_fold): Same.
(operator_minus::rv_fold): Same.
(operator_mult::rv_fold): Same.
(operator_div::rv_fold): Same.
* range-op-mixed.h: Add frange argument to rv_fold methods.
* range-op.h: Same.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/range-op-float.cc | 120 | ||||
-rw-r--r-- | gcc/range-op-mixed.h | 15 | ||||
-rw-r--r-- | gcc/range-op.h | 4 |
3 files changed, 107 insertions, 32 deletions
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 0951bd3..cb2c0a6 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -62,9 +62,11 @@ range_operator::fold_range (frange &r, tree type, return true; } + frange res; REAL_VALUE_TYPE lb, ub; bool maybe_nan; - rv_fold (lb, ub, maybe_nan, type, + rv_fold (res, type, + lb, ub, maybe_nan, op1.lower_bound (), op1.upper_bound (), op2.lower_bound (), op2.upper_bound (), trio.op1_op2 ()); @@ -75,6 +77,7 @@ range_operator::fold_range (frange &r, tree type, if (lb_nan && ub_nan) { r.set_nan (type); + gcc_checking_assert (r == res); return true; } if (lb_nan) @@ -92,6 +95,10 @@ range_operator::fold_range (frange &r, tree type, else r.clear_nan (); + if (op1.maybe_isnan () || op2.maybe_isnan ()) + res.update_nan (); + gcc_checking_assert (r == res); + // If the result has overflowed and flag_trapping_math, folding this // operation could elide an overflow or division by zero exception. // Avoid returning a singleton +-INF, to keep the propagators (DOM @@ -122,19 +129,19 @@ range_operator::fold_range (frange &r, tree type, // MAYBE_NAN is set to TRUE if, in addition to any result in LB or // UB, the final range has the possibility of a NAN. void -range_operator::rv_fold (REAL_VALUE_TYPE &lb, - REAL_VALUE_TYPE &ub, - bool &maybe_nan, - tree type ATTRIBUTE_UNUSED, - const REAL_VALUE_TYPE &lh_lb ATTRIBUTE_UNUSED, - const REAL_VALUE_TYPE &lh_ub ATTRIBUTE_UNUSED, - const REAL_VALUE_TYPE &rh_lb ATTRIBUTE_UNUSED, - const REAL_VALUE_TYPE &rh_ub ATTRIBUTE_UNUSED, - relation_kind) const +range_operator::rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, + REAL_VALUE_TYPE &ub, + bool &maybe_nan, + const REAL_VALUE_TYPE &, + const REAL_VALUE_TYPE &, + const REAL_VALUE_TYPE &, + const REAL_VALUE_TYPE &, relation_kind) const { lb = dconstninf; ub = dconstinf; maybe_nan = true; + r.set (type, dconstninf, dconstinf, nan_state (true)); } bool @@ -2471,8 +2478,9 @@ operator_plus::op2_range (frange &r, tree type, } void -operator_plus::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - bool &maybe_nan, tree type, +operator_plus::rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, const REAL_VALUE_TYPE &rh_lb, @@ -2490,6 +2498,21 @@ operator_plus::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, maybe_nan = true; else maybe_nan = false; + + // Handle possible NANs by saturating to the appropriate INF if only + // one end is a NAN. If both ends are a NAN, just return a NAN. + bool lb_nan = real_isnan (&lb); + bool ub_nan = real_isnan (&ub); + if (lb_nan && ub_nan) + { + r.set_nan (type); + return; + } + if (lb_nan) + lb = dconstninf; + else if (ub_nan) + ub = dconstinf; + r.set (type, lb, ub, nan_state (maybe_nan)); } @@ -2519,8 +2542,9 @@ operator_minus::op2_range (frange &r, tree type, } void -operator_minus::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - bool &maybe_nan, tree type, +operator_minus::rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, const REAL_VALUE_TYPE &rh_lb, @@ -2538,6 +2562,21 @@ operator_minus::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, maybe_nan = true; else maybe_nan = false; + + // Handle possible NANs by saturating to the appropriate INF if only + // one end is a NAN. If both ends are a NAN, just return a NAN. + bool lb_nan = real_isnan (&lb); + bool ub_nan = real_isnan (&ub); + if (lb_nan && ub_nan) + { + r.set_nan (type); + return; + } + if (lb_nan) + lb = dconstninf; + else if (ub_nan) + ub = dconstinf; + r.set (type, lb, ub, nan_state (maybe_nan)); } @@ -2612,8 +2651,9 @@ operator_mult::op2_range (frange &r, tree type, } void -operator_mult::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - bool &maybe_nan, tree type, +operator_mult::rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, const REAL_VALUE_TYPE &rh_lb, @@ -2639,6 +2679,7 @@ operator_mult::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, real_nan (&lb, "", 0, TYPE_MODE (type)); ub = lb; maybe_nan = true; + r.set_nan (type); return; } @@ -2660,12 +2701,20 @@ operator_mult::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, // is INF. if (singleton_inf_p (lh_lb, lh_ub) || singleton_inf_p (rh_lb, rh_ub)) - return inf_range (lb, ub, signbit_known); + { + inf_range (lb, ub, signbit_known); + r.set (type, lb, ub, nan_state (true)); + return; + } // 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); + { + zero_range (lb, ub, signbit_known); + r.set (type, lb, ub, nan_state (true)); + return; + } // Otherwise one of the multiplicands could be // [0.0, nextafter (0.0, 1.0)] and the [DBL_MAX, INF] @@ -2673,7 +2722,9 @@ operator_mult::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, // 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); + zero_to_inf_range (lb, ub, signbit_known); + r.set (type, lb, ub, nan_state (true)); + return; } } @@ -2713,6 +2764,10 @@ operator_mult::rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, frange_arithmetic (MULT_EXPR, type, cp[7], lh_ub, rh_ub, dconstinf); find_range (lb, ub, cp); + + gcc_checking_assert (!real_isnan (&lb)); + gcc_checking_assert (!real_isnan (&ub)); + r.set (type, lb, ub, nan_state (maybe_nan)); } @@ -2785,8 +2840,8 @@ public: return float_binary_op_range_finish (ret, r, type, wlhs, true); } private: - void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, bool &maybe_nan, - tree type, + void rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, bool &maybe_nan, const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, const REAL_VALUE_TYPE &rh_lb, @@ -2800,6 +2855,7 @@ private: real_nan (&lb, "", 0, TYPE_MODE (type)); ub = lb; maybe_nan = true; + r.set_nan (type); return; } @@ -2820,14 +2876,22 @@ private: // If divisor must be +-INF, the range is just +-0 // (including if the dividend is zero). if (zero_p (lh_lb, lh_ub) || singleton_inf_p (rh_lb, rh_ub)) - return zero_range (lb, ub, signbit_known); + { + zero_range (lb, ub, signbit_known); + r.set (type, lb, ub, nan_state (maybe_nan)); + return; + } // If divisor must be zero, the range is just +-INF // (including if the dividend is +-INF). // If dividend must be +-INF, the range is just +-INF // (including if the dividend is zero). if (zero_p (rh_lb, rh_ub) || singleton_inf_p (lh_lb, lh_ub)) - return inf_range (lb, ub, signbit_known); + { + inf_range (lb, ub, signbit_known); + r.set (type, lb, ub, nan_state (maybe_nan)); + return; + } // Otherwise if both operands may be zero, divisor could be // nextafter(0.0, +-1.0) and dividend +-0.0 @@ -2843,7 +2907,11 @@ private: // [+0.0, +INF], if they are always different we have // [-INF, -0.0]. If they vary, VARYING. if (maybe_nan) - return zero_to_inf_range (lb, ub, signbit_known); + { + zero_to_inf_range (lb, ub, signbit_known); + r.set (type, lb, ub, nan_state (maybe_nan)); + return; + } REAL_VALUE_TYPE cp[8]; // Do a cross-division. At this point none of the divisions should @@ -2869,6 +2937,10 @@ private: if (signbit_known >= 0) real_inf (&ub, false); } + + gcc_checking_assert (!real_isnan (&lb)); + gcc_checking_assert (!real_isnan (&ub)); + r.set (type, lb, ub, nan_state (maybe_nan)); } } fop_div; diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h index f7ff47b..ccaa2c2 100644 --- a/gcc/range-op-mixed.h +++ b/gcc/range-op-mixed.h @@ -414,8 +414,9 @@ private: void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const final override; - void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - bool &maybe_nan, tree type, + void rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, 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) const final override; @@ -483,8 +484,9 @@ private: void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const final override; - void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - bool &maybe_nan, tree type, + void rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, 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) const final override; @@ -553,8 +555,9 @@ public: bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, const wide_int &w1) const final override; - void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, - bool &maybe_nan, tree type, + void rv_fold (frange &r, tree type, + REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + bool &maybe_nan, 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; diff --git a/gcc/range-op.h b/gcc/range-op.h index 21d401c..3ec53a0 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -185,9 +185,9 @@ protected: virtual void update_bitmask (irange &, const irange &, const irange &) const; // Perform an float operation between 2 ranges and return it. - virtual void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, + virtual void rv_fold (frange &r, tree type, + 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, |