diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2013-10-29 20:45:56 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2013-10-29 20:45:56 +0000 |
commit | dd331dd0b5925b1b5ef8b740af0bd2e590248603 (patch) | |
tree | c13da6c96167b6f0e064b5ded476c94ae0d9e39c /gcc/config | |
parent | c6a684e36cabdac2c001b81426e075da29081cc3 (diff) | |
download | gcc-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.c | 29 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 126 |
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" "") |