aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Endo <olegendo@gcc.gnu.org>2012-07-25 23:03:06 +0000
committerOleg Endo <olegendo@gcc.gnu.org>2012-07-25 23:03:06 +0000
commitd8a48c211e9056e8aa8d62d4bb2a2cbe32c74815 (patch)
tree95d7dea89a15eeed4848095b5087afefcd61b69b
parent1acc33406fdf0d0eec647e2e5c6d02ce67a6e50d (diff)
downloadgcc-d8a48c211e9056e8aa8d62d4bb2a2cbe32c74815.zip
gcc-d8a48c211e9056e8aa8d62d4bb2a2cbe32c74815.tar.gz
gcc-d8a48c211e9056e8aa8d62d4bb2a2cbe32c74815.tar.bz2
re PR target/54089 ([SH] Refactor shift patterns)
PR target/54089 * config/sh/predicates.md (shift_count_operand): Handle not-SHMEDIA case. (p27_shift_count_operand, not_p27_shift_count_operand): New predicates. * config/sh/sh.md (ashlsi3): Remove parallel and T_REG clobber from expander. Do not emit shift insn for not-SHMEDIA case. (ashlsi3_std): Replace with ... (ashlsi3_k, ashlsi3_d): ... these new insns. * config/sh/sh.c (gen_ashift): Make static. Add sanity checks. Emit ashlsi3_k insn instead of ashlsi3_std in ASHIFT case. (gen_ashift_hi): Make static. * config/sh/sh-protos.h (gen_ashift, gen_ashift_hi): Remove forward declaration. From-SVN: r189872
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/config/sh/predicates.md15
-rw-r--r--gcc/config/sh/sh-protos.h2
-rw-r--r--gcc/config/sh/sh.c20
-rw-r--r--gcc/config/sh/sh.md103
5 files changed, 104 insertions, 52 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5c6403e..2ef72fe 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2012-07-25 Oleg Endo <olegendo@gcc.gnu.org>
+
+ PR target/54089
+ * config/sh/predicates.md (shift_count_operand): Handle not-SHMEDIA
+ case.
+ (p27_shift_count_operand, not_p27_shift_count_operand): New predicates.
+ * config/sh/sh.md (ashlsi3): Remove parallel and T_REG clobber
+ from expander. Do not emit shift insn for not-SHMEDIA case.
+ (ashlsi3_std): Replace with ...
+ (ashlsi3_k, ashlsi3_d): ... these new insns.
+ * config/sh/sh.c (gen_ashift): Make static. Add sanity checks.
+ Emit ashlsi3_k insn instead of ashlsi3_std in ASHIFT case.
+ (gen_ashift_hi): Make static.
+ * config/sh/sh-protos.h (gen_ashift, gen_ashift_hi): Remove forward
+ declaration.
+
2012-07-25 Bharathi Seshadri <bseshadr@cisco.com>
Jim Wilson <jimwilso@cisco.com>
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index 3b93721..e87f6ba 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -755,6 +755,13 @@
(define_predicate "shift_count_operand"
(match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,zero_extend,sign_extend")
{
+ /* Allow T_REG as shift count for dynamic shifts, although it is not
+ really possible. It will then be copied to a general purpose reg. */
+ if (! TARGET_SHMEDIA)
+ return const_int_operand (op, mode)
+ || (TARGET_DYNSHIFT && (arith_reg_operand (op, mode)
+ || t_reg_operand (op, mode)));
+
return (CONSTANT_P (op)
? (CONST_INT_P (op)
? (unsigned) INTVAL (op) < GET_MODE_BITSIZE (mode)
@@ -785,6 +792,14 @@
return arith_reg_operand (op, mode);
})
+(define_predicate "p27_shift_count_operand"
+ (and (match_code "const_int")
+ (match_test "satisfies_constraint_P27 (op)")))
+
+(define_predicate "not_p27_shift_count_operand"
+ (and (match_code "const_int")
+ (match_test "! satisfies_constraint_P27 (op)")))
+
;; TODO: Add a comment here.
(define_predicate "shift_operator"
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index 63fa599..ff29399 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -74,8 +74,6 @@ extern rtx sh_emit_cheap_store_flag (enum machine_mode, enum rtx_code, rtx, rtx)
extern void sh_emit_compare_and_branch (rtx *, enum machine_mode);
extern void sh_emit_compare_and_set (rtx *, enum machine_mode);
extern int shift_insns_rtx (rtx);
-extern void gen_ashift (int, int, rtx);
-extern void gen_ashift_hi (int, int, rtx);
extern void gen_shifty_op (int, rtx *);
extern void gen_shifty_hi_op (int, rtx *);
extern bool expand_ashiftrt (rtx *);
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 604e500..b0ef972 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -3277,9 +3277,11 @@ sh_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
/* Code to expand a shift. */
-void
+static void
gen_ashift (int type, int n, rtx reg)
{
+ rtx n_rtx;
+
/* Negative values here come from the shift_amounts array. */
if (n < 0)
{
@@ -3290,26 +3292,30 @@ gen_ashift (int type, int n, rtx reg)
n = -n;
}
+ n_rtx = GEN_INT (n);
+ gcc_assert (satisfies_constraint_P27 (n_rtx));
+
switch (type)
{
case ASHIFTRT:
- emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n)));
+ emit_insn (gen_ashrsi3_k (reg, reg, n_rtx));
break;
case LSHIFTRT:
if (n == 1)
- emit_insn (gen_lshrsi3_m (reg, reg, GEN_INT (n)));
+ emit_insn (gen_lshrsi3_m (reg, reg, n_rtx));
else
- emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n)));
+ emit_insn (gen_lshrsi3_k (reg, reg, n_rtx));
break;
case ASHIFT:
- emit_insn (gen_ashlsi3_std (reg, reg, GEN_INT (n)));
+ emit_insn (gen_ashlsi3_k (reg, reg, n_rtx));
break;
+ default:
+ gcc_unreachable ();
}
}
/* Same for HImode */
-
-void
+static void
gen_ashift_hi (int type, int n, rtx reg)
{
/* Negative values here come from the shift_amounts array. */
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index a8c11b5..2224fa4 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -3492,10 +3492,9 @@ label:
;; SImode shift left
(define_expand "ashlsi3"
- [(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
- (ashift: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_operand" "")
+ (ashift:SI (match_operand:SI 1 "arith_reg_operand" "")
+ (match_operand:SI 2 "shift_count_operand" "")))]
""
{
if (TARGET_SHMEDIA)
@@ -3503,56 +3502,74 @@ label:
emit_insn (gen_ashlsi3_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 (TARGET_DYNSHIFT)
+ if (TARGET_DYNSHIFT
+ && CONST_INT_P (operands[2]) && sh_dynamicalize_shift_p (operands[2]))
+ operands[2] = force_reg (SImode, operands[2]);
+})
+
+(define_insn "ashlsi3_k"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
+ (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
+ (match_operand:SI 2 "p27_shift_count_operand" "M,P27")))]
+ "TARGET_SH1"
+ "@
+ add %0,%0
+ shll%O2 %0"
+ [(set_attr "type" "arith")])
+
+(define_insn_and_split "ashlsi3_d"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0")
+ (match_operand:SI 2 "shift_count_operand" "r")))]
+ "TARGET_DYNSHIFT"
+ "shld %2,%0"
+ "&& (CONST_INT_P (operands[2]) && ! sh_dynamicalize_shift_p (operands[2]))"
+ [(const_int 0)]
+{
+ if (satisfies_constraint_P27 (operands[2]))
{
- emit_insn (gen_ashlsi3_std (operands[0], operands[1], operands[2]));
+ emit_insn (gen_ashlsi3_k (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ else if (!satisfies_constraint_P27 (operands[2]))
+ {
+ emit_insn (gen_ashlsi3_n (operands[0], operands[1], operands[2]));
DONE;
}
- if (! immediate_operand (operands[2], GET_MODE (operands[2])))
- FAIL;
-})
-;; This pattern is used by init_expmed for computing the costs of shift
-;; insns.
-(define_insn_and_split "ashlsi3_std"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r,r,r,r")
- (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0,0,0")
- (match_operand:SI 2 "nonmemory_operand" "r,M,P27,?ri")))
- (clobber (match_scratch:SI 3 "=X,X,X,&r"))]
- "TARGET_DYNSHIFT || (TARGET_SH1 && satisfies_constraint_P27 (operands[2]))"
- "@
- shld %2,%0
- add %0,%0
- shll%O2 %0
- #"
- "TARGET_DYNSHIFT
- && reload_completed
- && CONST_INT_P (operands[2])
- && ! satisfies_constraint_P27 (operands[2])"
- [(set (match_dup 3) (match_dup 2))
- (parallel
- [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 3)))
- (clobber (match_dup 4))])]
-{
- operands[4] = gen_rtx_SCRATCH (SImode);
+ FAIL;
}
- [(set_attr "length" "*,*,*,4")
- (set_attr "type" "dyn_shift,arith,arith,arith")])
+ [(set_attr "type" "arith")])
(define_insn_and_split "ashlsi3_n"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(ashift: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])"
+ (match_operand:SI 2 "not_p27_shift_count_operand" "")))]
+ "TARGET_SH1"
"#"
- "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 (ASHIFT, operands);
+ if (INTVAL (operands[2]) == 31)
+ {
+ /* If the shift amount is 31 we split into a different sequence before
+ reload so that it gets a chance to allocate R0 for the sequence.
+ If it fails to do so (due to pressure on R0), it will take one insn
+ more for the and. */
+ emit_insn (gen_andsi3 (operands[0], operands[1], const1_rtx));
+ emit_insn (gen_rotlsi3_31 (operands[0], operands[0]));
+ }
+ 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, operands[2]);
+ emit_insn (gen_ashlsi3_d (operands[0], operands[1], operands[2]));
+ }
+ else
+ gen_shifty_op (ASHIFT, operands);
+
DONE;
})