From 6e01d5265181a73cb7b8f678ea5d1baff1f91bdc Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Wed, 22 Aug 2012 22:52:17 +0000 Subject: re PR target/54089 ([SH] Refactor shift patterns) PR target/54089 * config/sh/predicates (p27_rshift_count_operand, not_p27_rshift_count_operand): New predicates. * config/sh/sh.c (sh_ashlsi_clobbers_t_reg_p, sh_lshrsi_clobbers_t_reg_p, sh_dynamicalize_shift_p): Handle special case when shift amount is 31. (gen_ashift): Emit gen_shlr instead of gen_lshrsi3_m. * config/sh/sh.md (ashlsi3_d): Set type to 'dyn_shift' instead of 'arith'. (ashlsi_c): Rename to shll. Adapt calls to gen_ashlsi_c throughout the file. (lshrsi3): Remove clobber from expander. Use shift_count_operand instead of nonmemory_operand predicate for second operand. Add handling of case lshrsi3_n_clobbers_t. (lshrsi3_k): Use p27_rshift_count_operand for second operand. (lshrsi3_d): Make insn_and_split. Split dynamic shift to constant shift sequences if beneficial. (lshrsi3_n): Make insn_and_split. Split constant shift sequence to dynamic shift if beneficial. (lshrsi3_n_clobbers_t): New insn_and_split. (lshrsi3_m): Delete. PR target/54089 * gcc.target/sh/pr54089-2.c: New. From-SVN: r190603 --- gcc/ChangeLog | 24 +++++ gcc/config/sh/predicates.md | 15 +++ gcc/config/sh/sh.c | 60 ++++++++--- gcc/config/sh/sh.md | 172 +++++++++++++++++++++++--------- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.target/sh/pr54089-2.c | 22 ++++ 6 files changed, 233 insertions(+), 65 deletions(-) create mode 100644 gcc/testsuite/gcc.target/sh/pr54089-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 527f822a..3bf9a38 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2012-08-22 Oleg Endo + + PR target/54089 + * config/sh/predicates (p27_rshift_count_operand, + not_p27_rshift_count_operand): New predicates. + * config/sh/sh.c (sh_ashlsi_clobbers_t_reg_p, + sh_lshrsi_clobbers_t_reg_p, sh_dynamicalize_shift_p): Handle special + case when shift amount is 31. + (gen_ashift): Emit gen_shlr instead of gen_lshrsi3_m. + * config/sh/sh.md (ashlsi3_d): Set type to 'dyn_shift' instead + of 'arith'. + (ashlsi_c): Rename to shll. Adapt calls to gen_ashlsi_c throughout + the file. + (lshrsi3): Remove clobber from expander. Use shift_count_operand + instead of nonmemory_operand predicate for second operand. Add + handling of case lshrsi3_n_clobbers_t. + (lshrsi3_k): Use p27_rshift_count_operand for second operand. + (lshrsi3_d): Make insn_and_split. Split dynamic shift to constant + shift sequences if beneficial. + (lshrsi3_n): Make insn_and_split. Split constant shift sequence to + dynamic shift if beneficial. + (lshrsi3_n_clobbers_t): New insn_and_split. + (lshrsi3_m): Delete. + 2012-08-22 Steven Bosscher * tracer.c (mark_bb_seen): Use SBITMAP_SIZE. diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index 12f69db..92a7b68 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -825,6 +825,8 @@ return arith_reg_operand (op, mode); }) +;; Predicates for matching operands that are constant shift +;; amounts 1, 2, 8, 16. (define_predicate "p27_shift_count_operand" (and (match_code "const_int") (match_test "satisfies_constraint_P27 (op)"))) @@ -833,6 +835,19 @@ (and (match_code "const_int") (match_test "! satisfies_constraint_P27 (op)"))) +;; For right shifts the constant 1 is a special case because the shlr insn +;; clobbers the T_REG and is handled by the T_REG clobbering version of the +;; insn, which is also used for non-P27 shift sequences. +(define_predicate "p27_rshift_count_operand" + (and (match_code "const_int") + (match_test "satisfies_constraint_P27 (op)") + (match_test "! satisfies_constraint_M (op)"))) + +(define_predicate "not_p27_rshift_count_operand" + (and (match_code "const_int") + (ior (match_test "! satisfies_constraint_P27 (op)") + (match_test "satisfies_constraint_M (op)")))) + ;; TODO: Add a comment here. (define_predicate "shift_operator" diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 0760cbc..3851ec6 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -2840,6 +2840,11 @@ static const struct ashl_lshr_sequence ashl_lshr_seq[32] = { 4, { 16, 8, 2, 2 }, 0 }, { 4, { 16, -1, -2, 16 }, ASHL_CLOBBERS_T }, { 3, { 16, -2, 16 }, 0 }, + + /* For a right shift by 31 a 2 insn shll-movt sequence can be used. + For a left shift by 31 a 2 insn and-rotl sequences can be used. + However, the shift-and combiner code needs this entry here to be in + terms of real shift insns. */ { 3, { 16, -1, 16 }, ASHL_CLOBBERS_T } }; @@ -2888,7 +2893,14 @@ bool sh_ashlsi_clobbers_t_reg_p (rtx shift_amount) { gcc_assert (CONST_INT_P (shift_amount)); - return (ashl_lshr_seq[INTVAL (shift_amount) & 31].clobbers_t + + const int shift_amount_i = INTVAL (shift_amount) & 31; + + /* Special case for shift count of 31: use and-rotl sequence. */ + if (shift_amount_i == 31) + return true; + + return (ashl_lshr_seq[shift_amount_i].clobbers_t & ASHL_CLOBBERS_T) != 0; } @@ -2896,10 +2908,39 @@ bool sh_lshrsi_clobbers_t_reg_p (rtx shift_amount) { gcc_assert (CONST_INT_P (shift_amount)); - return (ashl_lshr_seq[INTVAL (shift_amount) & 31].clobbers_t + + const int shift_amount_i = INTVAL (shift_amount) & 31; + + /* Special case for shift count of 31: use shll-movt sequence. */ + if (shift_amount_i == 31) + return true; + + return (ashl_lshr_seq[shift_amount_i].clobbers_t & LSHR_CLOBBERS_T) != 0; } +/* Return true if it is potentially beneficial to use a dynamic shift + instruction (shad / shar) instead of a combination of 1/2/8/16 + shift instructions for the specified shift count. + If dynamic shifts are not available, always return false. */ +bool +sh_dynamicalize_shift_p (rtx count) +{ + gcc_assert (CONST_INT_P (count)); + + const int shift_amount_i = INTVAL (count) & 31; + int insn_count; + + /* For left and right shifts, there are shorter 2 insn sequences for + shift amounts of 31. */ + if (shift_amount_i == 31) + insn_count = 2; + else + insn_count = ashl_lshr_seq[shift_amount_i].insn_count; + + return TARGET_DYNSHIFT && (insn_count > 1 + SH_DYNAMIC_SHIFT_COST); +} + /* Assuming we have a value that has been sign-extended by at least one bit, can we use the ext_shift_amounts with the last shift turned to an arithmetic shift to shift it by N without data loss, and quicker than by other means? */ @@ -3385,7 +3426,7 @@ gen_ashift (int type, int n, rtx reg) break; case LSHIFTRT: if (n == 1) - emit_insn (gen_lshrsi3_m (reg, reg, n_rtx)); + emit_insn (gen_shlr (reg, reg)); else emit_insn (gen_lshrsi3_k (reg, reg, n_rtx)); break; @@ -3596,19 +3637,6 @@ expand_ashiftrt (rtx *operands) return true; } -/* Return true if it is potentially beneficial to use a dynamic shift - instruction (shad / shar) instead of a combination of 1/2/8/16 - shift instructions for the specified shift count. - If dynamic shifts are not available, always return false. */ -bool -sh_dynamicalize_shift_p (rtx count) -{ - int insn_count; - gcc_assert (CONST_INT_P (count)); - insn_count = ashl_lshr_seq[INTVAL (count) & 31].insn_count; - return TARGET_DYNSHIFT && (insn_count > 1 + SH_DYNAMIC_SHIFT_COST); -} - /* Try to find a good way to implement the combiner pattern [(set (match_operand:SI 0 "register_operand" "r") (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 4402df8..ede916e 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -4058,7 +4058,7 @@ label: FAIL; } - [(set_attr "type" "arith")]) + [(set_attr "type" "dyn_shift")]) (define_insn_and_split "ashlsi3_n" [(set (match_operand:SI 0 "arith_reg_dest" "=r") @@ -4116,7 +4116,7 @@ label: DONE; }) -(define_insn "ashlsi_c" +(define_insn "shll" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0") (const_int 1))) (set (reg:SI T_REG) @@ -4142,7 +4142,7 @@ label: && peep2_reg_dead_p (2, operands[1])" [(const_int 0)] { - emit_insn (gen_ashlsi_c (operands[1], operands[1])); + emit_insn (gen_shll (operands[1], operands[1])); DONE; }) @@ -4349,7 +4349,7 @@ label: "&& 1" [(const_int 0)] { - emit_insn (gen_ashlsi_c (operands[0], operands[1])); + emit_insn (gen_shll (operands[0], operands[1])); emit_insn (gen_mov_neg_si_t (operands[0], get_t_reg_rtx ())); DONE; }) @@ -4463,12 +4463,10 @@ label: ;; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ;; SImode logical shift right -;; Only the single bit shift clobbers the T bit. (define_expand "lshrsi3" - [(parallel [(set (match_operand:SI 0 "arith_reg_dest" "") - (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "") - (match_operand:SI 2 "nonmemory_operand" ""))) - (clobber (reg:SI T_REG))])] + [(set (match_operand:SI 0 "arith_reg_dest" "") + (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "shift_count_operand" "")))] "" { if (TARGET_SHMEDIA) @@ -4476,71 +4474,147 @@ label: emit_insn (gen_lshrsi3_media (operands[0], operands[1], operands[2])); DONE; } - if (CONST_INT_P (operands[2]) - && sh_dynamicalize_shift_p (operands[2])) - operands[2] = force_reg (SImode, operands[2]); + + /* If a dynamic shift is supposed to be used, expand the lshrsi3_d insn + here, otherwise the pattern will never match due to the shift amount reg + negation. */ if (TARGET_DYNSHIFT - && arith_reg_operand (operands[2], GET_MODE (operands[2]))) + && CONST_INT_P (operands[2]) && sh_dynamicalize_shift_p (operands[2])) { - rtx count = copy_to_mode_reg (SImode, operands[2]); - emit_insn (gen_negsi2 (count, count)); - emit_insn (gen_lshrsi3_d (operands[0], operands[1], count)); + rtx neg_count = force_reg (SImode, + gen_int_mode (- INTVAL (operands[2]), SImode)); + emit_insn (gen_lshrsi3_d (operands[0], operands[1], neg_count)); DONE; } - if (! immediate_operand (operands[2], GET_MODE (operands[2]))) - FAIL; -}) -(define_insn "lshrsi3_d" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))] - "TARGET_DYNSHIFT" - "shld %2,%0" - [(set_attr "type" "dyn_shift")]) + if (TARGET_DYNSHIFT && ! CONST_INT_P (operands[2])) + { + rtx neg_count = gen_reg_rtx (SImode); + emit_insn (gen_negsi2 (neg_count, operands[2])); + emit_insn (gen_lshrsi3_d (operands[0], operands[1], neg_count)); + DONE; + } -(define_insn "shlr" + /* If the lshrsi3_* insn is going to clobber the T_REG it must be + expanded here. */ + if (CONST_INT_P (operands[2]) + && sh_lshrsi_clobbers_t_reg_p (operands[2]) + && ! sh_dynamicalize_shift_p (operands[2])) + { + emit_insn (gen_lshrsi3_n_clobbers_t (operands[0], operands[1], + operands[2])); + DONE; + } +}) + +(define_insn "lshrsi3_k" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (const_int 1))) - (set (reg:SI T_REG) - (and:SI (match_dup 1) (const_int 1)))] + (match_operand:SI 2 "p27_rshift_count_operand" "P27")))] "TARGET_SH1" - "shlr %0" + "shlr%O2 %0" [(set_attr "type" "arith")]) -(define_insn "lshrsi3_m" +(define_insn_and_split "lshrsi3_d" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (match_operand:SI 2 "const_int_operand" "M"))) - (clobber (reg:SI T_REG))] - "TARGET_SH1 && satisfies_constraint_M (operands[2])" - "shlr %0" - [(set_attr "type" "arith")]) + (neg:SI (match_operand:SI 2 "shift_count_operand" "r"))))] + "TARGET_DYNSHIFT" + "shld %2,%0" + "&& CONST_INT_P (operands[2]) && ! sh_dynamicalize_shift_p (operands[2]) + && ! sh_lshrsi_clobbers_t_reg_p (operands[2])" + [(const_int 0)] +{ + if (satisfies_constraint_P27 (operands[2])) + { + /* This will not be done for a shift amount of 1, because it would + clobber the T_REG. */ + emit_insn (gen_lshrsi3_k (operands[0], operands[1], operands[2])); + DONE; + } + else if (! satisfies_constraint_P27 (operands[2])) + { + /* This must happen before reload, otherwise the constant will be moved + into a register due to the "r" constraint, after which this split + cannot be done anymore. + Unfortunately the move insn will not always be eliminated. + Also, here we must not create a shift sequence that clobbers the + T_REG. */ + emit_move_insn (operands[0], operands[1]); + gen_shifty_op (LSHIFTRT, operands); + DONE; + } -(define_insn "lshrsi3_k" + FAIL; +} + [(set_attr "type" "dyn_shift")]) + +(define_insn_and_split "lshrsi3_n" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (match_operand:SI 2 "const_int_operand" "P27")))] - "TARGET_SH1 && satisfies_constraint_P27 (operands[2]) - && ! satisfies_constraint_M (operands[2])" - "shlr%O2 %0" - [(set_attr "type" "arith")]) + (match_operand:SI 2 "not_p27_rshift_count_operand")))] + "TARGET_SH1 && ! sh_lshrsi_clobbers_t_reg_p (operands[2])" + "#" + "&& (reload_completed + || (sh_dynamicalize_shift_p (operands[2]) && can_create_pseudo_p ()))" + [(const_int 0)] +{ + if (sh_dynamicalize_shift_p (operands[2]) && can_create_pseudo_p ()) + { + /* If this pattern was picked and dynamic shifts are supported, switch + to dynamic shift pattern before reload. */ + operands[2] = force_reg (SImode, + gen_int_mode (- INTVAL (operands[2]), SImode)); + emit_insn (gen_lshrsi3_d (operands[0], operands[1], operands[2])); + } + else + gen_shifty_op (LSHIFTRT, operands); -(define_insn_and_split "lshrsi3_n" + DONE; +}) + +;; The lshrsi3_n_clobbers_t pattern also works as a simplified version of +;; the shlr pattern. +(define_insn_and_split "lshrsi3_n_clobbers_t" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (match_operand:SI 2 "const_int_operand" "n"))) + (match_operand:SI 2 "not_p27_rshift_count_operand"))) (clobber (reg:SI T_REG))] - "TARGET_SH1 && ! sh_dynamicalize_shift_p (operands[2])" + "TARGET_SH1 && sh_lshrsi_clobbers_t_reg_p (operands[2])" "#" - "TARGET_SH1 && reload_completed" - [(use (reg:SI R0_REG))] + "&& (reload_completed || INTVAL (operands[2]) == 31 + || (sh_dynamicalize_shift_p (operands[2]) && can_create_pseudo_p ()))" + [(const_int 0)] { - gen_shifty_op (LSHIFTRT, operands); + if (INTVAL (operands[2]) == 31) + { + emit_insn (gen_shll (operands[0], operands[1])); + emit_insn (gen_movt (operands[0], get_t_reg_rtx ())); + } + else if (sh_dynamicalize_shift_p (operands[2]) && can_create_pseudo_p ()) + { + /* If this pattern was picked and dynamic shifts are supported, switch + to dynamic shift pattern before reload. */ + operands[2] = force_reg (SImode, + gen_int_mode (- INTVAL (operands[2]), SImode)); + emit_insn (gen_lshrsi3_d (operands[0], operands[1], operands[2])); + } + else + gen_shifty_op (LSHIFTRT, operands); + DONE; }) +(define_insn "shlr" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") + (const_int 1))) + (set (reg:SI T_REG) + (and:SI (match_dup 1) (const_int 1)))] + "TARGET_SH1" + "shlr %0" + [(set_attr "type" "arith")]) + (define_insn "lshrsi3_media" [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") (lshiftrt:SI (match_operand:SI 1 "extend_reg_operand" "r,r") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ed45fc0..3c4db30 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-08-22 Oleg Endo + + PR target/54089 + * gcc.target/sh/pr54089-2.c: New. + 2012-08-22 H.J. Lu * gcc.target/i386/long-double-64-1.c: New file. diff --git a/gcc/testsuite/gcc.target/sh/pr54089-2.c b/gcc/testsuite/gcc.target/sh/pr54089-2.c new file mode 100644 index 0000000..61b703d --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54089-2.c @@ -0,0 +1,22 @@ +/* Check that for dynamic logical right shifts with a constant the negated + constant is loaded directly, instead of loading the postitive constant + and negating it separately. This was a case that happened at optimization + level -O2 and looked like: + cmp/eq r6,r5 + mov #30,r1 + neg r1,r1 + shld r1,r4 + mov r4,r0 + rts + rotcr r0 */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O2" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "*"} { "-m3* -m2a* -m4*" } } */ +/* { dg-final { scan-assembler-not "neg" } } */ + +unsigned int +test (unsigned int a, int b, int c) +{ + unsigned char r = b == c; + return ((a >> 31) | (r << 31)); +} -- cgit v1.1