aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/config/arm/arm.md97
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr59216.c32
-rw-r--r--gcc/testsuite/gcc.target/arm/negdi-4.c16
5 files changed, 105 insertions, 51 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fcfae83..c1320a5 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 a26550a..8e52003 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 270c53c..38c359e 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 0000000..0de51ba
--- /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 dc3deaa..0000000
--- 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 } } */