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"} } */