From: Richard Sandiford Date: Tue, 27 Oct 2015 11:51:43 +0000 (+0000) Subject: Fold comparisons between sqrt and zero X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c53233c660496efed5115ec1f30d3009ecf716d6;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a2933215b2e..a90996651ea 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2015-10-27 Richard Sandiford + + * match.pd: Handle sqrt(x) cmp 0 specially. + 2015-10-27 Ilya Enkovich * tree-vect-generic.c (expand_vector_operations_1): Check diff --git a/gcc/match.pd b/gcc/match.pd index 26491d27840..b8e6b4643c8 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 8721999bd8f..cfc9f7a26cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-10-27 Richard Sandiford + + * gcc.dg/torture/builtin-sqrt-cmp-1.c: New test. + 2015-10-27 Richard Sandiford * 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 index 00000000000..3f4a7084056 --- /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; +}