The folding of comparisons against Inf (to constants or comparisons with the maximum finite value) has various cases where it introduces or loses "invalid" exceptions for comparisons with NaNs.
Folding x > +Inf to 0 should not be about HONOR_SNANS - ordered comparisons of both quiet and signaling NaNs should raise invalid. x <= +Inf is not the same as x == x, because again that loses an exception (equality comparisons don't raise exceptions except for signaling NaNs). x == +Inf is not the same as x > DBL_MAX, and a similar issue applies with the x != +Inf case - that transformation causes a spurious exception. This patch fixes the conditionals on the folding to avoid such introducing or losing exceptions. Bootstrapped with no regressions on x86_64-pc-linux-gnu (where the cases involving spurious exceptions wouldn't have failed anyway before GCC 8 because of unordered comparisons wrongly always having formerly been used by the back end). Also tested for powerpc-linux-gnu soft-float that this fixes many glibc math/ test failures that arose in that configuration because this folding affected the IBM long double support in libgcc (no such failures appeared for hard-float because of the bug of powerpc hard-float always using unordered comparisons) - some failures remain, but I believe them to be unrelated. OK to commit? gcc: 2018-01-05 Joseph Myers <jos...@codesourcery.com> PR tree-optimization/64811 * match.pd: When optimizing comparisons with Inf, avoid introducing or losing exceptions from comparisons with NaN. gcc/testsuite: 2018-01-05 Joseph Myers <jos...@codesourcery.com> PR tree-optimization/64811 * gcc.dg/torture/inf-compare-1.c, gcc.dg/torture/inf-compare-2.c, gcc.dg/torture/inf-compare-3.c, gcc.dg/torture/inf-compare-4.c, gcc.dg/torture/inf-compare-5.c, gcc.dg/torture/inf-compare-6.c, gcc.dg/torture/inf-compare-7.c, gcc.dg/torture/inf-compare-8.c: New tests. * gcc.c-torture/execute/ieee/fp-cmp-7.x: New file. Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 256279) +++ gcc/match.pd (working copy) @@ -3050,18 +3050,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) code = swap_tree_comparison (code); } (switch - /* x > +Inf is always false, if with ignore sNANs. */ + /* x > +Inf is always false, if we ignore NaNs or exceptions. */ (if (code == GT_EXPR - && ! HONOR_SNANS (@0)) + && !(HONOR_NANS (@0) && flag_trapping_math)) { constant_boolean_node (false, type); }) (if (code == LE_EXPR) - /* x <= +Inf is always true, if we don't case about NaNs. */ + /* x <= +Inf is always true, if we don't care about NaNs. */ (if (! HONOR_NANS (@0)) { constant_boolean_node (true, type); } - /* x <= +Inf is the same as x == x, i.e. !isnan(x). */ - (eq @0 @0))) - /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */ - (if (code == EQ_EXPR || code == GE_EXPR) + /* x <= +Inf is the same as x == x, i.e. !isnan(x), but this loses + an "invalid" exception. */ + (if (!flag_trapping_math) + (eq @0 @0)))) + /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX, but + for == this introduces an exception for x a NaN. */ + (if ((code == EQ_EXPR && !(HONOR_NANS (@0) && flag_trapping_math)) + || code == GE_EXPR) (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (if (neg) (lt @0 { build_real (TREE_TYPE (@0), max); }) @@ -3072,7 +3076,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (neg) (ge @0 { build_real (TREE_TYPE (@0), max); }) (le @0 { build_real (TREE_TYPE (@0), max); })))) - /* x != +Inf is always equal to !(x > DBL_MAX). */ + /* x != +Inf is always equal to !(x > DBL_MAX), but this introduces + an exception for x a NaN so use an unordered comparison. */ (if (code == NE_EXPR) (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (if (! HONOR_NANS (@0)) @@ -3080,10 +3085,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (ge @0 { build_real (TREE_TYPE (@0), max); }) (le @0 { build_real (TREE_TYPE (@0), max); })) (if (neg) - (bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); }) - { build_one_cst (type); }) - (bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); }) - { build_one_cst (type); })))))))))) + (unge @0 { build_real (TREE_TYPE (@0), max); }) + (unle @0 { build_real (TREE_TYPE (@0), max); })))))))))) /* If this is a comparison of a real constant with a PLUS_EXPR or a MINUS_EXPR of a real constant, we can convert it into a Index: gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x =================================================================== --- gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x (nonexistent) +++ gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x (working copy) @@ -0,0 +1,2 @@ +lappend additional_flags "-fno-trapping-math" +return 0 Index: gcc/testsuite/gcc.dg/torture/inf-compare-1.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-1.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-1.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x > __builtin_inf (); + if (i != 0 || !fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-2.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-2.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-2.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x < -__builtin_inf (); + if (i != 0 || !fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-3.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-3.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-3.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x <= __builtin_inf (); + if (i != 0 || !fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-4.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-4.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-4.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x >= -__builtin_inf (); + if (i != 0 || !fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-5.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-5.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-5.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x == __builtin_inf (); + if (i != 0 || fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-6.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-6.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-6.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x == -__builtin_inf (); + if (i != 0 || fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-7.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-7.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-7.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x != __builtin_inf (); + if (i != 1 || fetestexcept (FE_INVALID)) + abort (); +} Index: gcc/testsuite/gcc.dg/torture/inf-compare-8.c =================================================================== --- gcc/testsuite/gcc.dg/torture/inf-compare-8.c (nonexistent) +++ gcc/testsuite/gcc.dg/torture/inf-compare-8.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-add-options ieee } */ +/* { dg-require-effective-target fenv_exceptions } */ + +#include <fenv.h> + +extern void abort (void); +extern void exit (int); + +volatile double x = __builtin_nan (""); +volatile int i; + +int +main (void) +{ + i = x != -__builtin_inf (); + if (i != 1 || fetestexcept (FE_INVALID)) + abort (); +} -- Joseph S. Myers jos...@codesourcery.com