diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 97 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr59216.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/negdi-4.c | 16 |
5 files changed, 105 insertions, 51 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fcfae83e0cd..c1320a5807b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2013-11-22 Richard Earnshaw <rearnsha@arm.com> + + PR target/59216 + * arm.md (negdi_extendsidi): Fix invalid split. + 2013-11-22 Alex Velenko <Alex.Velenko@arm.com> * config/aarch64/arm_neon.h (vmov_n_f32): Implemented in C. diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index a26550a476a..8e52003af1c 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -4710,47 +4710,74 @@ ;; Negate an extended 32-bit value. (define_insn_and_split "*negdi_extendsidi" - [(set (match_operand:DI 0 "s_register_operand" "=r,&r,l,&l") - (neg:DI (sign_extend:DI (match_operand:SI 1 "s_register_operand" "0,r,0,l")))) + [(set (match_operand:DI 0 "s_register_operand" "=l,r") + (neg:DI (sign_extend:DI + (match_operand:SI 1 "s_register_operand" "l,r")))) (clobber (reg:CC CC_REGNUM))] "TARGET_32BIT" - "#" ; rsb\\t%Q0, %1, #0\;asr\\t%R0, %Q0, #31 + "#" "&& reload_completed" [(const_int 0)] { - operands[2] = gen_highpart (SImode, operands[0]); - operands[0] = gen_lowpart (SImode, operands[0]); - rtx tmp = gen_rtx_SET (VOIDmode, - operands[0], - gen_rtx_MINUS (SImode, - const0_rtx, - operands[1])); - if (TARGET_ARM) - { - emit_insn (tmp); - } - else - { - /* Set the flags, to emit the short encoding in Thumb2. */ - rtx flags = gen_rtx_SET (VOIDmode, - gen_rtx_REG (CCmode, CC_REGNUM), - gen_rtx_COMPARE (CCmode, - const0_rtx, - operands[1])); - emit_insn (gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, - flags, - tmp))); - } - emit_insn (gen_rtx_SET (VOIDmode, - operands[2], - gen_rtx_ASHIFTRT (SImode, - operands[0], - GEN_INT (31)))); - DONE; + rtx low = gen_lowpart (SImode, operands[0]); + rtx high = gen_highpart (SImode, operands[0]); + + if (reg_overlap_mentioned_p (low, operands[1])) + { + /* Input overlaps the low word of the output. Use: + asr Rhi, Rin, #31 + rsbs Rlo, Rin, #0 + rsc Rhi, Rhi, #0 (thumb2: sbc Rhi, Rhi, Rhi, lsl #1). */ + rtx cc_reg = gen_rtx_REG (CC_Cmode, CC_REGNUM); + + emit_insn (gen_rtx_SET (VOIDmode, high, + gen_rtx_ASHIFTRT (SImode, operands[1], + GEN_INT (31)))); + + emit_insn (gen_subsi3_compare (low, const0_rtx, operands[1])); + if (TARGET_ARM) + emit_insn (gen_rtx_SET (VOIDmode, high, + gen_rtx_MINUS (SImode, + gen_rtx_MINUS (SImode, + const0_rtx, + high), + gen_rtx_LTU (SImode, + cc_reg, + const0_rtx)))); + else + { + rtx two_x = gen_rtx_ASHIFT (SImode, high, GEN_INT (1)); + emit_insn (gen_rtx_SET (VOIDmode, high, + gen_rtx_MINUS (SImode, + gen_rtx_MINUS (SImode, + high, + two_x), + gen_rtx_LTU (SImode, + cc_reg, + const0_rtx)))); + } + } + else + { + /* No overlap, or overlap on high word. Use: + rsb Rlo, Rin, #0 + bic Rhi, Rlo, Rin + asr Rhi, Rhi, #31 + Flags not needed for this sequence. */ + emit_insn (gen_rtx_SET (VOIDmode, low, + gen_rtx_NEG (SImode, operands[1]))); + emit_insn (gen_rtx_SET (VOIDmode, high, + gen_rtx_AND (SImode, + gen_rtx_NOT (SImode, operands[1]), + low))); + emit_insn (gen_rtx_SET (VOIDmode, high, + gen_rtx_ASHIFTRT (SImode, high, + GEN_INT (31)))); + } + DONE; } - [(set_attr "length" "8,8,4,4") - (set_attr "arch" "a,a,t2,t2") + [(set_attr "length" "12") + (set_attr "arch" "t2,*") (set_attr "type" "multiple")] ) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 270c53cbc5b..38c359e1fe0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-11-22 Richard Earnshaw <rearnsha@arm.com> + + PR target/59216 + * gcc.target/arm/negdi-4.c: Delete invalid test. + * gcc.dg/torture/pr59216.c: New test. + 2013-11-22 Alex Velenko <Alex.Velenko@arm.com> * gcc.target/aarch64/vmov_n_1.c: New testcase. diff --git a/gcc/testsuite/gcc.dg/torture/pr59216.c b/gcc/testsuite/gcc.dg/torture/pr59216.c new file mode 100644 index 00000000000..0de51bac95b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr59216.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ + +#include <limits.h> + +extern void abort (void); +extern void exit (int); + +long long __attribute__((noinline)) f(int a) +{ + return -(long long) a; +} + +int +main() +{ + if (f(0) != 0) + abort (); + + if (f(1) != -(long long)1) + abort (); + + if (f(-1) != -(long long)-1) + abort (); + + if (f(INT_MIN) != -(long long)INT_MIN) + abort (); + + if (f(INT_MAX) != -(long long)INT_MAX) + abort (); + + exit (0); +} diff --git a/gcc/testsuite/gcc.target/arm/negdi-4.c b/gcc/testsuite/gcc.target/arm/negdi-4.c deleted file mode 100644 index dc3deaad5ad..00000000000 --- a/gcc/testsuite/gcc.target/arm/negdi-4.c +++ /dev/null @@ -1,16 +0,0 @@ -/* { dg-do compile } */ -/* { dg-require-effective-target arm32 } */ -/* { dg-options "-O2" } */ - -signed long long negdi_extendsidi (signed int x) -{ - return -((signed long long) x); -} -/* -Expected output: - rsbs r0, r0, #0 - mov r1, r0, asr #31 -*/ -/* { dg-final { scan-assembler-times "rsb" 1 } } */ -/* { dg-final { scan-assembler-times "asr" 1 } } */ -/* { dg-final { scan-assembler-times "rsc" 0 } } */ |