diff mbox

[24/28] mn10300: Implement adddi3, subdi3.

Message ID 1294691517-19580-25-git-send-email-rth@redhat.com
State New
Headers show

Commit Message

Richard Henderson Jan. 10, 2011, 8:31 p.m. UTC
From: Richard Henderson <rth@twiddle.net>

Via expander, pre- and post-reload patterns.  The pre-reload
pattern is defined to allow lower_subregs totally split the
DImode values.
---
 gcc/config/mn10300/mn10300.md    |  321 ++++++++++++++++++++++++++++++++++++++
 gcc/config/mn10300/predicates.md |    5 +
 2 files changed, 326 insertions(+), 0 deletions(-)

Comments

Jeff Law Jan. 19, 2011, 6:17 p.m. UTC | #1
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Via expander, pre- and post-reload patterns.  The pre-reload
> pattern is defined to allow lower_subregs totally split the
> DImode values.
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNyqbAAoJEBRtltQi2kC7jzUH/2XQYA6baim2SkfMbHqyuVXE
wkzYgkqspnal3GQh+07gtomVyaYFcaH5G6VG2XiSkS/Nb779EJ2V/AqLkAyc76K9
36DraGc7uiEXzNt4DByuqch2LcNiwsAWbpjOuB5BhmhKAUGxy2Ztd0JTi7WhVBg7
p9rW15wmcum4ckAV+XaQZkiChoC7JKyuVB41U9fZU8SnSoOEMKga/7MeaD4kbPpZ
5nY+3/kfmv+ZeC6u87xwUW5AkTOcQ84kGXAfpJnbeoYWLuQ7303Hi8xRDl7CyYRg
pyARIfLWPAPntQ5TBaCdHPeLneTQSuosRUM1pjPFwKCdlBlLr7VFX6HlOclqTIw=
=u7h7
-----END PGP SIGNATURE-----
diff mbox

