Fix folding of Inf/NaN comparisons for -ftrapping-math (PR tree-optimization/64811).
authorJoseph Myers <joseph@codesourcery.com>
Tue, 9 Jan 2018 13:25:38 +0000 (13:25 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Tue, 9 Jan 2018 13:25:38 +0000 (13:25 +0000)
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

12 files changed:
gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.x [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/inf-compare-8.c [new file with mode: 0644]

index 0d9089b5761df35ffca2238dd889e5edc315e4a2..24fd1b4187f466c110157daf2bda3a61c7da6119 100644 (file)
@@ -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
index 915c20f5e12761be5a8a117f3afd68d0ed2d478a..435125a317275527661fba011a9d26e507d293a6 100644 (file)
@@ -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 7f90a43cc5edc88f06b44594dcfc1b3d5fd37883..679b22a68d405332fd5de444bec9bbedc7b1a452 100644 (file)
@@ -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 (file)
index 0000000..35f7a0a
--- /dev/null
@@ -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 (file)
index 0000000..0f45108
--- /dev/null
@@ -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 (file)
index 0000000..ba73395
--- /dev/null
@@ -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 (file)
index 0000000..e545d3b
--- /dev/null
@@ -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 (file)
index 0000000..fca6cbf
--- /dev/null
@@ -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 (file)
index 0000000..d7f17e7
--- /dev/null
@@ -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 (file)
index 0000000..2dd862b
--- /dev/null
@@ -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 (file)
index 0000000..36676b4
--- /dev/null
@@ -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 (file)
index 0000000..cfda813
--- /dev/null
@@ -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 ();
+}