mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
131db6b8b2
commit
6e01d52651
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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" "")
|
||||
[(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))])]
|
||||
(match_operand:SI 2 "shift_count_operand" "")))]
|
||||
""
|
||||
{
|
||||
if (TARGET_SHMEDIA)
|
||||
|
|
@ -4476,29 +4474,137 @@ 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 (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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
if (! immediate_operand (operands[2], GET_MODE (operands[2])))
|
||||
FAIL;
|
||||
})
|
||||
|
||||
(define_insn "lshrsi3_d"
|
||||
(define_insn "lshrsi3_k"
|
||||
[(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"))))]
|
||||
(match_operand:SI 2 "p27_rshift_count_operand" "P27")))]
|
||||
"TARGET_SH1"
|
||||
"shlr%O2 %0"
|
||||
[(set_attr "type" "arith")])
|
||||
|
||||
(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")
|
||||
(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;
|
||||
}
|
||||
|
||||
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 "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);
|
||||
|
||||
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 "not_p27_rshift_count_operand")))
|
||||
(clobber (reg:SI T_REG))]
|
||||
"TARGET_SH1 && sh_lshrsi_clobbers_t_reg_p (operands[2])"
|
||||
"#"
|
||||
"&& (reload_completed || INTVAL (operands[2]) == 31
|
||||
|| (sh_dynamicalize_shift_p (operands[2]) && can_create_pseudo_p ()))"
|
||||
[(const_int 0)]
|
||||
{
|
||||
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")
|
||||
|
|
@ -4509,38 +4615,6 @@ label:
|
|||
"shlr %0"
|
||||
[(set_attr "type" "arith")])
|
||||
|
||||
(define_insn "lshrsi3_m"
|
||||
[(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")])
|
||||
|
||||
(define_insn "lshrsi3_k"
|
||||
[(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")])
|
||||
|
||||
(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" "n")))
|
||||
(clobber (reg:SI T_REG))]
|
||||
"TARGET_SH1 && ! sh_dynamicalize_shift_p (operands[2])"
|
||||
"#"
|
||||
"TARGET_SH1 && reload_completed"
|
||||
[(use (reg:SI R0_REG))]
|
||||
{
|
||||
gen_shifty_op (LSHIFTRT, operands);
|
||||
DONE;
|
||||
})
|
||||
|
||||
(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")
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
Loading…
Reference in New Issue