From: Joseph Myers Date: Tue, 9 Jan 2018 13:25:38 +0000 (+0000) Subject: Fix folding of Inf/NaN comparisons for -ftrapping-math (PR tree-optimization/64811). X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e96a5786c75a9fb7c1720a0a4860e990bcc830bf;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0d9089b5761..24fd1b4187f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2018-01-09 Joseph Myers + + 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 PR sanitizer/82517 diff --git a/gcc/match.pd b/gcc/match.pd index 915c20f5e12..435125a3172 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 7f90a43cc5e..679b22a68d4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2018-01-09 Joseph Myers + + 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 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 00000000000..35f7a0a7d99 --- /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 00000000000..0f4510829b5 --- /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 + +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 00000000000..ba7339586a4 --- /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 + +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 00000000000..e545d3b620c --- /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 + +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 00000000000..fca6cbf6d94 --- /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 + +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 00000000000..d7f17e7dd21 --- /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 + +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 00000000000..2dd862b7ebe --- /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 + +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 00000000000..36676b4e79f --- /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 + +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 00000000000..cfda813a0c6 --- /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 + +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 (); +}