re PR tree-optimization/91734 (gcc skip an if statement with "-O1 -ffast-math")
authorJakub Jelinek <jakub@redhat.com>
Sat, 5 Oct 2019 07:36:09 +0000 (09:36 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sat, 5 Oct 2019 07:36:09 +0000 (09:36 +0200)
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

gcc/ChangeLog
gcc/generic-match-head.c
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr91734.c [new file with mode: 0644]

index 18b4f89bb2816ec0a9626bbe540f6038301bac1a..171d554483983b37f88ccbf84540e48e55224549 100644 (file)
@@ -1,3 +1,15 @@
+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
index b54e03552bae6b254f4e502fd28200650f68035d..fdc603977fc5b03a843944f75ce262f5d2256308 100644 (file)
@@ -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"
index 9bd5f3e64752744550fc436f64e8341918d3a899..e3ac06c8ef5b893bd344734095b11047a43f98b8 100644 (file)
@@ -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))
index 46245216b9066bb10f293fe252f340ab9fd96837..10ba0d9ed7d7fdd215abc48a526e0bba425080a6 100644 (file)
@@ -1,3 +1,8 @@
+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
diff --git a/gcc/testsuite/gcc.dg/pr91734.c b/gcc/testsuite/gcc.dg/pr91734.c
new file mode 100644 (file)
index 0000000..1cc3e40
--- /dev/null
@@ -0,0 +1,97 @@
+/* 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;
+}