diff options
author | olegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-08-16 23:19:45 +0000 |
---|---|---|
committer | olegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-08-16 23:19:45 +0000 |
commit | 40b94d3c57006a1edda17ad0c294c16d10902e95 (patch) | |
tree | 4e1cabf9877a8b6fbc1ec3c14a08cbf72706a59c /gcc/config/sh/sh.md | |
parent | d82b04919bc6cd3baf2310efdc88e3a9b6bdfb49 (diff) | |
download | gcc-40b94d3c57006a1edda17ad0c294c16d10902e95.tar.gz |
PR target/54236
* config/sh/sh.md (addc): Add commutative modifier.
(*addc, *minus_plus_one, *subc, *negc): New insns and splits.
PR target/54236
* gcc.target/sh/pr54236-1.c: New.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@190459 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sh/sh.md')
-rw-r--r-- | gcc/config/sh/sh.md | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 5128bcef3fe..26d3e636d91 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -1686,7 +1686,7 @@ (define_insn "addc" [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "0") + (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%0") (match_operand:SI 2 "arith_reg_operand" "r")) (reg:SI T_REG))) (set (reg:SI T_REG) @@ -1695,6 +1695,76 @@ "addc %2,%0" [(set_attr "type" "arith")]) +;; A simplified version of the addc insn, where the exact value of the +;; T bit doesn't matter. This is easier for combine to pick up. +;; We allow a reg or 0 for one of the operands in order to be able to +;; do 'reg + T' sequences. Reload will load the constant 0 into the reg +;; as needed. +(define_insn "*addc" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (plus:SI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%0") + (match_operand:SI 2 "arith_reg_or_0_operand" "r")) + (match_operand:SI 3 "t_reg_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "addc %2,%0" + [(set_attr "type" "arith")]) + +;; 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" + [(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" "")) + (const_int 1))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(set (reg:SI T_REG) (const_int 1)) + (parallel [(set (match_dup 0) (plus:SI (plus:SI (match_dup 1) (match_dup 2)) + (reg:SI T_REG))) + (clobber (reg:SI T_REG))])]) + +;; Sometimes combine will try to do 'reg + (0-reg) + 1' if the *addc pattern +;; matched. Split this up into a simple sub add sequence, as this will save +;; us one sett insn. +(define_insn_and_split "*minus_plus_one" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (plus:SI (minus:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" "")) + (const_int 1)))] + "TARGET_SH1" + "#" + "&& 1" + [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 0) (const_int 1)))]) + +;; Split 'reg + T' into 'reg + 0 + T' to utilize the addc insn. +;; If the 0 constant can be CSE-ed, this becomes a one instruction +;; operation, as opposed to sequences such as +;; movt r2 +;; add r2,r3 +;; +;; Even if the constant is not CSE-ed, a sequence such as +;; mov #0,r2 +;; addc r2,r3 +;; 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" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (plus:SI (match_operand:SI 1 "t_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (plus:SI (plus:SI (match_dup 2) (const_int 0)) + (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" "") @@ -1805,6 +1875,63 @@ "subc %2,%0" [(set_attr "type" "arith")]) +;; A simplified version of the subc insn, where the exact value of the +;; T bit doesn't matter. This is easier for combine to pick up. +;; We allow a reg or 0 for one of the operands in order to be able to +;; do 'reg - T' sequences. Reload will load the constant 0 into the reg +;; as needed. +(define_insn "*subc" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (minus:SI (minus:SI (match_operand:SI 1 "arith_reg_operand" "0") + (match_operand:SI 2 "arith_reg_or_0_operand" "r")) + (match_operand:SI 3 "t_reg_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "subc %2,%0" + [(set_attr "type" "arith")]) + +;; Split reg - reg - 1 into a sett subc sequence, as it can be scheduled +;; better, if the sett insn can be done early. +;; Notice that combine turns 'a - b - 1' into 'a + (~b)'. +(define_insn_and_split "*subc" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (plus:SI (not:SI (match_operand:SI 1 "arith_reg_operand" "")) + (match_operand:SI 2 "arith_reg_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(set (reg:SI T_REG) (const_int 1)) + (parallel [(set (match_dup 0) + (minus:SI (minus:SI (match_dup 2) (match_dup 1)) + (reg:SI T_REG))) + (clobber (reg:SI T_REG))])]) + +;; Split 'reg - T' into 'reg - 0 - T' to utilize the subc insn. +;; If the 0 constant can be CSE-ed, this becomes a one instruction +;; operation, as opposed to sequences such as +;; movt r2 +;; sub r2,r3 +;; +;; Even if the constant is not CSE-ed, a sequence such as +;; mov #0,r2 +;; subc r2,r3 +;; 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 "*subc" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (minus:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "t_reg_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (minus:SI (minus:SI (match_dup 1) (const_int 0)) + (match_dup 2))) + (clobber (reg:SI T_REG))])]) + (define_insn "*subsi3_internal" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (minus:SI (match_operand:SI 1 "arith_reg_operand" "0") @@ -4530,6 +4657,19 @@ label: "negc %1,%0" [(set_attr "type" "arith")]) +;; A simplified version of the negc insn, where the exact value of the +;; T bit doesn't matter. This is easier for combine to pick up. +;; Notice that '0 - x - 1' is the same as '~x', thus we don't specify +;; extra patterns for this case. +(define_insn "*negc" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (minus:SI (neg:SI (match_operand:SI 1 "arith_reg_operand" "r")) + (match_operand:SI 2 "t_reg_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "negc %1,%0" + [(set_attr "type" "arith")]) + (define_insn "*negdi_media" [(set (match_operand:DI 0 "arith_reg_dest" "=r") (neg:DI (match_operand:DI 1 "arith_reg_operand" "r")))] |