aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorOleg Endo <olegendo@gcc.gnu.org>2013-10-29 20:45:56 +0000
committerOleg Endo <olegendo@gcc.gnu.org>2013-10-29 20:45:56 +0000
commitdd331dd0b5925b1b5ef8b740af0bd2e590248603 (patch)
treec13da6c96167b6f0e064b5ded476c94ae0d9e39c /gcc/config
parentc6a684e36cabdac2c001b81426e075da29081cc3 (diff)
downloadgcc-dd331dd0b5925b1b5ef8b740af0bd2e590248603.zip
gcc-dd331dd0b5925b1b5ef8b740af0bd2e590248603.tar.gz
gcc-dd331dd0b5925b1b5ef8b740af0bd2e590248603.tar.bz2
re PR target/54236 ([SH] Improve addc and subc insn utilization)
PR target/54236 * config/sh/sh.md (*addc): Rename existing variations to ... (*addc_r_r_1, *addc_2r_1, *addc_r_1): ... these. (*addc_r_lsb, *addc_r_r_lsb, *addc_r_lsb_r, *addc_2r_lsb, *addc_r_msb, *addc_r_r_msb, *addc_2r_msb): New insn_and_split patterns. * config/sh/sh.c (addsubcosts): Handle some addc special cases. PR target/54236 * gcc.target/sh/pr54236-2: New. * gcc.target/sh/pr54089-6: Add another rotl special case. From-SVN: r204180
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/sh/sh.c29
-rw-r--r--gcc/config/sh/sh.md126
2 files changed, 152 insertions, 3 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index ae4b7a5..167b615 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -3159,6 +3159,35 @@ and_xor_ior_costs (rtx x, int code)
static inline int
addsubcosts (rtx x)
{
+ if (GET_MODE (x) == SImode)
+ {
+ /* The addc or subc patterns will eventually become one or two
+ instructions. Below are some costs for some of the patterns
+ which combine would reject because the costs of the individual
+ insns in the patterns are lower.
+
+ FIXME: It would be much easier if we had something like insn cost
+ attributes and the cost calculation machinery used those attributes
+ in the first place. This would eliminate redundant recog-like C
+ code to calculate costs of complex patterns. */
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+
+ if (GET_CODE (x) == PLUS)
+ {
+ if (GET_CODE (op0) == AND
+ && XEXP (op0, 1) == const1_rtx
+ && (GET_CODE (op1) == PLUS
+ || (GET_CODE (op1) == MULT && XEXP (op1, 1) == const2_rtx)))
+ return 1;
+
+ if (GET_CODE (op0) == MULT && XEXP (op0, 1) == const2_rtx
+ && GET_CODE (op1) == LSHIFTRT
+ && CONST_INT_P (XEXP (op1, 1)) && INTVAL (XEXP (op1, 1)) == 31)
+ return 1;
+ }
+ }
+
/* On SH1-4 we have only max. SImode operations.
Double the cost for modes > SImode. */
const int cost_scale = !TARGET_SHMEDIA
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index db4f8d2..0b95299 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -1841,7 +1841,7 @@
;; Split 'reg + reg + 1' into a sett addc sequence, as it can be scheduled
;; better, if the sett insn can be done early.
-(define_insn_and_split "*addc"
+(define_insn_and_split "*addc_r_r_1"
[(set (match_operand:SI 0 "arith_reg_dest" "")
(plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "arith_reg_operand" ""))
@@ -1857,7 +1857,7 @@
;; Left shifts by one are usually done with an add insn to avoid T_REG
;; clobbers. Thus addc can also be used to do something like '(x << 1) + 1'.
-(define_insn_and_split "*addc"
+(define_insn_and_split "*addc_2r_1"
[(set (match_operand:SI 0 "arith_reg_dest")
(plus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand")
(const_int 2))
@@ -1897,7 +1897,7 @@
;; can be scheduled much better since the load of the constant can be
;; done earlier, before any comparison insns that store the result in
;; the T bit.
-(define_insn_and_split "*addc"
+(define_insn_and_split "*addc_r_1"
[(set (match_operand:SI 0 "arith_reg_dest" "")
(plus:SI (match_operand:SI 1 "t_reg_operand" "")
(match_operand:SI 2 "arith_reg_operand" "")))
@@ -1910,6 +1910,126 @@
(match_dup 1)))
(clobber (reg:SI T_REG))])])
+;; Use shlr-addc to do 'reg + (reg & 1)'.
+(define_insn_and_split "*addc_r_lsb"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 1))
+ (match_operand:SI 2 "arith_reg_operand")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0) (plus:SI (reg:SI T_REG) (match_dup 2)))
+ (clobber (reg:SI T_REG))])]
+{
+ emit_insn (gen_shlr (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Use shlr-addc to do 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_r_r_lsb"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 1))
+ (match_operand:SI 2 "arith_reg_operand"))
+ (match_operand:SI 3 "arith_reg_operand")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 2) (match_dup 3))
+ (reg:SI T_REG)))
+ (clobber (reg:SI T_REG))])]
+{
+ emit_insn (gen_shlr (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Canonicalize 'reg + (reg & 1) + reg' into 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_r_lsb_r"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 1))
+ (plus:SI (match_operand:SI 2 "arith_reg_operand")
+ (match_operand:SI 3 "arith_reg_operand"))))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0)
+ (plus:SI (plus:SI (and:SI (match_dup 1) (const_int 1))
+ (match_dup 2))
+ (match_dup 3)))
+ (clobber (reg:SI T_REG))])])
+
+;; Canonicalize '2 * reg + (reg & 1)' into 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_2r_lsb"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (and:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 1))
+ (mult:SI (match_operand:SI 2 "arith_reg_operand")
+ (const_int 2))))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0)
+ (plus:SI (plus:SI (and:SI (match_dup 1) (const_int 1))
+ (match_dup 2))
+ (match_dup 2)))
+ (clobber (reg:SI T_REG))])])
+
+;; Use shll-addc to do 'reg + ((unsigned int)reg >> 31)'.
+(define_insn_and_split "*addc_r_msb"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 31))
+ (match_operand:SI 2 "arith_reg_operand")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0) (plus:SI (reg:SI T_REG) (match_dup 2)))
+ (clobber (reg:SI T_REG))])]
+{
+ emit_insn (gen_shll (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Use shll-addc to do 'reg + reg + ((unsigned int)reg >> 31)'.
+(define_insn_and_split "*addc_r_r_msb"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (plus:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 31))
+ (match_operand:SI 2 "arith_reg_operand"))
+ (match_operand:SI 3 "arith_reg_operand")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 2) (match_dup 3))
+ (reg:SI T_REG)))
+ (clobber (reg:SI T_REG))])]
+{
+ emit_insn (gen_shll (gen_reg_rtx (SImode), operands[1]));
+})
+
+;; Canonicalize '2 * reg + ((unsigned int)reg >> 31)'
+;; into 'reg + reg + (reg & 1)'.
+(define_insn_and_split "*addc_2r_msb"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (plus:SI (mult:SI (match_operand:SI 1 "arith_reg_operand")
+ (const_int 2))
+ (lshiftrt:SI (match_operand:SI 2 "arith_reg_operand")
+ (const_int 31))))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(parallel [(set (match_dup 0)
+ (plus:SI (plus:SI (lshiftrt:SI (match_dup 2) (const_int 31))
+ (match_dup 1))
+ (match_dup 1)))
+ (clobber (reg:SI T_REG))])])
+
(define_expand "addsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(plus:SI (match_operand:SI 1 "arith_operand" "")