Hi,

If it is cheap enough to treat a floating-point value as an integer and
to do bitwise arithmetic on it (as it is for AArch64) we can rewrite:

  x * copysign (1.0, y)

as:

  x ^ (y & (1 << sign_bit_position))

This patch implements that rewriting rule in match.pd, and a testcase
expecting the transform.

This is worth about 6% in 481.wrf for AArch64. I don't don't know enough
about the x86 microarchitectures to know how productive this transformation
is there. In Spec2006FP I didn't see any interesting results in either
direction. Looking at code generation for the testcase I add, I think the
x86 code generation looks worse, but I can't understand why it doesn't use
a vector-side xor and load the mask vector-side. With that fixed up I think
the code generation would look better - though as I say, I'm not an expert
here...

Bootstrapped on both aarch64-none-linux-gnu and x86_64 with no issues.

OK for trunk?

Thanks,
James

---
gcc/

2015-10-01  James Greenhalgh  <james.greenha...@arm.com>

        * match.pd (mult (COPYSIGN:s real_onep @0) @1): New simplifier.

gcc/testsuite/

2015-10-01  James Greenhalgh  <james.greenha...@arm.com>

        * gcc.dg/tree-ssa/copysign.c: New.

diff --git a/gcc/match.pd b/gcc/match.pd
index bd5c267..d51ad2e 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 (define_operator_list TAN BUILT_IN_TANF BUILT_IN_TAN BUILT_IN_TANL)
 (define_operator_list COSH BUILT_IN_COSHF BUILT_IN_COSH BUILT_IN_COSHL)
 (define_operator_list CEXPI BUILT_IN_CEXPIF BUILT_IN_CEXPI BUILT_IN_CEXPIL)
+(define_operator_list COPYSIGN BUILT_IN_COPYSIGNF BUILT_IN_COPYSIGN BUILT_IN_COPYSIGNL)
 
 /* Simplifications of operations with one constant operand and
    simplifications to constants or single values.  */
@@ -2079,6 +2080,21 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Simplification of math builtins.  */
 
+/* Simplify x * copysign (1.0, y) -> x ^ (y & (1 << sign_bit_position)).  */
+(simplify
+  (mult:c (COPYSIGN:s real_onep @0) @1)
+  (with
+    {
+      wide_int m = wi::min_value (TYPE_PRECISION (type), SIGNED);
+      tree tt
+	= build_nonstandard_integer_type (TYPE_PRECISION (type),
+					  false);
+      tree mask = wide_int_to_tree (tt, m);
+    }
+    (view_convert (bit_xor (view_convert:tt @1)
+			   (bit_and (view_convert:tt @0)
+				     { mask; })))))
+
 /* fold_builtin_logarithm */
 (if (flag_unsafe_math_optimizations)
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copysign.c b/gcc/testsuite/gcc.dg/tree-ssa/copysign.c
new file mode 100644
index 0000000..b67f3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/copysign.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-gimple" } */
+
+double
+foo_d (double x, double y)
+{
+  return x * __builtin_copysign (1.0, y);
+}
+
+float
+foo_f (float x, float y)
+{
+  return x * __builtin_copysignf (1.0f, y);
+}
+
+long double
+foo_l (long double x, long double y)
+{
+  return x * __builtin_copysignl (1.0, y);
+}
+
+/* { dg-final { scan-tree-dump-not "copysign" "gimple"} } */

Reply via email to