Commit e96a5786 by Joseph Myers Committed by Joseph Myers

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
parent aa5bfa8d
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> 2018-01-09 Martin Liska <mliska@suse.cz>
PR sanitizer/82517 PR sanitizer/82517
......
...@@ -3050,18 +3050,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) ...@@ -3050,18 +3050,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
code = swap_tree_comparison (code); code = swap_tree_comparison (code);
} }
(switch (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 (if (code == GT_EXPR
&& ! HONOR_SNANS (@0)) && !(HONOR_NANS (@0) && flag_trapping_math))
{ constant_boolean_node (false, type); }) { constant_boolean_node (false, type); })
(if (code == LE_EXPR) (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)) (if (! HONOR_NANS (@0))
{ constant_boolean_node (true, type); } { constant_boolean_node (true, type); }
/* x <= +Inf is the same as x == x, i.e. !isnan(x). */ /* x <= +Inf is the same as x == x, i.e. !isnan(x), but this loses
(eq @0 @0))) an "invalid" exception. */
/* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */ (if (!flag_trapping_math)
(if (code == EQ_EXPR || code == GE_EXPR) (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))); } (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (neg) (if (neg)
(lt @0 { build_real (TREE_TYPE (@0), max); }) (lt @0 { build_real (TREE_TYPE (@0), max); })
...@@ -3072,7 +3076,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) ...@@ -3072,7 +3076,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (neg) (if (neg)
(ge @0 { build_real (TREE_TYPE (@0), max); }) (ge @0 { build_real (TREE_TYPE (@0), max); })
(le @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) (if (code == NE_EXPR)
(with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
(if (! HONOR_NANS (@0)) (if (! HONOR_NANS (@0))
...@@ -3080,10 +3085,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) ...@@ -3080,10 +3085,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(ge @0 { build_real (TREE_TYPE (@0), max); }) (ge @0 { build_real (TREE_TYPE (@0), max); })
(le @0 { build_real (TREE_TYPE (@0), max); })) (le @0 { build_real (TREE_TYPE (@0), max); }))
(if (neg) (if (neg)
(bit_xor (lt @0 { build_real (TREE_TYPE (@0), max); }) (unge @0 { build_real (TREE_TYPE (@0), max); })
{ build_one_cst (type); }) (unle @0 { build_real (TREE_TYPE (@0), max); }))))))))))
(bit_xor (gt @0 { build_real (TREE_TYPE (@0), max); })
{ build_one_cst (type); }))))))))))
/* If this is a comparison of a real constant with a PLUS_EXPR /* 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 or a MINUS_EXPR of a real constant, we can convert it into a
......
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> 2018-01-09 Georg-Johann Lay <avr@gjlay.de>
PR target/79883 PR target/79883
......
lappend additional_flags "-fno-trapping-math"
return 0
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
/* { 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 ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment