Commit 0043b528 by Jakub Jelinek Committed by Jakub Jelinek

re PR tree-optimization/91734 (gcc skip an if statement with "-O1 -ffast-math")

	PR tree-optimization/91734
	* generic-match-head.c: Include fold-const-call.h.
	* match.pd (sqrt(x) cmp c): Check the boundary value and
	in case inexact computation of c*c affects comparison of the boundary,
	turn LT_EXPR into LE_EXPR, GE_EXPR into GT_EXPR, LE_EXPR into LT_EXPR
	or GT_EXPR into GE_EXPR.  Punt for sqrt comparisons against NaN and
	for -frounding-math.  For c2, try the next smaller or larger floating
	point constant depending on comparison code and if it has the same
	sqrt as c2, use it instead of c2.

	* gcc.dg/pr91734.c: New test.

From-SVN: r276621
parent 30648d02
2019-10-05 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/91734
* generic-match-head.c: Include fold-const-call.h.
* match.pd (sqrt(x) cmp c): Check the boundary value and
in case inexact computation of c*c affects comparison of the boundary,
turn LT_EXPR into LE_EXPR, GE_EXPR into GT_EXPR, LE_EXPR into LT_EXPR
or GT_EXPR into GE_EXPR. Punt for sqrt comparisons against NaN and
for -frounding-math. For c2, try the next smaller or larger floating
point constant depending on comparison code and if it has the same
sqrt as c2, use it instead of c2.
2019-10-04 Martin Sebor <msebor@redhat.com>
PR middle-end/91977
......
......@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "vec-perm-indices.h"
#include "fold-const.h"
#include "fold-const-call.h"
#include "stor-layout.h"
#include "tree-dfa.h"
#include "builtins.h"
......
......@@ -3726,8 +3726,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp { tem; } @1)))))
/* Fold comparisons against built-in math functions. */
(if (flag_unsafe_math_optimizations
&& ! flag_errno_math)
(if (flag_unsafe_math_optimizations && ! flag_errno_math)
(for sq (SQRT)
(simplify
(cmp (sq @0) REAL_CST@1)
......@@ -3762,56 +3761,108 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
if x is negative or NaN. Due to -funsafe-math-optimizations,
the results for other x follow from natural arithmetic. */
(cmp @0 @1)))
(if (cmp == GT_EXPR || cmp == GE_EXPR)
(if ((cmp == LT_EXPR
|| cmp == LE_EXPR
|| cmp == GT_EXPR
|| cmp == GE_EXPR)
&& !REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
/* Give up for -frounding-math. */
&& !HONOR_SIGN_DEPENDENT_ROUNDING (TREE_TYPE (@0)))
(with
{
REAL_VALUE_TYPE c2;
REAL_VALUE_TYPE c2;
enum tree_code ncmp = cmp;
const real_format *fmt
= REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@0)));
real_arithmetic (&c2, MULT_EXPR,
&TREE_REAL_CST (@1), &TREE_REAL_CST (@1));
real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
}
(if (REAL_VALUE_ISINF (c2))
/* sqrt(x) > y is x == +Inf, when y is very large. */
(if (HONOR_INFINITIES (@0))
(eq @0 { build_real (TREE_TYPE (@0), c2); })
{ constant_boolean_node (false, type); })
/* sqrt(x) > c is the same as x > c*c. */
(cmp @0 { build_real (TREE_TYPE (@0), c2); }))))
(if (cmp == LT_EXPR || cmp == LE_EXPR)
(with
{
REAL_VALUE_TYPE c2;
real_arithmetic (&c2, MULT_EXPR,
&TREE_REAL_CST (@1), &TREE_REAL_CST (@1));
real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
real_convert (&c2, fmt, &c2);
/* See PR91734: if c2 is inexact and sqrt(c2) < c (or sqrt(c2) >= c),
then change LT_EXPR into LE_EXPR or GE_EXPR into GT_EXPR. */
if (!REAL_VALUE_ISINF (c2))
{
tree c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0),
build_real (TREE_TYPE (@0), c2));
if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST)
ncmp = ERROR_MARK;
else if ((cmp == LT_EXPR || cmp == GE_EXPR)
&& real_less (&TREE_REAL_CST (c3), &TREE_REAL_CST (@1)))
ncmp = cmp == LT_EXPR ? LE_EXPR : GT_EXPR;
else if ((cmp == LE_EXPR || cmp == GT_EXPR)
&& real_less (&TREE_REAL_CST (@1), &TREE_REAL_CST (c3)))
ncmp = cmp == LE_EXPR ? LT_EXPR : GE_EXPR;
else
{
/* With rounding to even, sqrt of up to 3 different values
gives the same normal result, so in some cases c2 needs
to be adjusted. */
REAL_VALUE_TYPE c2alt, tow;
if (cmp == LT_EXPR || cmp == GE_EXPR)
tow = dconst0;
else
real_inf (&tow);
real_nextafter (&c2alt, fmt, &c2, &tow);
real_convert (&c2alt, fmt, &c2alt);
if (REAL_VALUE_ISINF (c2alt))
ncmp = ERROR_MARK;
else
{
c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0),
build_real (TREE_TYPE (@0), c2alt));
if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST)
ncmp = ERROR_MARK;
else if (real_equal (&TREE_REAL_CST (c3),
&TREE_REAL_CST (@1)))
c2 = c2alt;
}
}
}
}
(if (REAL_VALUE_ISINF (c2))
(switch
/* sqrt(x) < y is always true, when y is a very large
value and we don't care about NaNs or Infinities. */
(if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
{ constant_boolean_node (true, type); })
/* sqrt(x) < y is x != +Inf when y is very large and we
don't care about NaNs. */
(if (! HONOR_NANS (@0))
(ne @0 { build_real (TREE_TYPE (@0), c2); }))
/* sqrt(x) < y is x >= 0 when y is very large and we
don't care about Infinities. */
(if (! HONOR_INFINITIES (@0))
(ge @0 { build_real (TREE_TYPE (@0), dconst0); }))
/* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */
(if (GENERIC)
(truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
(ne @0 { build_real (TREE_TYPE (@0), c2); }))))
/* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */
(if (! HONOR_NANS (@0))
(cmp @0 { build_real (TREE_TYPE (@0), c2); })
/* sqrt(x) < c is the same as x >= 0 && x < c*c. */
(if (GENERIC)
(truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
(cmp @0 { build_real (TREE_TYPE (@0), c2); })))))))))
(if (cmp == GT_EXPR || cmp == GE_EXPR)
(if (REAL_VALUE_ISINF (c2))
/* sqrt(x) > y is x == +Inf, when y is very large. */
(if (HONOR_INFINITIES (@0))
(eq @0 { build_real (TREE_TYPE (@0), c2); })
{ constant_boolean_node (false, type); })
/* sqrt(x) > c is the same as x > c*c. */
(if (ncmp != ERROR_MARK)
(if (ncmp == GE_EXPR)
(ge @0 { build_real (TREE_TYPE (@0), c2); })
(gt @0 { build_real (TREE_TYPE (@0), c2); }))))
/* else if (cmp == LT_EXPR || cmp == LE_EXPR) */
(if (REAL_VALUE_ISINF (c2))
(switch
/* sqrt(x) < y is always true, when y is a very large
value and we don't care about NaNs or Infinities. */
(if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
{ constant_boolean_node (true, type); })
/* sqrt(x) < y is x != +Inf when y is very large and we
don't care about NaNs. */
(if (! HONOR_NANS (@0))
(ne @0 { build_real (TREE_TYPE (@0), c2); }))
/* sqrt(x) < y is x >= 0 when y is very large and we
don't care about Infinities. */
(if (! HONOR_INFINITIES (@0))
(ge @0 { build_real (TREE_TYPE (@0), dconst0); }))
/* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */
(if (GENERIC)
(truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
(ne @0 { build_real (TREE_TYPE (@0), c2); }))))
/* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */
(if (ncmp != ERROR_MARK && ! HONOR_NANS (@0))
(if (ncmp == LT_EXPR)
(lt @0 { build_real (TREE_TYPE (@0), c2); })
(le @0 { build_real (TREE_TYPE (@0), c2); }))
/* sqrt(x) < c is the same as x >= 0 && x < c*c. */
(if (ncmp != ERROR_MARK && GENERIC)
(if (ncmp == LT_EXPR)
(truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
(lt @0 { build_real (TREE_TYPE (@0), c2); }))
(truth_andif
(ge @0 { build_real (TREE_TYPE (@0), dconst0); })
(le @0 { build_real (TREE_TYPE (@0), c2); })))))))))))
/* Transform sqrt(x) cmp sqrt(y) -> x cmp y. */
(simplify
(cmp (sq @0) (sq @1))
......
2019-10-05 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/91734
* gcc.dg/pr91734.c: New test.
2019-10-04 Joseph Myers <joseph@codesourcery.com>
PR c/82752
......
/* PR tree-optimization/91734 */
/* { dg-do run } */
/* { dg-add-options ieee } */
/* { dg-additional-options "-O2 -std=gnu99" } */
__attribute__((noipa, optimize ("Ofast"))) int
f1 (float x)
{
return __builtin_sqrtf (x) < __FLT_MIN__;
}
__attribute__((noipa, optimize ("Ofast"))) int
f2 (float x)
{
return __builtin_sqrtf (x) < 0x1.2dd3d0p-65f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f3 (float x)
{
return __builtin_sqrtf (x) >= 0x1.2dd3d0p-65f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f4 (float x)
{
return __builtin_sqrtf (x) >= 0x1.5642e6p+54f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f5 (float x)
{
return __builtin_sqrtf (x) > 0x1.5642e6p+54f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f6 (float x)
{
return __builtin_sqrtf (x) < 0x1.4da1cp-19f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f7 (float x)
{
return __builtin_sqrtf (x) <= 0x1.4da1cp-19f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f8 (float x)
{
return __builtin_sqrtf (x) < 0x1.50cb62p-65f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f9 (float x)
{
return __builtin_sqrtf (x) <= 0x1.4fc00cp-73f;
}
__attribute__((noipa, optimize ("Ofast"))) int
f10 (float x)
{
return __builtin_sqrtf (x) < 0x1.001002p+0f;
}
int
main ()
{
if (__FLT_RADIX__ != 2
|| __FLT_MANT_DIG__ != 24
|| __FLT_MIN_EXP__ != -125
|| __FLT_MAX_EXP__ != 128
|| __FLT_HAS_DENORM__ != 1
|| __FLT_HAS_INFINITY__ != 1)
return 0;
if (!f1 (0.0f) || f1 (0x1.0p-149f))
__builtin_abort ();
if (!f2 (0x1.63dbc0p-130f))
__builtin_abort ();
if (f3 (0x1.63dbc0p-130f))
__builtin_abort ();
if (!f4 (0x1.c996d0p+108f) || !f4 (0x1.c996cep+108f) || f4 (0x1.c996ccp+108f))
__builtin_abort ();
if (f5 (0x1.c996d0p+108f) || f5 (0x1.c996d2p+108f) || !f5 (0x1.c996d4p+108f))
__builtin_abort ();
if (!f6 (0x1.b2ce3p-38f) || f6 (0x1.b2ce32p-38f) || f6 (0x1.b2ce34p-38f))
__builtin_abort ();
if (!f7 (0x1.b2ce3p-38f) || !f7 (0x1.b2ce34p-38f) || !f7 (0x1.b2ce36p-38f) || f7 (0x1.b2ce38p-38f))
__builtin_abort ();
if (!f8 (0x1.bb166p-130f) || !f8 (0x1.bb168p-130f) || f8 (0x1.bb16ap-130f) || f8 (0x1.bb16cp-130f))
__builtin_abort ();
if (!f9 (0x1.8p-146f) || !f9 (0x1.ap-146f) || f9 (0x1.cp-146f) || f9 (0x1.ep-146f))
__builtin_abort ();
if (f10 (0x1.002004p+0f))
__builtin_abort ();
return 0;
}
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