summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/sh/sh.md147
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.target/sh/pr51244-10.c27
-rw-r--r--gcc/testsuite/gcc.target/sh/pr51244-7.c26
-rw-r--r--gcc/testsuite/gcc.target/sh/pr51244-8.c27
-rw-r--r--gcc/testsuite/gcc.target/sh/pr51244-9.c35
7 files changed, 258 insertions, 23 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0d411c71b43..c327437dc00 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2012-08-12 Oleg Endo <olegendo@gcc.gnu.org>
+
+ PR target/51244
+ * config/sh/sh.md: Add splits for inverted compare and branch
+ opportunities.
+ (*cmpeqsi_t): New insn.
+ (cmpgtsi_t, cmpgesi_t): Swap r and N alternatives.
+ (cmpgeusi_t): Use satisfies_constraint_Z. Emit sett insn in
+ replacement insn list and not in the preparation statements.
+ (clrt, sett): Add mt_group attribute.
+
2012-08-12 Marc Glisse <marc.glisse@inria.fr>
PR middle-end/54193
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index ffa899d3a48..8af99f8e49e 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -742,12 +742,6 @@
}
[(set_attr "type" "mt_group")])
-;; ??? Perhaps should only accept reg/constant if the register is reg 0.
-;; That would still allow reload to create cmpi instructions, but would
-;; perhaps allow forcing the constant into a register when that is better.
-;; Probably should use r0 for mem/imm compares, but force constant into a
-;; register for pseudo/imm compares.
-
(define_insn "cmpeqsi_t"
[(set (reg:SI T_REG)
(eq:SI (match_operand:SI 0 "arith_reg_operand" "r,z,r")
@@ -759,24 +753,40 @@
cmp/eq %1,%0"
[(set_attr "type" "mt_group")])
+;; FIXME: For some reason, on SH4A and SH2A combine fails to simplify this
+;; pattern by itself. What this actually does is:
+;; x == 0: (1 >> 0-0) & 1 = 1
+;; x != 0: (1 >> 0-x) & 1 = 0
+;; Without this the test pr51244-8.c fails on SH2A and SH4A.
+(define_insn_and_split "*cmpeqsi_t"
+ [(set (reg:SI T_REG)
+ (and:SI (lshiftrt:SI
+ (const_int 1)
+ (neg:SI (match_operand:SI 0 "arith_reg_operand" "r")))
+ (const_int 1)))]
+ "TARGET_SH1"
+ "#"
+ "&& 1"
+ [(set (reg:SI T_REG) (eq:SI (match_dup 0) (const_int 0)))])
+
(define_insn "cmpgtsi_t"
[(set (reg:SI T_REG)
(gt:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
- (match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
+ (match_operand:SI 1 "arith_reg_or_0_operand" "N,r")))]
"TARGET_SH1"
"@
- cmp/gt %1,%0
- cmp/pl %0"
+ cmp/pl %0
+ cmp/gt %1,%0"
[(set_attr "type" "mt_group")])
(define_insn "cmpgesi_t"
[(set (reg:SI T_REG)
(ge:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
- (match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
+ (match_operand:SI 1 "arith_reg_or_0_operand" "N,r")))]
"TARGET_SH1"
"@
- cmp/ge %1,%0
- cmp/pz %0"
+ cmp/pz %0
+ cmp/ge %1,%0"
[(set_attr "type" "mt_group")])
;; FIXME: This is actually wrong. There is no way to literally move a
@@ -815,6 +825,99 @@
DONE;
})
+;; Combine patterns to invert compare and branch operations for which we
+;; don't have actual comparison insns. These patterns are used in cases
+;; which appear after the initial cbranchsi expansion, which also does
+;; some condition inversion.
+
+(define_split
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_or_0_operand" ""))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ [(set (reg:SI T_REG) (eq:SI (match_dup 0) (match_dup 1)))
+ (set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+;; FIXME: Similar to the *cmpeqsi_t pattern above, for some reason, on SH4A
+;; and SH2A combine fails to simplify this pattern by itself.
+;; What this actually does is:
+;; x == 0: (1 >> 0-0) & 1 = 1
+;; x != 0: (1 >> 0-x) & 1 = 0
+;; Without this the test pr51244-8.c fails on SH2A and SH4A.
+(define_split
+ [(set (pc)
+ (if_then_else
+ (eq (and:SI (lshiftrt:SI
+ (const_int 1)
+ (neg:SI (match_operand:SI 0 "arith_reg_operand" "")))
+ (const_int 1))
+ (const_int 0))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ [(set (reg:SI T_REG) (eq:SI (match_dup 0) (const_int 0)))
+ (set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+(define_split
+ [(set (pc)
+ (if_then_else (le (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_or_0_operand" ""))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ [(set (reg:SI T_REG) (gt:SI (match_dup 0) (match_dup 1)))
+ (set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+(define_split
+ [(set (pc)
+ (if_then_else (lt (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_or_0_operand" ""))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ [(set (reg:SI T_REG) (ge:SI (match_dup 0) (match_dup 1)))
+ (set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+(define_split
+ [(set (pc)
+ (if_then_else (leu (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_operand" ""))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ [(set (reg:SI T_REG) (gtu:SI (match_dup 0) (match_dup 1)))
+ (set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
+(define_split
+ [(set (pc)
+ (if_then_else (ltu (match_operand:SI 0 "arith_reg_operand" "")
+ (match_operand:SI 1 "arith_reg_operand" ""))
+ (label_ref (match_operand 2))
+ (pc)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ [(set (reg:SI T_REG) (geu:SI (match_dup 0) (match_dup 1)))
+ (set (pc) (if_then_else (eq (reg:SI T_REG) (const_int 0))
+ (label_ref (match_dup 2))
+ (pc)))])
+
;; -------------------------------------------------------------------------
;; SImode unsigned integer comparisons
;; -------------------------------------------------------------------------
@@ -825,13 +928,10 @@
(match_operand:SI 1 "arith_reg_or_0_operand" "rN")))]
"TARGET_SH1"
"cmp/hs %1,%0"
- "&& operands[1] == CONST0_RTX (SImode)"
- [(pc)]
-{
- emit_insn (gen_sett ());
- DONE;
-}
- [(set_attr "type" "mt_group")])
+ "&& satisfies_constraint_Z (operands[0])"
+ [(set (reg:SI T_REG) (const_int 1))]
+ ""
+ [(set_attr "type" "mt_group")])
(define_insn "cmpgtusi_t"
[(set (reg:SI T_REG)
@@ -839,7 +939,7 @@
(match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"cmp/hi %1,%0"
- [(set_attr "type" "mt_group")])
+ [(set_attr "type" "mt_group")])
;; -------------------------------------------------------------------------
@@ -5132,13 +5232,14 @@ label:
(define_insn "clrt"
[(set (reg:SI T_REG) (const_int 0))]
"TARGET_SH1"
- "clrt")
+ "clrt"
+ [(set_attr "type" "mt_group")])
(define_insn "sett"
[(set (reg:SI T_REG) (const_int 1))]
"TARGET_SH1"
- "sett")
-
+ "sett"
+ [(set_attr "type" "mt_group")])
;; Use the combine pass to transform sequences such as
;; mov r5,r0
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1b1b42d4d76..f8b52217b2b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,13 @@
2012-08-12 Oleg Endo <olegendo@gcc.gnu.org>
+ PR target/51244
+ * gcc.target/sh/pr51244-7.c: New.
+ * gcc.target/sh/pr51244-8.c: New.
+ * gcc.target/sh/pr51244-9.c: New.
+ * gcc.target/sh/pr51244-10.c: New.
+
+2012-08-12 Oleg Endo <olegendo@gcc.gnu.org>
+
* gcc.target/sh/pr50749-sf-postinc-1.c: Skip for -m3. Don't skip for
-m2e or -m2a.
* gcc.target/sh/pr50749-sf-postinc-3.c: Likewise.
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-10.c b/gcc/testsuite/gcc.target/sh/pr51244-10.c
new file mode 100644
index 00000000000..20f052eedda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr51244-10.c
@@ -0,0 +1,27 @@
+/* Check that compare-branch is inverted properly.
+ In this case the improved bit test is a side effect of compare-branch
+ inversion patterns, even though the branch condition does not get
+ inverted here.
+ Example:
+ mov.b @(14,r9),r0 -> mov.b @(14,r9),r0
+ shll r0 cmp/pz r0
+ subc r0,r0 bt .L192
+ and #1,r0
+ tst r0,r0
+ bt .L195
+*/
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "shll|subc|and" } } */
+int
+test_00 (int* p)
+{
+ int nr = 15;
+ volatile char* addr = (volatile char*)&p[1];
+
+ if ((addr[(nr >> 3) ^ 7] & (1 << (nr & 7))) == 0)
+ return 40;
+ else
+ return 50;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-7.c b/gcc/testsuite/gcc.target/sh/pr51244-7.c
new file mode 100644
index 00000000000..e7e3ac1385c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr51244-7.c
@@ -0,0 +1,26 @@
+/* Check that compare-branch is inverted properly.
+ Example:
+ clrt -> clrt
+ subc r0,r6 subc r0,r6
+ mov r3,r7 mov r3,r7
+ subc r1,r7 subc r1,r7
+ mov #0,r1 tst r7,r7
+ cmp/hi r1,r7 bf .L111
+ bt .L111 bra .L197
+ bra .L197
+ nop
+*/
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "cmp/hi" } } */
+/* { dg-final { scan-assembler-not "mov\t#0" } } */
+
+int other_func (long long);
+int
+test_00 (unsigned long long a, unsigned long long b)
+{
+ if ((a - b) > 0xFFFFFFFFLL)
+ return other_func (a - b);
+ return 20;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-8.c b/gcc/testsuite/gcc.target/sh/pr51244-8.c
new file mode 100644
index 00000000000..9d95ae3f87a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr51244-8.c
@@ -0,0 +1,27 @@
+/* Check that compare-branch is inverted properly.
+ Example:
+ mov #1,r0 -> tst r8,r8
+ neg r8,r1 bt .L47
+ shad r1,r0
+ tst #1,r0
+ bf .L47
+*/
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "shad|neg" } } */
+
+int test_01_00 (int*, void*);
+int
+test_01 (int* m, void* v)
+{
+ unsigned long n = (unsigned long)v - 1;
+
+ if (!n)
+ return 50;
+
+ if (1 & (1 << n)) /* if n == 0: 1 & (1 << 0) -> true */
+ return 60;
+ else /* if n != 0: 1 & (1 << n) -> false */
+ return -8;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr51244-9.c b/gcc/testsuite/gcc.target/sh/pr51244-9.c
new file mode 100644
index 00000000000..13639bdc87d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr51244-9.c
@@ -0,0 +1,35 @@
+/* Check that compare-branch is inverted properly.
+ Example:
+ mov.w .L566,r2 -> mov.w .L566,r2
+ add r11,r2 add r11,r2
+ mov.l @(12,r2),r7 mov.l @(8,r2),r5
+ mov.l @(8,r2),r5 mov.l @(12,r2),r2
+ mov #0,r2 tst r2,r2
+ cmp/hi r2,r7 bt .L534
+ bf .L534
+*/
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */
+/* { dg-final { scan-assembler-not "mov\t#0" } } */
+static inline unsigned int
+test_03_00 (unsigned int x)
+{
+ /* Return unassigned value on purpose. */
+ unsigned int res;
+ return res;
+}
+
+struct S
+{
+ unsigned int a;
+ unsigned int b;
+};
+
+int test_03 (struct S* i)
+{
+ if ((i->a != 2 && i->a != 3) || i->a > test_03_00 (i->b))
+ return -5;
+
+ return -55;
+}