Index: gcc/config/sh/predicates.md =================================================================== --- gcc/config/sh/predicates.md (revision 228175) +++ gcc/config/sh/predicates.md (working copy) @@ -1158,10 +1158,18 @@ ;; A predicate describing the T bit register in any form. (define_predicate "t_reg_operand" - (match_code "reg,subreg,sign_extend,zero_extend") + (match_code "reg,subreg,sign_extend,zero_extend,ne,eq") { switch (GET_CODE (op)) { + case EQ: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const1_rtx; + + case NE: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const0_rtx; + case REG: return REGNO (op) == T_REG; @@ -1183,13 +1191,21 @@ ;; A predicate describing a negated T bit register. (define_predicate "negt_reg_operand" - (match_code "subreg,xor") + (match_code "subreg,xor,ne,eq") { switch (GET_CODE (op)) { + case EQ: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const0_rtx; + + case NE: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const1_rtx; + case XOR: return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) - && satisfies_constraint_M (XEXP (op, 1)); + && XEXP (op, 1) == const1_rtx; case SUBREG: return negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))); Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 228176) +++ gcc/config/sh/sh.c (working copy) @@ -3592,13 +3592,12 @@ case EQ: /* An and with a constant compared against zero is - most likely going to be a TST #imm, R0 instruction. - Notice that this does not catch the zero_extract variants from - the md file. */ + most likely going to be a TST #imm, R0 instruction. */ if (XEXP (x, 1) == const0_rtx - && (GET_CODE (XEXP (x, 0)) == AND - || (SUBREG_P (XEXP (x, 0)) - && GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND))) + && ((GET_CODE (XEXP (x, 0)) == AND + || (SUBREG_P (XEXP (x, 0)) + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND)) + || GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT)) { *total = 1; return true; @@ -14200,7 +14199,8 @@ return false; /* Early accept known possible operands before doing recog. */ - if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode)) + if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode) + || negt_reg_operand (op, mode)) return true; /* Early reject impossible operands before doing recog. @@ -14209,8 +14209,8 @@ such as lower-subreg will bail out. Some insns such as SH4A movua are done with UNSPEC, so must reject those, too, or else it would result in an invalid reg -> treg move. */ - if (register_operand (op, mode) || memory_operand (op, mode) - || sh_unspec_insn_p (op)) + if (CONST_INT_P (op) || register_operand (op, mode) + || memory_operand (op, mode) || sh_unspec_insn_p (op)) return false; if (!can_create_pseudo_p ()) @@ -14230,26 +14230,30 @@ SET_PREV_INSN (i) = NULL; SET_NEXT_INSN (i) = NULL; + /* If the comparison op doesn't have a result mode, set it to SImode. */ + machine_mode prev_op_mode = GET_MODE (op); + if (COMPARISON_P (op) && prev_op_mode == VOIDmode) + PUT_MODE (op, SImode); + int result = recog (PATTERN (i), i, 0); - /* It seems there is no insn like that. Create a simple negated - version and try again. If we hit a negated form, we'll allow that - and append a nott sequence when splitting out the insns. Insns that - do the split can then remove the trailing nott if they know how to - deal with it. */ - if (result < 0 && GET_CODE (op) == EQ) + /* It seems there is no insn like that. Create a negated version and + try again. If we hit a negated form, we'll allow that and append a + nott sequence when splitting out the insns. Insns that do the split + can then remove the trailing nott if they know how to deal with it. */ + if (result < 0 && COMPARISON_P (op)) { - PUT_CODE (op, NE); + machine_mode cmp_mode = GET_MODE (XEXP (op, 0)); + if (cmp_mode == VOIDmode) + cmp_mode = GET_MODE (XEXP (op, 1)); + + rtx_code prev_code = GET_CODE (op); + PUT_CODE (op, reverse_condition (GET_CODE (op))); result = recog (PATTERN (i), i, 0); - PUT_CODE (op, EQ); + PUT_CODE (op, prev_code); } - if (result < 0 && GET_CODE (op) == NE) - { - PUT_CODE (op, EQ); - result = recog (PATTERN (i), i, 0); - PUT_CODE (op, NE); - } + PUT_MODE (op, prev_op_mode); recog_data = prev_recog_data; return result >= 0; } @@ -14350,37 +14354,43 @@ fprintf (dump_file, "\n"); } + /* If the insn is not found, we will try a negated form and append + a nott. */ + bool append_nott = false; + /* We are going to invoke recog/split_insns in a re-entrant way and thus have to capture its current state and restore it afterwards. */ recog_data_d prev_recog_data = recog_data; - int insn_code = recog (PATTERN (i), i, 0); - - /* If the insn was not found, see if we matched the negated form before - and append a nott. */ - bool append_nott = false; - - if (insn_code < 0 && GET_CODE (x) == EQ) + if (negt_reg_operand (x, GET_MODE (x))) { - PUT_CODE (x, NE); - insn_code = recog (PATTERN (i), i, 0); - if (insn_code >= 0) - append_nott = true; - else - PUT_CODE (x, EQ); + /* This is a normal movt followed by a nott. It will be converted + into a movrt after initial expansion. */ + XEXP (PATTERN (i), 1) = get_t_reg_rtx (); + append_nott = true; } - if (insn_code < 0 && GET_CODE (x) == NE) + else { - PUT_CODE (x, EQ); - insn_code = recog (PATTERN (i), i, 0); - if (insn_code >= 0) - append_nott = true; - else - PUT_CODE (x, NE); + /* If the comparison op doesn't have a mode set, set it to SImode. */ + if (COMPARISON_P (x) && GET_MODE (x) == VOIDmode) + PUT_MODE (x, SImode); + + int insn_code = recog (PATTERN (i), i, 0); + + if (insn_code < 0 && COMPARISON_P (x)) + { + machine_mode cmp_mode = GET_MODE (XEXP (x, 0)); + if (cmp_mode == VOIDmode) + cmp_mode = GET_MODE (XEXP (x, 1)); + + PUT_CODE (x, reverse_condition (GET_CODE (x))); + insn_code = recog (PATTERN (i), i, 0); + append_nott = true; + } + + gcc_assert (insn_code >= 0); } - gcc_assert (insn_code >= 0); - /* Try to recursively split the insn. Some insns might refuse to split any further while we are in the treg_set_expr splitting phase. They will be emitted as part of the outer insn and then split again. */ Index: gcc/testsuite/gcc.target/sh/pr54236-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-1.c (revision 228175) +++ gcc/testsuite/gcc.target/sh/pr54236-1.c (working copy) @@ -4,8 +4,8 @@ /* { dg-do compile } */ /* { dg-options "-O1" } */ /* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ -/* { dg-final { scan-assembler-times "addc" 4 } } */ -/* { dg-final { scan-assembler-times "subc" 3 } } */ +/* { dg-final { scan-assembler-times "addc" 6 } } */ +/* { dg-final { scan-assembler-times "subc" 4 } } */ /* { dg-final { scan-assembler-times "sett" 5 } } */ /* { dg-final { scan-assembler-times "negc" 2 { target { ! sh2a } } } } */ @@ -86,3 +86,25 @@ /* 1x addc, 1x sett */ return (a << 1) + 1; } + +unsigned int +test_09 (unsigned int x) +{ + /* 1x tst, 1x addc */ + return x - (x != 0); +} + +unsigned int +test_10 (unsigned int x) +{ + /* 1x tst, 1x subc */ + return x + (x == 0); +} + +unsigned int +test_11 (unsigned int x) +{ + /* 1x tst, 1x addc */ + return x + (x != 0); +} + Index: gcc/testsuite/gcc.target/sh/pr54236-5.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-5.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54236-5.c (working copy) @@ -0,0 +1,89 @@ +/* Check that addc and subc instructions are generated as expected in + combination with ifcvt. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-times "subc" 4 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "not\t" 0 { target { ! sh2a } } } } */ + +/* { dg-final { scan-assembler-times "subc" 4 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 4 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "nott" 0 { target { sh2a } } } } */ + +/* { dg-final { scan-assembler-times "tst\t" 4 } } */ +/* { dg-final { scan-assembler-times "cmp/eq" 1 } } */ +/* { dg-final { scan-assembler-times "cmp/pl" 2 } } */ +/* { dg-final { scan-assembler-times "cmp/gt" 1 } } */ + +/* { dg-final { scan-assembler-not "movt" } } */ +/* { dg-final { scan-assembler-not "negc" } } */ +/* { dg-final { scan-assembler-not "movrt" } } */ + +int +test_00 (int x, int y) +{ + /* 1x tst, 1x subc */ + if (y) + ++x; + return x; +} + +int +test_01 (int x, int y) +{ + /* 1x tst, 1x addc */ + if (y) + --x; + return x; +} + +int +test_02 (int x, int y) +{ + /* 1x tst, 1x addc */ + if (!y) + ++x; + return x; +} + +int +test_03 (int x, int y) +{ + /* 1x tst, 1x subc */ + if (!y) + --x; + return x; +} + +int +test_04 (int x, int y) +{ + /* 1x cmp/eq, 1x addc */ + if (y == x) + ++x; + return x; +} + +int +test_05 (int x, int y) +{ + /* 1x cmp/gt, 1x subc */ + if (y < 4) + ++x; + return x; +} + +int +test_06 (int x) +{ + /* 1x cmp/pl, 1x addc */ + return x > 0 ? x + 1 : x; +} + +int +test_07 (int x) +{ + /* 1x cmp/pl, 1x subc */ + return x > 0 ? x - 1 : x; +} Index: gcc/testsuite/gcc.target/sh/pr54236-6.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-6.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54236-6.c (working copy) @@ -0,0 +1,75 @@ +/* In this snippet, there was a missed subc case: + tst #1,r0 + movt r0 + neg r0,r0 + + which should be: + tst #1,r0 + subc r0,r0 +*/ + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-times {tst #1,r0} 1 } } */ +/* { dg-final { scan-assembler-times {subc r} 1 } } */ + +/* { dg-final { scan-assembler-not "movt|not|neg\movrt" } } */ + + +struct inode +{ + unsigned int i_gid; +}; + +struct iattr +{ + unsigned int ia_valid; + unsigned int ia_gid; +}; + +struct task_struct +{ + unsigned long flags; + unsigned int cap_effective; +}; + +extern int in_group_p (unsigned int); + +static inline struct task_struct* +get_current (void) +{ + struct task_struct *current; + return current; +} + +static inline int +capable (int cap) +{ + if (((get_current()->cap_effective) & (1 << (cap)))) + { + get_current()->flags |= 0x00000100; + return 1; + } + return 0; +} + +int +inode_change_ok (struct inode *inode, struct iattr *attr) +{ + int retval = -1; + unsigned int ia_valid = attr->ia_valid; + + if (ia_valid & 512) + goto fine; + + if ((ia_valid & 4) + && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) + && !capable(0)) + goto error; + +fine: + retval = 0; +error: + return retval; +} Index: gcc/testsuite/gcc.target/sh/pr59533-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr59533-1.c (revision 228175) +++ gcc/testsuite/gcc.target/sh/pr59533-1.c (working copy) @@ -9,13 +9,13 @@ /* { dg-final { scan-assembler-times "and" 3 } } */ /* { dg-final { scan-assembler-times "extu.b" 5 } } */ -/* { dg-final { scan-assembler-times "cmp/pz" 22 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "addc" 3 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "subc" 12 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "cmp/pz" 27 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "subc" 16 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "cmp/pz" 20 { target { sh2a } } } } */ -/* { dg-final { scan-assembler-times "addc" 5 { target { sh2a } } } } */ -/* { dg-final { scan-assembler-times "subc" 10 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "cmp/pz" 25 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 6 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "subc" 14 { target { sh2a } } } } */ /* { dg-final { scan-assembler-times "bld" 2 { target { sh2a } } } } */ int @@ -183,3 +183,38 @@ /* 1x cmp/pz, 1x movt */ return (x >> 31) + 1; } + +int +test_23 (int x) +{ + /* 1x cmp/pz, 1x subc */ + return x < 0 ? x + 1 : x; +} + +unsigned int +test_24 (unsigned int x) +{ + /* 1x cmp/pz, 1x subc */ + return x & 0x80000000 ? x + 1 : x; +} + +unsigned int +test_25 (unsigned int x) +{ + /* 1x cmp/pz, 1x subc */ + return x >> 31 ? x + 1 : x; +} + +int +test_26 (int x) +{ + /* 1x cmp/pz, 1x subc */ + return x >> 31 ? x + 1 : x; +} + +int +test_27 (int x, int y, int z) +{ + /* 1x cmp/pz, 1x addc */ + return 1 - ((x >> 4) < 0) + z; +}