From 6fb917d907f8ae1708f3aea9805957e27992624c Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Mon, 28 Sep 2015 14:00:44 +0000 Subject: [PATCH] re PR target/54236 ([SH] Improve addc and subc insn utilization) gcc/ PR target/54236 * config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow and handle ne and eq codes. * config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn. (sh_recog_treg_set_expr): Early accept negt_reg_operand. Eearly reject CONST_INT_P. Use reverse_condition. (sh_split_treg_set_expr): Likewise. gcc/testsuite/ PR target/54236 * gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New. * gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26, test_27): New. * gcc.target/sh/pr54236-5.c: New. * gcc.target/sh/pr54236-6.c: New. From-SVN: r228202 --- gcc/ChangeLog | 10 +++ gcc/config/sh/predicates.md | 22 +++++- gcc/config/sh/sh.c | 100 +++++++++++++----------- gcc/testsuite/ChangeLog | 9 +++ gcc/testsuite/gcc.target/sh/pr54236-1.c | 26 +++++- gcc/testsuite/gcc.target/sh/pr54236-5.c | 89 +++++++++++++++++++++ gcc/testsuite/gcc.target/sh/pr54236-6.c | 75 ++++++++++++++++++ gcc/testsuite/gcc.target/sh/pr59533-1.c | 47 +++++++++-- 8 files changed, 322 insertions(+), 56 deletions(-) create mode 100644 gcc/testsuite/gcc.target/sh/pr54236-5.c create mode 100644 gcc/testsuite/gcc.target/sh/pr54236-6.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e066bd76b82..6b9af395919 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2015-09-28 Oleg Endo + + PR target/54236 + * config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow + and handle ne and eq codes. + * config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn. + (sh_recog_treg_set_expr): Early accept negt_reg_operand. Eearly reject + CONST_INT_P. Use reverse_condition. + (sh_split_treg_set_expr): Likewise. + 2015-09-28 James Greenhalgh * config/arm/types.md (type): Add rotate_imm. diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index 6f0d89e1f19..b847ae74a9d 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -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))); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 1a859724ff1..b203258102a 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -3592,13 +3592,12 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code, 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 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode) 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 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode) 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 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode) 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); - result = recog (PATTERN (i), i, 0); - PUT_CODE (op, EQ); - } - if (result < 0 && GET_CODE (op) == NE) - { - PUT_CODE (op, EQ); + 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, NE); + PUT_CODE (op, prev_code); } + PUT_MODE (op, prev_op_mode); recog_data = prev_recog_data; return result >= 0; } @@ -14350,36 +14354,42 @@ sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn) 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); - gcc_assert (insn_code >= 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); + } /* 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d5dd6f21e08..c2f693b7e33 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2015-09-28 Oleg Endo + + PR target/54236 + * gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New. + * gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26, + test_27): New. + * gcc.target/sh/pr54236-5.c: New. + * gcc.target/sh/pr54236-6.c: New. + 2015-09-28 Kyrylo Tkachov PR rtl-optimization/67456 diff --git a/gcc/testsuite/gcc.target/sh/pr54236-1.c b/gcc/testsuite/gcc.target/sh/pr54236-1.c index b5c35464a6a..7d89a5ee170 100644 --- a/gcc/testsuite/gcc.target/sh/pr54236-1.c +++ b/gcc/testsuite/gcc.target/sh/pr54236-1.c @@ -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 @@ test_08 (int a) /* 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); +} + diff --git a/gcc/testsuite/gcc.target/sh/pr54236-5.c b/gcc/testsuite/gcc.target/sh/pr54236-5.c new file mode 100644 index 00000000000..082b4f0bd3e --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54236-5.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/sh/pr54236-6.c b/gcc/testsuite/gcc.target/sh/pr54236-6.c new file mode 100644 index 00000000000..9920618f3a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54236-6.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/sh/pr59533-1.c b/gcc/testsuite/gcc.target/sh/pr59533-1.c index f45e4b83d71..c5c6c7e141b 100644 --- a/gcc/testsuite/gcc.target/sh/pr59533-1.c +++ b/gcc/testsuite/gcc.target/sh/pr59533-1.c @@ -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 @@ test_22 (int x) /* 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; +} -- 2.30.2