diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 35acd1eb678..a6fcec3a2e5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2012-10-30 Oleg Endo + + PR target/54988 + * config/sh/sh.md (tstqi_t_zero): Rename to *tstqi_t_zero. + (*tst_t_zero): New insns. + * config/sh/iterators.md (lowpart_be, lowpart_le): New mode attributes. + 2012-10-30 H.J. Lu * gimple-pretty-print.c (dump_gimple_bb_header): Avoid alloca. diff --git a/gcc/config/sh/iterators.md b/gcc/config/sh/iterators.md index e118c3ef1cd..c68c37eed2d 100644 --- a/gcc/config/sh/iterators.md +++ b/gcc/config/sh/iterators.md @@ -38,3 +38,6 @@ ;; Return codes. (define_code_iterator any_return [return simple_return]) +;; Lowpart subreg byte position code attributes for big and little endian. +(define_mode_attr lowpart_be [(QI "3") (HI "2")]) +(define_mode_attr lowpart_le [(QI "0") (HI "0")]) diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index d875a63961a..d9843228ff5 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -633,13 +633,39 @@ ;; Test low QI subreg against zero. ;; This avoids unnecessary zero extension before the test. -(define_insn "tstqi_t_zero" +(define_insn "*tstqi_t_zero" [(set (reg:SI T_REG) (eq:SI (match_operand:QI 0 "logical_operand" "z") (const_int 0)))] "TARGET_SH1" "tst #255,%0" [(set_attr "type" "mt_group")]) +;; This pattern might be risky because it also tests the upper bits and not +;; only the subreg. However, it seems that combine will get to this only +;; when testing sign/zero extended values. In this case the extended upper +;; bits do not matter. +(define_insn "*tst_t_zero" + [(set (reg:SI T_REG) + (eq:SI + (subreg:QIHI + (and:SI (match_operand:SI 0 "arith_reg_operand" "%r") + (match_operand:SI 1 "arith_reg_operand" "r")) ) + (const_int 0)))] + "TARGET_SH1 && TARGET_LITTLE_ENDIAN" + "tst %0,%1" + [(set_attr "type" "mt_group")]) + +(define_insn "*tst_t_zero" + [(set (reg:SI T_REG) + (eq:SI + (subreg:QIHI + (and:SI (match_operand:SI 0 "arith_reg_operand" "%r") + (match_operand:SI 1 "arith_reg_operand" "r")) ) + (const_int 0)))] + "TARGET_SH1 && !TARGET_LITTLE_ENDIAN" + "tst %0,%1" + [(set_attr "type" "mt_group")]) + ;; Extract LSB, negate and store in T bit. (define_insn "tstsi_t_and_not" @@ -3514,7 +3540,7 @@ label: /* If it is possible to turn the and insn into a zero extension already, redundant zero extensions will be folded, which results in better code. - Ideally the splitter of *andsi_compact would be enough, if reundant + Ideally the splitter of *andsi_compact would be enough, if redundant zero extensions were detected after the combine pass, which does not happen at the moment. */ if (TARGET_SH1) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 627d80ddb37..7acc07a7533 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-10-30 Oleg Endo + + PR target/54988 + * gcc.target/sh/pr53988.c: New. + 2012-10-30 Bin Cheng PR target/54989 diff --git a/gcc/testsuite/gcc.target/sh/pr53988.c b/gcc/testsuite/gcc.target/sh/pr53988.c new file mode 100644 index 00000000000..4bade1efb73 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr53988.c @@ -0,0 +1,74 @@ +/* Check that the tst Rm,Rn instruction is generated for QImode and HImode + values loaded from memory. If everything goes as expected we won't see + any sign/zero extensions or and ops. On SH2A we don't expect to see the + movu insn. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-times "tst\tr" 8 } } */ +/* { dg-final { scan-assembler-not "tst\t#255" } } */ +/* { dg-final { scan-assembler-not "exts|extu|and|movu" } } */ + +int +test00 (char* a, char* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test01 (unsigned char* a, unsigned char* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test02 (short* a, short* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test03 (unsigned short* a, unsigned short* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test04 (char* a, short* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test05 (short* a, char* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test06 (int* a, char* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +} + +int +test07 (int* a, short* b, int c, int d) +{ + if (*a & *b) + return c; + return d; +}