Fold comparisons between sqrt and zero
authorRichard Sandiford <richard.sandiford@arm.com>
Tue, 27 Oct 2015 11:51:43 +0000 (11:51 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Tue, 27 Oct 2015 11:51:43 +0000 (11:51 +0000)
The expression:

      signbit(sqrt(x))

is always 0 for -ffast-math.  The signbit fold first converts it to:

      sqrt(x) < 0

and whether we realise that this is false depends on a race between two
folders: the sqrt comparison folder, which wants to convert it to

      x < 0*0

and the generic tree_expr_nonnegative_p rule for ... < 0, which would
give the hoped-for 0.

The sqrt code already handles comparisons with negative values specially,
so this patch simply extends that idea to comparisons with zero.

Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi.

gcc/
* match.pd: Handle sqrt(x) cmp 0 specially.

gcc/testsuite/
* gcc.dg/torture/builtin-sqrt-cmp-1.c: New test.

From-SVN: r229422

gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/builtin-sqrt-cmp-1.c [new file with mode: 0644]

index a2933215b2ed70f0d295530caa8f40fcba097cd7..a90996651ea8ad957996f5e841c664d9d54f5dbf 100644 (file)
@@ -1,3 +1,7 @@
+2015-10-27  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * match.pd: Handle sqrt(x) cmp 0 specially.
+
 2015-10-27  Ilya Enkovich  <enkovich.gnu@gmail.com>
 
        * tree-vect-generic.c (expand_vector_operations_1): Check
index 26491d278408b962e731f727a11598eed2f8b37b..b8e6b4643c8a7d40dd39bd7b5cd22e50024bb4b9 100644 (file)
@@ -1973,6 +1973,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        { constant_boolean_node (true, type); })
        /* sqrt(x) > y is the same as x >= 0, if y is negative.  */
        (ge @0 { build_real (TREE_TYPE (@0), dconst0); })))
+     (if (real_equal (TREE_REAL_CST_PTR (@1), &dconst0))
+      (switch
+       /* sqrt(x) < 0 is always false.  */
+       (if (cmp == LT_EXPR)
+       { constant_boolean_node (false, type); })
+       /* sqrt(x) >= 0 is always true if we don't care about NaNs.  */
+       (if (cmp == GE_EXPR && !HONOR_NANS (@0))
+       { constant_boolean_node (true, type); })
+       /* sqrt(x) <= 0 -> x == 0.  */
+       (if (cmp == LE_EXPR)
+       (eq @0 @1))
+       /* Otherwise sqrt(x) cmp 0 -> x cmp 0.  Here cmp can be >=, >,
+          == or !=.  In the last case:
+
+           (sqrt(x) != 0) == (NaN != 0) == true == (x != 0)
+
+         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)
       (with
        {
index 8721999bd8f39ec5caf0d036042add009044dee2..cfc9f7a26cb78e4ad3f86cd79b8f1ff49e18ad0c 100644 (file)
@@ -1,3 +1,7 @@
+2015-10-27  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * gcc.dg/torture/builtin-sqrt-cmp-1.c: New test.
+
 2015-10-27  Richard Sandiford  <richard.sandiford@arm.com>
 
        * gcc.dg/builtins-52.c: Add -O to dg-options.
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-sqrt-cmp-1.c b/gcc/testsuite/gcc.dg/torture/builtin-sqrt-cmp-1.c
new file mode 100644 (file)
index 0000000..3f4a708
--- /dev/null
@@ -0,0 +1,53 @@
+/* { dg-do link } */
+/* { dg-options "-ffast-math" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+extern double sqrt (double);
+extern float sqrtf (float);
+extern long double sqrtl (long double);
+
+/* All references to link_error should go away at compile-time.  */
+extern void link_error (void);
+
+#define TEST_ONE(SUFFIX, TYPE)                 \
+  void __attribute__ ((noinline, noclone))     \
+  test##SUFFIX (TYPE f, int *res)              \
+  {                                            \
+    TYPE sqrt_res = sqrt##SUFFIX (f);          \
+    res[0] = sqrt_res < 0;                     \
+    if (res[0])                                        \
+      link_error ();                           \
+    res[1] = sqrt_res <= 0;                    \
+    if (res[1] != (f == 0))                    \
+      link_error ();                           \
+    res[2] = (sqrt_res == 0);                  \
+    if (res[2] != (f == 0))                    \
+      link_error ();                           \
+    res[3] = (sqrt_res != 0);                  \
+    if (res[3] != (f != 0))                    \
+      link_error ();                           \
+    res[4] = (sqrt_res > 0);                   \
+    if (res[4] != (f > 0))                     \
+      link_error ();                           \
+    res[5] = (sqrt_res >= 0);                  \
+    if (!res[5])                               \
+      link_error ();                           \
+  }
+
+volatile float f;
+volatile double d;
+volatile long double ld;
+
+TEST_ONE (f, float)
+TEST_ONE (, double)
+TEST_ONE (l, long double)
+
+int
+main ()
+{
+  int res[6];
+  testf (f, res);
+  test (d, res);
+  testl (ld, res);
+  return 0;
+}