diff options
author | James Greenhalgh <james.greenhalgh@arm.com> | 2015-09-17 08:23:05 +0000 |
---|---|---|
committer | James Greenhalgh <jgreenhalgh@gcc.gnu.org> | 2015-09-17 08:23:05 +0000 |
commit | fb0f04feaa6710087d04a5214394bd468d983a6b (patch) | |
tree | b83481dc814025c58c58a64ff47444650c086743 /gcc | |
parent | bb6b3973cc5738eab821d4fd8a61d14266d8a503 (diff) | |
download | gcc-fb0f04feaa6710087d04a5214394bd468d983a6b.zip gcc-fb0f04feaa6710087d04a5214394bd468d983a6b.tar.gz gcc-fb0f04feaa6710087d04a5214394bd468d983a6b.tar.bz2 |
[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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/config/aarch64/aarch64.md | 46 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/copysign_1.c | 81 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/copysign_2.c | 81 |
5 files changed, 218 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 42faf2e..dcc6f2f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2015-09-17 James Greenhalgh <james.greenhalgh@arm.com> + + * config/aarch64/aarch64.md (copysigndf3): New. + (copysignsf3): Likewise. + 2015-09-17 David S. Miller <davem@davemloft.net> * config/sparc/sparc-protos.h (sparc_secondary_memory_needed): diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 88ba72e..925c6b1 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -4412,6 +4412,52 @@ [(set_attr "type" "f_minmax<s>")] ) +;; 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 bea9258..ab7f1cc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-09-17 James Greenhalgh <james.greenhalgh@arm.com> + + * gcc.target/aarch64/copysign_1.c: New. + * gcc.target/aarch64/copysign_2.c: New. + 2015-09-17 Bin Cheng <bin.cheng@arm.com> * 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 0000000..27fb9ca --- /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 0000000..6eaa704 --- /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" } } */ + |