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))
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. */
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))
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. */
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;
--- /dev/null
+/* 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 ();
+}