This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Fix folding of Inf/NaN comparisons for -ftrapping-math (PR tree-optimization/64811)


On January 5, 2018 10:13:34 PM GMT+01:00, Joseph Myers <joseph@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  <joseph@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  <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.
>
>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 ();
>+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]