Patch

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index fae87e9..edfdb5d 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -534,6 +534,172 @@ 
   [(set_attr "timings" "11,22")]
 )
 
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+		   (plus:SI (match_operand:SI 1 "register_operand")
+			    (match_operand:SI 2 "nonmemory_operand")))
+	      (set (reg:CCZNC CC_REG)
+		   (compare:CCZNC (plus:SI (match_dup 1) (match_dup 2))
+				  (const_int 0)))])]
+  ""
+)
+
+(define_insn "addc_internal"
+  [(set (match_operand:SI 0 "register_operand"            "=D,r,r")
+	(plus:SI
+	  (plus:SI
+	    (ltu:SI (reg:CC CC_REG) (const_int 0))
+	    (match_operand:SI 1 "register_operand"        "%0,0,r"))
+	  (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r")))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "@
+   addc %2,%0
+   addc %2,%0
+   addc %2,%1,%0"
+  [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "adddi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(plus:DI (match_operand:DI 1 "register_operand" "")
+		 (match_operand:DI 2 "nonmemory_operand" "")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  if (!reg_or_am33_const_operand (op2h, SImode))
+    op2h = force_reg (SImode, op2h);
+
+  emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+;; Note that reload only supports one commutative operand.  Thus we cannot
+;; auto-swap both the high and low outputs with their matching constraints.
+;; For MN103, we're strapped for registers but thankfully the alternatives
+;; are few.  For AM33, it becomes much easier to not represent the early
+;; clobber and 6 permutations of immediate and three-operand adds, but
+;; instead allocate a scratch register and do the expansion by hand.
+
+(define_insn_and_split "adddi3_internal"
+  [(set (match_operand:SI          0 "register_operand"   "=r, r, r")
+	(plus:SI (match_operand:SI 2 "register_operand"   "%0, 0, r")
+		 (match_operand:SI 3 "nonmemory_operand"  "ri,ri,ri")))
+   (set (match_operand:SI          1 "register_operand"   "=D, D, r")
+	(plus:SI
+	  (plus:SI
+	    (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+	    (match_operand:SI      4 "register_operand"   " 1, D, r"))
+	  (match_operand:SI 5 "reg_or_am33_const_operand" " D, 1,ri")))
+   (clobber (match_scratch:SI      6                      "=X, X,&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op2l = operands[3];
+  rtx op1h = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+  rtx x;
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+	op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
+
+  if (rtx_equal_p (op0l, op1l))
+    ;
+  else if (rtx_equal_p (op0l, op2l))
+    x = op1l, op1l = op2l, op2l = x;
+  else
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2l))
+	{
+	  emit_move_insn (op0l, op2l);
+	  op2l = op1l;
+	  op1l = op0l;
+	}
+    }
+  emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+  if (rtx_equal_p (op0h, op1h))
+    ;
+  else if (rtx_equal_p (op0h, op2h))
+    x = op1h, op1h = op2h, op2h = x;
+  else
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2h))
+	{
+	  emit_move_insn (op0h, op2h);
+	  op2h = op1h;
+	  op1h = op0h;
+	}
+    }
+  emit_insn (gen_addc_internal (op0h, op1h, op2h));
+  DONE;
+}
+  [(set_attr "isa" "*,*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word add is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*adddi3_degenerate"
+  [(set (match_operand:SI          0 "register_operand"  "=&r,&r")
+	(match_operand:SI          2 "nonmemory_operand" "  0, 0"))
+   (set (match_operand:SI          1 "register_operand"  "=r , r")
+	(plus:SI (match_operand:SI 3 "register_operand"  "%1 , r")
+		 (match_operand:SI 4 "nonmemory_operand" "ri, r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  rtx scratch = NULL_RTX;
+  if (!rtx_equal_p (operands[0], operands[2]))
+    {
+      gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+      if (reg_overlap_mentioned_p (operands[0], operands[3])
+	  || reg_overlap_mentioned_p (operands[0], operands[4]))
+	{
+	  scratch = gen_reg_rtx (SImode);
+	  emit_move_insn (scratch, operands[2]);
+	}
+      else
+	emit_move_insn (operands[0], operands[2]);
+    }
+  emit_insn (gen_addsi3 (operands[1], operands[3], operands[4]));
+  if (scratch)
+    emit_move_insn (operands[0], scratch);
+  DONE;
+})
+
 ;; ----------------------------------------------------------------------
 ;; SUBTRACT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
@@ -566,6 +732,161 @@ 
    (set_attr "timings" "11,22")]
 )
 
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+		   (minus:SI (match_operand:SI 1 "register_operand")
+			     (match_operand:SI 2 "nonmemory_operand")))
+	      (set (reg:CCZNC CC_REG)
+		   (compare:CCZNC (minus:SI (match_dup 1) (match_dup 2))
+				  (const_int 0)))])]
+  ""
+)
+
+(define_insn "subc_internal"
+  [(set (match_operand:SI 0 "register_operand"                      "=D,r,r")
+	(minus:SI
+	  (minus:SI (match_operand:SI 1 "register_operand"          " 0,0,r")
+		    (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r"))
+	  (geu:SI (reg:CC CC_REG) (const_int 0))))
+   (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "@
+   subc %2,%0
+   subc %2,%0
+   subc %2,%1,%0"
+  [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "subdi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (minus:DI (match_operand:DI 1 "register_operand" "")
+                  (match_operand:DI 2 "nonmemory_operand" "")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  if (!reg_or_am33_const_operand (op2h, SImode))
+    op2h = force_reg (SImode, op2h);
+
+  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op1h, op2l, op2h));
+  DONE;
+})
+
+;; As with adddi3, the use of the scratch register helps reduce the 
+;; number of permutations for AM33.
+;; ??? The early clobber on op0 avoids a reload bug wherein both output
+;; registers are set the same.  Consider negate, where both op2 and op3
+;; are 0, are csed to the same input register, and reload fails to undo
+;; the cse when satisfying the matching constraints.
+
+(define_insn_and_split "subdi3_internal"
+  [(set (match_operand:SI     0 "register_operand"         "=&r, r")
+	(minus:SI
+	  (match_operand:SI   2 "register_operand"         "  0, r")
+	  (match_operand:SI   4 "nonmemory_operand"        " ri,ri")))
+   (set (match_operand:SI     1 "register_operand"         "=D , r")
+	(minus:SI
+	  (minus:SI
+	    (match_operand:SI 3 "register_operand"         "  1, r")
+	    (match_operand:SI 5 "reg_or_am33_const_operand" " D,ri"))
+	  (ltu:SI (match_dup 2) (match_dup 4))))
+   (clobber (match_scratch:SI 6                            "=X ,&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op1h = operands[3];
+  rtx op2l = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+	op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
+
+  if (!rtx_equal_p (op0l, op1l))
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2l))
+	{
+	  emit_move_insn (op0l, op1l);
+	  op1l = op0l;
+	}
+    }
+  emit_insn (gen_subsi3_flags (op0l, op1l, op2l));
+
+  if (!rtx_equal_p (op0h, op1h))
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2h))
+	{
+	  emit_move_insn (op0h, op1h);
+	  op1h = op0h;
+	}
+    }
+  emit_insn (gen_subc_internal (op0h, op1h, op2h));
+  DONE;
+}
+  [(set_attr "isa" "*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word sub is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*subdi3_degenerate"
+  [(set (match_operand:SI          0 "register_operand"   "=&r,&r")
+	(match_operand:SI          2 "nonmemory_operand"  "  0, 0"))
+   (set (match_operand:SI          1 "register_operand"   "=r , r")
+	(minus:SI (match_operand:SI 3 "register_operand"  "  1, r")
+		  (match_operand:SI 4 "nonmemory_operand" " ri, r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  rtx scratch = NULL_RTX;
+  if (!rtx_equal_p (operands[0], operands[2]))
+    {
+      gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+      if (reg_overlap_mentioned_p (operands[0], operands[3])
+	  || reg_overlap_mentioned_p (operands[0], operands[4]))
+	{
+	  scratch = gen_reg_rtx (SImode);
+	  emit_move_insn (scratch, operands[2]);
+	}
+      else
+	emit_move_insn (operands[0], operands[2]);
+    }
+  emit_insn (gen_subsi3 (operands[1], operands[3], operands[4]));
+  if (scratch)
+    emit_move_insn (operands[0], scratch);
+  DONE;
+})
+
 (define_insn_and_split "negsi2"
   [(set (match_operand:SI         0 "register_operand"  "=D,&r")
 	(neg:SI (match_operand:SI 1 "register_operand"  " 0, r")))
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index 4badebb..8316990 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -43,6 +43,11 @@ 
       || XEXP (op, 1) == stack_pointer_rtx;
 })
 
+(define_predicate "reg_or_am33_const_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_test "TARGET_AM33")
+	    (match_operand 0 "immediate_operand"))))
+
 (define_predicate "label_ref_operand"
   (match_code "label_ref"))