diff mbox series

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

Message ID alpine.DEB.2.20.1801052112460.4805@digraph.polyomino.org.uk
State New
Headers show
Series Fix folding of Inf/NaN comparisons for -ftrapping-math (PR tree-optimization/64811) | expand

Commit Message

Joseph Myers Jan. 5, 2018, 9:13 p.m. UTC
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?

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.

Comments

Richard Biener Jan. 6, 2018, 7:45 a.m. UTC | #1
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 ();
>+}
Bernhard Reutner-Fischer Jan. 10, 2018, 7:28 p.m. UTC | #2
Joseph,

On Sat, Jan 06, 2018 at 08:45:33AM +0100, Richard Biener wrote:
> On January 5, 2018 10:13:34 PM GMT+01:00, Joseph Myers <joseph@codesourcery.com> wrote:

> >unrelated.  OK to commit?
> 
> OK. 
> 
> Richard. 

> >Index: gcc/match.pd
> >===================================================================
> >--- gcc/match.pd	(revision 256279)
> >+++ gcc/match.pd	(working copy)

> >+	/* 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.  */

What does "x a NaN" mean? x OP NaN resp. x CMP 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.  */

Likewise.

> >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 ();
> >+}

Shouldn't run tests return 0 here? Also drop the exit() declaration
since it's unused?
Same for all new tests in this patch.

thanks,

> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-2.c
> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-3.c
> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-4.c
> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-5.c
> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-6.c
> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-7.c
> >Index: gcc/testsuite/gcc.dg/torture/inf-compare-8.c
Joseph Myers Jan. 10, 2018, 8:17 p.m. UTC | #3
On Wed, 10 Jan 2018, Bernhard Reutner-Fischer wrote:

> > >+	/* 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.  */
> 
> What does "x a NaN" mean? x OP NaN resp. x CMP NaN ?

That x is a NaN.  fpclassify (x) == FP_NAN.  It's not a C comparison 
operator since NaNs compare unequal to everything.

> Shouldn't run tests return 0 here? Also drop the exit() declaration
> since it's unused?

C99 automatically returns 0 from the end of main, but it's true the 
default style would be exit (0) in tests.
Bernhard Reutner-Fischer Jan. 10, 2018, 8:44 p.m. UTC | #4
On Wed, Jan 10, 2018 at 08:17:08PM +0000, Joseph Myers wrote:
> On Wed, 10 Jan 2018, Bernhard Reutner-Fischer wrote:
> 
> > > >+	/* 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.  */
> > 
> > What does "x a NaN" mean? x OP NaN resp. x CMP NaN ?
> 
> That x is a NaN.  fpclassify (x) == FP_NAN.  It's not a C comparison 

So s/for x a NaN/if x is a NaN/ wouldn't have thrown me off.

> operator since NaNs compare unequal to everything.
> 
> > Shouldn't run tests return 0 here? Also drop the exit() declaration
> > since it's unused?
> 
> C99 automatically returns 0 from the end of main, but it's true the 
> default style would be exit (0) in tests.

Ah right fenv_exceptions even sets -std=gnu99 and fenv support would
require a minimum of C99 anyway so you're of course right. Obviously
i'm half asleep, sorry for the noise..

thanks,
diff mbox series

Patch

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 ();
+}