aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Endo <olegendo@gcc.gnu.org>2012-08-22 22:52:17 +0000
committerOleg Endo <olegendo@gcc.gnu.org>2012-08-22 22:52:17 +0000
commit6e01d5265181a73cb7b8f678ea5d1baff1f91bdc (patch)
tree036a6368ca64516b6be1aed09908a8c533e43618
parent131db6b8b25c6cb2349045f8c8196be6e376f454 (diff)
downloadgcc-6e01d5265181a73cb7b8f678ea5d1baff1f91bdc.zip
gcc-6e01d5265181a73cb7b8f678ea5d1baff1f91bdc.tar.gz
gcc-6e01d5265181a73cb7b8f678ea5d1baff1f91bdc.tar.bz2
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
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/config/sh/predicates.md15
-rw-r--r--gcc/config/sh/sh.c60
-rw-r--r--gcc/config/sh/sh.md172
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/sh/pr54089-2.c22
6 files changed, 233 insertions, 65 deletions
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 <olegendo@gcc.gnu.org>
+
+ 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 <steven@gcc.gnu.org>
* 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 <olegendo@gcc.gnu.org>
+
+ PR target/54089
+ * gcc.target/sh/pr54089-2.c: New.
+
2012-08-22 H.J. Lu <hongjiu.lu@intel.com>
* 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));
+}