diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 460ed8416bf..75b99cd500d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2012-10-08 Oleg Endo + + PR target/54685 + * config/sh/sh.md (one_cmplsi2): Make insn_and_split. Add manual + combine matching for an insn sequence where a ge:SI pattern can be used. + 2012-10-08 Dodji Seketeli PR c++/53528 C++11 attribute support diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 989d52e3ea2..0a1cd09c1f8 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -5189,11 +5189,61 @@ label: "neg %1,%0" [(set_attr "type" "arith")]) -(define_insn "one_cmplsi2" +(define_insn_and_split "one_cmplsi2" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (not:SI (match_operand:SI 1 "arith_reg_operand" "r")))] "TARGET_SH1" "not %1,%0" + "&& can_create_pseudo_p ()" + [(set (reg:SI T_REG) (ge:SI (match_dup 1) (const_int 0))) + (set (match_dup 0) (reg:SI T_REG))] +{ +/* PR 54685 + If the result of 'unsigned int <= 0x7FFFFFFF' ends up as the following + sequence: + + (set (reg0) (not:SI (reg0) (reg1))) + (parallel [(set (reg2) (lshiftrt:SI (reg0) (const_int 31))) + (clobber (reg:SI T_REG))]) + + ... match and combine the sequence manually in the split pass after the + combine pass. Notice that combine does try the target pattern of this + split, but if the pattern is added it interferes with other patterns, in + particular with the div0s comparisons. + This could also be done with a peephole but doing it here before register + allocation can save one temporary. + When we're here, the not:SI pattern obviously has been matched already + and we only have to see whether the following insn is the left shift. */ + + rtx i = next_nonnote_insn_bb (curr_insn); + if (i == NULL_RTX || !NONJUMP_INSN_P (i)) + FAIL; + + rtx p = PATTERN (i); + if (GET_CODE (p) != PARALLEL || XVECLEN (p, 0) != 2) + FAIL; + + rtx p0 = XVECEXP (p, 0, 0); + rtx p1 = XVECEXP (p, 0, 1); + + if (/* (set (reg2) (lshiftrt:SI (reg0) (const_int 31))) */ + GET_CODE (p0) == SET + && GET_CODE (XEXP (p0, 1)) == LSHIFTRT + && REG_P (XEXP (XEXP (p0, 1), 0)) + && REGNO (XEXP (XEXP (p0, 1), 0)) == REGNO (operands[0]) + && CONST_INT_P (XEXP (XEXP (p0, 1), 1)) + && INTVAL (XEXP (XEXP (p0, 1), 1)) == 31 + + /* (clobber (reg:SI T_REG)) */ + && GET_CODE (p1) == CLOBBER && REG_P (XEXP (p1, 0)) + && REGNO (XEXP (p1, 0)) == T_REG) + { + operands[0] = XEXP (p0, 0); + set_insn_deleted (i); + } + else + FAIL; +} [(set_attr "type" "arith")]) (define_expand "one_cmpldi2" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d20a9e89304..1eb751ed9b7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-10-08 Oleg Endo + + PR target/54685 + * gcc.target/sh/pr54685.c: New. + 2012-10-08 Dodji Seketeli PR c++/53528 C++11 attribute support diff --git a/gcc/testsuite/gcc.target/sh/pr54685.c b/gcc/testsuite/gcc.target/sh/pr54685.c new file mode 100644 index 00000000000..ba08a4ade9e --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54685.c @@ -0,0 +1,58 @@ +/* Check that a comparison 'unsigned int <= 0x7FFFFFFF' results in code + utilizing the cmp/pz instruction. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-not "not" } } */ +/* { dg-final { scan-assembler-times "cmp/pz" 7 } } */ +/* { dg-final { scan-assembler-times "shll" 1 } } */ +/* { dg-final { scan-assembler-times "movt" 4 } } */ + +int +test_00 (unsigned int a) +{ + return !(a > 0x7FFFFFFF); +} + +int +test_01 (unsigned int a) +{ + return !(a > 0x7FFFFFFF) ? -5 : 10; +} + +int +test_02 (unsigned int a) +{ + /* 1x shll, 1x movt */ + return a >= 0x80000000; +} + +int +test_03 (unsigned int a) +{ + return a >= 0x80000000 ? -5 : 10; +} + +int +test_04 (unsigned int a) +{ + return a <= 0x7FFFFFFF; +} + +int +test_05 (unsigned int a) +{ + return a <= 0x7FFFFFFF ? -5 : 10; +} + +int +test_06 (unsigned int a) +{ + return a < 0x80000000; +} + +int +test_07 (unsigned int a) +{ + return a < 0x80000000 ? -5 : 10; +}