Hello, This fixes the issues of PR 54988. Tested on rev 192482 with make -k check RUNTESTFLAGS="--target_board=sh-sim \{-m2/-ml,-m2/-mb,-m2a/-mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}"
and no new failures. Cheers, Oleg gcc/ChangeLog: PR target/54988 * config/sh/sh.md (tstqi_t_zero): Rename to *tstqi_t_zero. (*tst<mode>_t_zero): New insns. * config/sh/iterators.md (lowpart_be, lowpart_le): New mode attributes. testsuite/ChangeLog: PR target/54988 gcc.target/sh/pr53988.c: New.
Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 192482) +++ gcc/config/sh/sh.md (working copy) @@ -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<mode>_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")) <lowpart_le>) + (const_int 0)))] + "TARGET_SH1 && TARGET_LITTLE_ENDIAN" + "tst %0,%1" + [(set_attr "type" "mt_group")]) + +(define_insn "*tst<mode>_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")) <lowpart_be>) + (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 @@ /* 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) Index: gcc/config/sh/iterators.md =================================================================== --- gcc/config/sh/iterators.md (revision 192482) +++ gcc/config/sh/iterators.md (working copy) @@ -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")]) Index: gcc/testsuite/gcc.target/sh/pr53988.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr53988.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr53988.c (revision 0) @@ -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; +}