This patch adds patterns to handle negation of an extended 32-bit value more
efficiently.
For example,
(set (reg:DI r0) (neg:DI (sign_extend:DI (reg:SI r0)))
The compiler currently generates
mov r1, r0, asr #31
rsbs r0, r0, #0
rsc r1, r1, #0
and after the patch it generates:
rsb r0, r0, #0
mov r1, r0, asr #31
(set (reg:DI r0) (neg:DI (zero_extend:DI (reg:SI r0)))
The compiler currently generates
mov r1, #0
rsbs r0, r0, #0
rsc r1, r1, #0
and after the patch it generates:
rsbs r0, r0, #0
sbc r1, r1, r1
The following examples are not affected by the patch:
(set (reg:DI r0) (sign_extend:DI (neg:SI (reg:SI r0)))
rsb r0, r0, #0
mov r1, r0, asr #31
(set (reg:DI r0) (zero_extend:DI (neg:SI (reg:SI r0)))
rsb r0, r0, #0
mov r1, #0
The patch also adds the appropriate test cases.
gcc/
2013-01-10 Greta Yorsh <[email protected]>
* config/arm/arm.md (negdi_extendsidi): New pattern.
(negdi_zero_extendsidi): Likewise.
gcc/testsuite
2013-01-10 Greta Yorsh <[email protected]>
* gcc.target/arm/negdi-1.c: New test.
* gcc.target/arm/negdi-2.c: Likewise.
* gcc.target/arm/negdi-3.c: Likewise.
* gcc.target/arm/negdi-4.c: Likewise.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index
de57f40c20ad89a71dc9b3b172b9d5666afde9f8..0000000000000000000000000000000000000000
100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -4207,6 +4207,72 @@ (define_expand "negdf2"
"TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
"")
+;; 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"))))
+ (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))));
+ }
+ [(set_attr "length" "8,8,4,4")
+ (set_attr "arch" "a,a,t2,t2")]
+)
+
+(define_insn_and_split "*negdi_zero_extendsidi"
+ [(set (match_operand:DI 0 "s_register_operand" "=r,&r")
+ (neg:DI (zero_extend:DI (match_operand:SI 1 "s_register_operand"
"0,r"))))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_32BIT"
+ "#" ; "rsbs\\t%Q0, %1, #0\;sbc\\t%R0,%R0,%R0"
+ ;; Don't care what register is input to sbc,
+ ;; since we just just need to propagate the carry.
+ "&& reload_completed"
+ [(parallel [(set (reg:CC CC_REGNUM)
+ (compare:CC (const_int 0) (match_dup 1)))
+ (set (match_dup 0) (minus:SI (const_int 0) (match_dup 1)))])
+ (set (match_dup 2) (minus:SI (minus:SI (match_dup 2) (match_dup 2))
+ (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
+ {
+ operands[2] = gen_highpart (SImode, operands[0]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ }
+ [(set_attr "conds" "clob")
+ (set_attr "length" "8")] ;; length in thumb is 4
+)
+
;; abssi2 doesn't really clobber the condition codes if a different register
;; is being set. To keep things simple, assume during rtl manipulations that
;; it does, but tell the final scan operator the truth. Similarly for
diff --git a/gcc/testsuite/gcc.target/arm/negdi-1.c
b/gcc/testsuite/gcc.target/arm/negdi-1.c
index ...7cd80ea3dc397f4c0eee688de5d6b49c685e869f 100644
--- a/gcc/testsuite/gcc.target/arm/negdi-1.c
+++ b/gcc/testsuite/gcc.target/arm/negdi-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O2" } */
+
+signed long long extendsidi_negsi (signed int x)
+{
+ return -x;
+}
+
+/*
+Expected output:
+ rsb r0, r0, #0
+ mov r1, r0, asr #31
+*/
+/* { dg-final { scan-assembler-times "rsb\\tr0, r0, #0" 1 { target {
arm_nothumb } } } } */
+/* { dg-final { scan-assembler-times "negs\\tr0" 1 { target { ! arm_nothumb }
} } } */
+/* { dg-final { scan-assembler-times "asr" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/negdi-2.c
b/gcc/testsuite/gcc.target/arm/negdi-2.c
index ...96bbcab337e54cdb072fc11f19cf412b56b463a5 100644
--- a/gcc/testsuite/gcc.target/arm/negdi-2.c
+++ b/gcc/testsuite/gcc.target/arm/negdi-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O2" } */
+
+signed long long zero_extendsidi_negsi (unsigned int x)
+{
+ return -x;
+}
+/*
+Expected output:
+ rsb r0, r0, #0
+ mov r1, #0
+*/
+/* { dg-final { scan-assembler-times "rsb\\tr0, r0, #0" 1 { target {
arm_nothumb } } } } */
+/* { dg-final { scan-assembler-times "negs\\tr0, r0" 1 { target { !
arm_nothumb } } } } */
+/* { dg-final { scan-assembler-times "mov" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/negdi-3.c
b/gcc/testsuite/gcc.target/arm/negdi-3.c
index ...76ddf49fc0ddb8b0287b8e30f72962ea25d12438 100644
--- a/gcc/testsuite/gcc.target/arm/negdi-3.c
+++ b/gcc/testsuite/gcc.target/arm/negdi-3.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O2" } */
+
+signed long long negdi_zero_extendsidi (unsigned int x)
+{
+ return -((signed long long) x);
+}
+/*
+Expected output:
+ rsbs r0, r0, #0
+ sbc r1, r1, r1
+*/
+/* { dg-final { scan-assembler-times "rsb" 1 } } */
+/* { dg-final { scan-assembler-times "sbc" 1 } } */
+/* { dg-final { scan-assembler-times "mov" 0 } } */
+/* { dg-final { scan-assembler-times "rsc" 0 } } */
diff --git a/gcc/testsuite/gcc.target/arm/negdi-4.c
b/gcc/testsuite/gcc.target/arm/negdi-4.c
index ...981b1a955a6547049864b3379e9fe595ebb47f2f 100644
--- a/gcc/testsuite/gcc.target/arm/negdi-4.c
+++ b/gcc/testsuite/gcc.target/arm/negdi-4.c
@@ -0,0 +1,16 @@
+/* { 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 } } */