aboutsummaryrefslogtreecommitdiff
path: root/gcc/match.pd
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-10-05 07:36:09 +0000
committerJakub Jelinek <jakub@redhat.com>2019-10-05 07:36:09 +0000
commit251549c2837a6e0efdb54f0fc5c8b77353debbeb (patch)
tree67f05915a1d5bd9c404586fb97a5e8fbc421c015 /gcc/match.pd
parentf7ebb9228f557eaf56dccf9603814ec2df48f9ef (diff)
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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@276621 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/match.pd')
-rw-r--r--gcc/match.pd145
1 files changed, 98 insertions, 47 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index 9bd5f3e6475..e3ac06c8ef5 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -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))