On January 5, 2018 10:13:34 PM GMT+01:00, Joseph Myers <jos...@codesourcery.com> wrote: >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?
OK. Richard. >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 (); >+}