{ 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 }
};
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;
}
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? */
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;
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")
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")
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)
&& 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;
})
"&& 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;
})
;; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
;; 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)
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")