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 <[email protected]>
* match.pd (mult (COPYSIGN:s real_onep @0) @1): New simplifier.
gcc/testsuite/
2015-10-01 James Greenhalgh <[email protected]>
* 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"} } */