diff options
author | Joseph Myers <joseph@codesourcery.com> | 2018-01-09 13:25:38 +0000 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2018-01-09 13:25:38 +0000 |
commit | e96a5786c75a9fb7c1720a0a4860e990bcc830bf (patch) | |
tree | a89520fd45e90056d90ab7810d9c09d60ed7698d /gcc | |
parent | aa5bfa8d5d9b5751bc6b1854d663fbf777849711 (diff) | |
download | gcc-e96a5786c75a9fb7c1720a0a4860e990bcc830bf.zip gcc-e96a5786c75a9fb7c1720a0a4860e990bcc830bf.tar.gz gcc-e96a5786c75a9fb7c1720a0a4860e990bcc830bf.tar.bz2 |
Fix folding of Inf/NaN comparisons for -ftrapping-math (PR tree-optimization/64811).
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.
PR tree-optimization/64811
gcc:
* match.pd: When optimizing comparisons with Inf, avoid
introducing or losing exceptions from comparisons with NaN.
gcc/testsuite:
* 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.
From-SVN: r256380
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/match.pd | 27 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-1.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-2.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-3.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-4.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-5.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-6.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-7.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/inf-compare-8.c | 19 |
12 files changed, 185 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0d9089b..24fd1b4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2018-01-09 Joseph Myers <joseph@codesourcery.com> + + PR tree-optimization/64811 + * match.pd: When optimizing comparisons with Inf, avoid + introducing or losing exceptions from comparisons with NaN. + 2018-01-09 Martin Liska <mliska@suse.cz> PR sanitizer/82517 diff --git a/gcc/match.pd b/gcc/match.pd index 915c20f..435125a 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7f90a43..679b22a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2018-01-09 Joseph Myers <joseph@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. + 2018-01-09 Georg-Johann Lay <avr@gjlay.de> PR target/79883 diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x new file mode 100644 index 0000000..35f7a0a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x @@ -0,0 +1,2 @@ +lappend additional_flags "-fno-trapping-math" +return 0 diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-1.c b/gcc/testsuite/gcc.dg/torture/inf-compare-1.c new file mode 100644 index 0000000..0f45108 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-1.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-2.c b/gcc/testsuite/gcc.dg/torture/inf-compare-2.c new file mode 100644 index 0000000..ba73395 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-2.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-3.c b/gcc/testsuite/gcc.dg/torture/inf-compare-3.c new file mode 100644 index 0000000..e545d3b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-3.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-4.c b/gcc/testsuite/gcc.dg/torture/inf-compare-4.c new file mode 100644 index 0000000..fca6cbf --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-4.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-5.c b/gcc/testsuite/gcc.dg/torture/inf-compare-5.c new file mode 100644 index 0000000..d7f17e7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-5.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-6.c b/gcc/testsuite/gcc.dg/torture/inf-compare-6.c new file mode 100644 index 0000000..2dd862b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-6.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-7.c b/gcc/testsuite/gcc.dg/torture/inf-compare-7.c new file mode 100644 index 0000000..36676b4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-7.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.dg/torture/inf-compare-8.c b/gcc/testsuite/gcc.dg/torture/inf-compare-8.c new file mode 100644 index 0000000..cfda813 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/inf-compare-8.c @@ -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 (); +} |