[gcc r15-11443] range-op-float: Fix up inf handling in other reverse ops [PR126464]
Jakub Jelinek
jakub@gcc.gnu.org
Sat Aug 1 10:17:04 GMT 2026
https://gcc.gnu.org/g:46b25706b7af8f8843c3dd88bbf59c5b44de0ac1
commit r15-11443-g46b25706b7af8f8843c3dd88bbf59c5b44de0ac1
Author: Jakub Jelinek <jakub@redhat.com>
Date: Fri Jul 31 08:56:03 2026 +0200
range-op-float: Fix up inf handling in other reverse ops [PR126464]
On Thu, Jul 30, 2026 at 09:31:17AM +0200, Richard Biener wrote:
> > 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.
On a second thought, this actually isn't specific to just reverse of
narrowing float to float casts, it is a problem for any other reverse binary
ops too.
E.g. the following testcase is miscompiled at -O2 since r13-3926-gd4c2f1d376da
(but works with -O0). The lhs of the addition is [-inf, -inf], one of its
operand is [-1e304, -1e300] and we think the other operand has to be
[-inf, -inf]. That is obviously wrong, even much larger operands can result
in -inf, anything below -DBL_MAX + -1e300 where x + -1e300 doesn't round to
-DBL_MAX or higher but to -inf.
So, the following patch just widens lb of +inf and ub of -inf by 1ulp for
all callers (and thus doesn't need the also_inf argument.
2026-07-31 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/126464
* range-op-float.cc (float_widen_lhs_range): Remove also_inf
argument, replace its uses as if it was always true.
* gcc.dg/torture/pr126464.c: New test.
Reviewed-by: Richard Biener <rguenth@suse.de>
(cherry picked from commit 6f32166346de2d1c0f6253e4fe37e8a6edac655d)
Diff:
---
gcc/range-op-float.cc | 10 +++++-----
gcc/testsuite/gcc.dg/torture/pr126464.c | 28 ++++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 9e024f3c6560..b8cb2b5097d1 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -2366,14 +2366,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, bool also_inf = false)
+float_widen_lhs_range (tree type, const frange &lhs)
{
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) || (also_inf && !real_isneg (&lb)))
+ if (real_isfinite (&lb) || !real_isneg (&lb))
{
frange_nextafter (TYPE_MODE (type), lb, dconstninf);
if (real_isinf (&lb))
@@ -2389,7 +2389,7 @@ float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false)
}
if (!flag_rounding_math
&& !MODE_COMPOSITE_P (TYPE_MODE (type))
- && (!also_inf || real_isfinite (&lhs.lower_bound ())))
+ && real_isfinite (&lhs.lower_bound ()))
{
/* If not -frounding-math nor IBM double double, actually widen
just by 0.5ulp rather than 1ulp. */
@@ -2398,7 +2398,7 @@ float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false)
real_arithmetic (&lb, RDIV_EXPR, &tem, &dconst2);
}
}
- if (real_isfinite (&ub) || (also_inf && real_isneg (&ub)))
+ if (real_isfinite (&ub) || real_isneg (&ub))
{
frange_nextafter (TYPE_MODE (type), ub, dconstinf);
if (real_isinf (&ub))
@@ -2409,7 +2409,7 @@ float_widen_lhs_range (tree type, const frange &lhs, bool also_inf = false)
}
if (!flag_rounding_math
&& !MODE_COMPOSITE_P (TYPE_MODE (type))
- && (!also_inf || real_isfinite (&lhs.upper_bound ())))
+ && real_isfinite (&lhs.upper_bound ()))
{
/* If not -frounding-math nor IBM double double, actually widen
just by 0.5ulp rather than 1ulp. */
diff --git a/gcc/testsuite/gcc.dg/torture/pr126464.c b/gcc/testsuite/gcc.dg/torture/pr126464.c
new file mode 100644
index 000000000000..c0dced1eedc0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr126464.c
@@ -0,0 +1,28 @@
+/* PR tree-optimization/126464 */
+/* { dg-do run } */
+
+#if __DBL_MANT_DIG__ == 53 && __DBL_MAX_10_EXP__ == 308 \
+ && __DBL_HAS_INFINITY__ && __FLT_EVAL_METHOD__ == 0
+[[gnu::noipa]] double
+foo (double x, double y)
+{
+ if (y >= -1e304 && y <= -1e300)
+ {
+ if (x + y == -__builtin_inf ())
+ return x * 0.5;
+ }
+ return x;
+}
+#endif
+
+int
+main ()
+{
+#if __DBL_MANT_DIG__ == 53 && __DBL_MAX_10_EXP__ == 308 \
+ && __DBL_HAS_INFINITY__ && __FLT_EVAL_METHOD__ == 0
+ if (foo (-__builtin_inf (), -1e303) != -__builtin_inf ())
+ __builtin_abort ();
+ if (foo (-1.797693134862e308, -1e303) != -1.797693134862e308 / 2.0)
+ __builtin_abort ();
+#endif
+}
More information about the Gcc-cvs
mailing list