diff options
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 147 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr51244-10.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr51244-7.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr51244-8.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr51244-9.c | 35 |
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; +} |