diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 238a3262d2be77cb9bbca4844929b4d79dee15f6..a8d39cff27f559b885b47a2f7236ce1e9655f76a 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -324,6 +324,24 @@ frange_arithmetic (enum tree_code code, tree type, bool inexact = real_arithmetic (&value, code, &op1, &op2); real_convert (&result, mode, &value); + /* When rounding towards negative infinity, x + (-x) and + x - x is -0 rather than +0 real_arithmetic computes. + So, when we are looking for lower bound (inf is negative), + use -0 rather than +0. */ + if (flag_rounding_math + && (code == PLUS_EXPR || code == MINUS_EXPR) + && !inexact + && real_iszero (&result) + && !real_isneg (&result) + && real_isneg (&inf)) + { + REAL_VALUE_TYPE op2a = op2; + if (code == PLUS_EXPR) + op2a.sign ^= 1; + if (real_isneg (&op1) == real_isneg (&op2a) && real_equal (&op1, &op2a)) + result.sign = 1; + } + // Be extra careful if there may be discrepancies between the // compile and runtime results. bool round = false; diff --git a/gcc/testsuite/gcc.dg/pr110755.c b/gcc/testsuite/gcc.dg/pr110755.c new file mode 100644 index 0000000000000000000000000000000000000000..c3bfaa61cb4a76d34efd09389168e397f186abd0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr110755.c @@ -0,0 +1,29 @@ +/* PR tree-optimization/110755 */ +/* { dg-do run } */ +/* { dg-require-effective-target fenv } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-O2 -frounding-math" } */ + +#include <fenv.h> + +__attribute__((noipa)) float +foo (float x) +{ + if (x > 0.0) + { + x += 0x1p+23; + x -= 0x1p+23; + x = __builtin_fabsf (x); + } + return x; +} + +int +main () +{ +#ifdef FE_DOWNWARD + fesetround (FE_DOWNWARD); + if (__builtin_signbit (foo (0.5))) + __builtin_abort (); +#endif +}