From: James Greenhalgh Date: Thu, 17 Sep 2015 08:23:05 +0000 (+0000) Subject: [AArch64] Implement copysign[ds]f3 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fb0f04feaa6710087d04a5214394bd468d983a6b;p=gcc.git [AArch64] Implement copysign[ds]f3 gcc/ * config/aarch64/aarch64.md (copysigndf3): New. (copysignsf3): Likewise. gcc/testsuite/ * gcc.target/aarch64/copysign_1.c: New. * gcc.target/aarch64/copysign_2.c: New. From-SVN: r227849 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 42faf2ed542..dcc6f2f4347 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2015-09-17 James Greenhalgh + + * config/aarch64/aarch64.md (copysigndf3): New. + (copysignsf3): Likewise. + 2015-09-17 David S. Miller * config/sparc/sparc-protos.h (sparc_secondary_memory_needed): diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 88ba72e3ac7..925c6b1d377 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -4412,6 +4412,52 @@ [(set_attr "type" "f_minmax")] ) +;; For copysign (x, y), we want to generate: +;; +;; LDR d2, #(1 << 63) +;; BSL v2.8b, [y], [x] +;; +;; or another, equivalent, sequence using one of BSL/BIT/BIF. +;; aarch64_simd_bsldf will select the best suited of these instructions +;; to generate based on register allocation, and knows how to partially +;; constant fold based on the values of X and Y, so expand through that. + +(define_expand "copysigndf3" + [(match_operand:DF 0 "register_operand") + (match_operand:DF 1 "register_operand") + (match_operand:DF 2 "register_operand")] + "TARGET_FLOAT && TARGET_SIMD" +{ + rtx mask = gen_reg_rtx (DImode); + emit_move_insn (mask, GEN_INT (HOST_WIDE_INT_1U << 63)); + emit_insn (gen_aarch64_simd_bsldf (operands[0], mask, + operands[2], operands[1])); + DONE; +} +) + +;; As above, but we must first get to a 64-bit value if we wish to use +;; aarch64_simd_bslv2sf. + +(define_expand "copysignsf3" + [(match_operand:SF 0 "register_operand") + (match_operand:SF 1 "register_operand") + (match_operand:SF 2 "register_operand")] + "TARGET_FLOAT && TARGET_SIMD" +{ + rtx mask = gen_reg_rtx (DImode); + + /* Juggle modes to get us in to a vector mode for BSL. */ + rtx op1 = lowpart_subreg (V2SFmode, operands[1], SFmode); + rtx op2 = lowpart_subreg (V2SFmode, operands[2], SFmode); + rtx tmp = gen_reg_rtx (V2SFmode); + emit_move_insn (mask, GEN_INT (HOST_WIDE_INT_1U << 31)); + emit_insn (gen_aarch64_simd_bslv2sf (tmp, mask, op2, op1)); + emit_move_insn (operands[0], lowpart_subreg (SFmode, tmp, V2SFmode)); + DONE; +} +) + ;; ------------------------------------------------------------------- ;; Reload support ;; ------------------------------------------------------------------- diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bea92585038..ab7f1cc5f1a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-09-17 James Greenhalgh + + * gcc.target/aarch64/copysign_1.c: New. + * gcc.target/aarch64/copysign_2.c: New. + 2015-09-17 Bin Cheng * gcc.dg/tree-ssa/loop-bound-2.c: New test. diff --git a/gcc/testsuite/gcc.target/aarch64/copysign_1.c b/gcc/testsuite/gcc.target/aarch64/copysign_1.c new file mode 100644 index 00000000000..27fb9ca4ed7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/copysign_1.c @@ -0,0 +1,81 @@ +/* { dg-do run } */ +/* { dg-options "-O2 --save-temps" } */ + +double fabs (double); + +double +check (double x, double y) +{ + return __builtin_copysign (x, y); +} + +double +check1 (double x) +{ + return __builtin_copysign (x, 1.0); +} + +double +check2 (double x) +{ + return __builtin_copysign (1.0, x); +} + +double +check3 (double x) +{ + return -__builtin_copysign (x, 1.0); +} + +double +check4 (double x, double y) +{ + return x * __builtin_copysign (x, y); +} + +double +check5 (double x, double y) +{ + return __builtin_copysign (-x, -y); +} + +int +main (int argc, char** argv) +{ + double x = 2.0; + double y = -5.0; + double epsilon = 0.00001; + + double expected = -2.0; + + if (fabs (check (x, y) - expected) >= epsilon) + __builtin_abort (); + + expected = 2.0; + + if (fabs (check1 (x) - expected) >= epsilon) + __builtin_abort (); + + expected = 1.0; + + if (fabs (check2 (x) - expected) >= epsilon) + __builtin_abort (); + + expected = -2.0; + + if (fabs (check3 (x) - expected) >= epsilon) + __builtin_abort (); + + expected = -4.0; + + if (fabs (check4 (x, y) - expected) >= epsilon) + __builtin_abort (); + + expected = 2.0; + + if (fabs (check5 (x, y) - expected) >= epsilon) + __builtin_abort (); +} + +/* { dg-final { scan-assembler-not "copysign\tw" } } */ + diff --git a/gcc/testsuite/gcc.target/aarch64/copysign_2.c b/gcc/testsuite/gcc.target/aarch64/copysign_2.c new file mode 100644 index 00000000000..6eaa70413a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/copysign_2.c @@ -0,0 +1,81 @@ +/* { dg-do run } */ +/* { dg-options "-O2 --save-temps" } */ + +float fabsf (float); + +float +check (float x, float y) +{ + return __builtin_copysignf (x, y); +} + +float +check1 (float x) +{ + return __builtin_copysignf (x, 1.0); +} + +float +check2 (float x) +{ + return __builtin_copysignf (1.0, x); +} + +float +check3 (float x) +{ + return -__builtin_copysignf (x, 1.0); +} + +float +check4 (float x, float y) +{ + return x * __builtin_copysignf (x, y); +} + +float +check5 (float x, float y) +{ + return __builtin_copysignf (-x, -y); +} + +int +main (int argc, char** argv) +{ + float x = 2.0f; + float y = -5.0f; + float epsilon = 0.00001f; + + float expected = -2.0f; + + if (fabsf (check (x, y) - expected) >= epsilon) + __builtin_abort (); + + expected = 2.0f; + + if (fabsf (check1 (x) - expected) >= epsilon) + __builtin_abort (); + + expected = 1.0f; + + if (fabsf (check2 (x) - expected) >= epsilon) + __builtin_abort (); + + expected = -2.0f; + + if (fabsf (check3 (x) - expected) >= epsilon) + __builtin_abort (); + + expected = -4.0f; + + if (fabsf (check4 (x, y) - expected) >= epsilon) + __builtin_abort (); + + expected = 2.0f; + + if (fabsf (check5 (x, y) - expected) >= epsilon) + __builtin_abort (); +} + +/* { dg-final { scan-assembler-not "copysign\tw" } } */ +