summaryrefslogtreecommitdiff
path: root/gcc/config/sh/sh.md
diff options
context:
space:
mode:
authorolegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-16 23:19:45 +0000
committerolegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-16 23:19:45 +0000
commit40b94d3c57006a1edda17ad0c294c16d10902e95 (patch)
tree4e1cabf9877a8b6fbc1ec3c14a08cbf72706a59c /gcc/config/sh/sh.md
parentd82b04919bc6cd3baf2310efdc88e3a9b6bdfb49 (diff)
downloadgcc-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.md142
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")))]