aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-10-27 11:51:43 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-10-27 11:51:43 +0000
commitc53233c660496efed5115ec1f30d3009ecf716d6 (patch)
tree81cfb3c2323bef8e2dc2dea990e95e29dc92fc9d /gcc
parent3f8c04e73cd50d34d2b9f4128c615dbd35a6e40a (diff)
downloadgcc-c53233c660496efed5115ec1f30d3009ecf716d6.zip
gcc-c53233c660496efed5115ec1f30d3009ecf716d6.tar.gz
gcc-c53233c660496efed5115ec1f30d3009ecf716d6.tar.bz2
Fold comparisons between sqrt and zero
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/match.pd19
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/torture/builtin-sqrt-cmp-1.c53
4 files changed, 80 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a293321..a909966 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/match.pd b/gcc/match.pd
index 26491d2..b8e6b46 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -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
{
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8721999..cfc9f7a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
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.
2015-10-27 Richard Sandiford <richard.sandiford@arm.com>
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
index 0000000..3f4a708
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-sqrt-cmp-1.c
@@ -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;
+}