From: Jakub Jelinek Date: Thu, 30 Jul 2026 07:56:41 +0000 (+0200) Subject: range-op-float: Fix up inf handling in reverse narrowing float to float cast [PR126464] X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3754582630fa1eeff44a39f656ba0c7db6e58d0d;p=thirdparty%2Fgcc.git range-op-float: Fix up inf handling in reverse narrowing float to float cast [PR126464] The following testcase is miscompiled since my r16-1108 change. The problem is if we handle a reverse of a narrowing float to float cast (in the example there are double -> float and long double -> double cast) and the lhs range is [-inf, -inf] or [+inf, +inf] (note, regardless of whether some NaNs are allowed or not, so not necessarily lhs.known_isinf ()), then handling that range in the wider type also as [-inf, -inf] or [+inf, +inf] is wrong, e.g. for the double -> float conversion, [-inf, -0x0.ffffff8p+128] double range could map to just that [-inf, -inf]. We have already float_widen_lhs_range function but that just extends the range by +/-1ulp or 0.5ulp if the bounds are finite. If the range isn't singleton (except for optional NaN), then the minimum (or maximum) finite is already in the range, so this just extends the case where they are singleton. I don't know how to portably figure out that 0x0.ffffff8p+128 for double -> float (especially when in float_widen_lhs_range we don't know yet the wider type), so the patch just uses the +/-1ulp extension (i.e. [-inf, min_finite] or [+inf, max_finite] case. 2026-07-30 Jakub Jelinek PR tree-optimization/126464 * range-op-float.cc (float_widen_lhs_range): Add also_inf argument defaulted to false, if true, extend even lb of +inf and ub of -inf. (operator_cast::op1_range): Adjust float_widen_lhs_range caller. * gcc.dg/pr126464.c: New test. Reviewed-by: Richard Biener --- diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 5d1273732b9..e4daa97b0be 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -2374,14 +2374,14 @@ zero_to_inf_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, int signbit_known) in each direction. See PR109008 for more details. */ static frange -float_widen_lhs_range (tree type, const frange &lhs) +float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false) { frange ret = lhs; if (lhs.known_isnan ()) return ret; REAL_VALUE_TYPE lb = lhs.lower_bound (); REAL_VALUE_TYPE ub = lhs.upper_bound (); - if (real_isfinite (&lb)) + if (real_isfinite (&lb) || (also_inf && !real_isneg (&lb))) { frange_nextafter (TYPE_MODE (type), lb, dconstninf); if (real_isinf (&lb)) @@ -2395,7 +2395,9 @@ float_widen_lhs_range (tree type, const frange &lhs) lb = dconstm1; SET_REAL_EXP (&lb, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); } - if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type))) + if (!flag_rounding_math + && !MODE_COMPOSITE_P (TYPE_MODE (type)) + && (!also_inf || real_isfinite (&lhs.lower_bound ()))) { /* If not -frounding-math nor IBM double double, actually widen just by 0.5ulp rather than 1ulp. */ @@ -2404,7 +2406,7 @@ float_widen_lhs_range (tree type, const frange &lhs) real_arithmetic (&lb, RDIV_EXPR, &tem, &dconst2); } } - if (real_isfinite (&ub)) + if (real_isfinite (&ub) || (also_inf && real_isneg (&ub))) { frange_nextafter (TYPE_MODE (type), ub, dconstinf); if (real_isinf (&ub)) @@ -2413,7 +2415,9 @@ float_widen_lhs_range (tree type, const frange &lhs) ub = dconst1; SET_REAL_EXP (&ub, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); } - if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type))) + if (!flag_rounding_math + && !MODE_COMPOSITE_P (TYPE_MODE (type)) + && (!also_inf || real_isfinite (&lhs.upper_bound ()))) { /* If not -frounding-math nor IBM double double, actually widen just by 0.5ulp rather than 1ulp. */ @@ -3022,7 +3026,7 @@ operator_cast::op1_range (frange &r, tree type, const frange &lhs, else { rm = true; - wlhs = float_widen_lhs_range (lhs_type, lhs); + wlhs = float_widen_lhs_range (lhs_type, lhs, true); } auto save_flag_rounding_math = flag_rounding_math; flag_rounding_math = rm; diff --git a/gcc/testsuite/gcc.dg/pr126464.c b/gcc/testsuite/gcc.dg/pr126464.c new file mode 100644 index 00000000000..b6eb1320dec --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr126464.c @@ -0,0 +1,61 @@ +/* PR tree-optimization/126464 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-add-options ieee } */ +/* { dg-skip-if "not IEEE float" { "pdp11-*-*" } } */ + +[[gnu::noipa]] double +foo (double x) +{ + float y = (float) x; + + if (y == -__builtin_inff ()) + return x * 0.5; + return y; +} + +[[gnu::noipa]] long double +bar (long double x) +{ + double y = (double) x; + + if (y == __builtin_inf ()) + return x * 0.5L; + return y; +} + +[[gnu::noipa]] double +baz (double x) +{ + float y = (float) x; + + if (y == __builtin_inff ()) + return x * 0.5; + return y; +} + +[[gnu::noipa]] long double +qux (long double x) +{ + double y = (double) x; + + if (y == -__builtin_inf ()) + return x * 0.5L; + return y; +} + +int +main () +{ + if (!__builtin_isinf ((double) 1e300) + && __builtin_isinf ((float) 1e300) + && (foo (-1e300) != -5e299 + || baz (1e300) != 5e299)) + __builtin_abort (); + + if (!__builtin_isinf ((long double) 1e4000L) + && __builtin_isinf ((double) 1e4000L) + && (bar (1e4000L) != 5e3999L + || qux (-1e4000L) != -5e3999L)) + __builtin_abort (); +}