Patchwork [17/28] mn10300: Explicitly represent MDR in multiply and divide.

login
register
mail settings
Submitter Richard Henderson
Date Jan. 10, 2011, 8:31 p.m.
Message ID <1294691517-19580-18-git-send-email-rth@redhat.com>
Download mbox | patch
Permalink /patch/78215/
State New
Headers show

Comments

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

Note that the mulsidi3_internal pattern is structured so
as to let the lower-subregs pass fully split the result.
---
 gcc/config/mn10300/mn10300.md |  271 +++++++++++++++++++++++------------------
 1 files changed, 155 insertions(+), 116 deletions(-)
Jeff Law - Jan. 18, 2011, 5:13 p.m.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Note that the mulsidi3_internal pattern is structured so
> as to let the lower-subregs pass fully split the result.
OK
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNcpSAAoJEBRtltQi2kC71b8H/3rj+M77p8W7QBZ735ETWIMV
VlzPlU6v4XMeA/y55wsYp5majf2X/xXlQVPV5tBKTpoyspHggDX5zQYa7w3YbM3e
DpiZCoRlt+H/MlqSaqxx7f8r0+5+pbapdorW4UTtoexjqVMlM7Lnx3lOye7AVad3
bWuQ29jco1LrRGRJW8qpSdhDGitWvVkZNxBgg7tNdUj8zeRsGGPjSGTVqImZOYBw
KdIc2Tg6qV+SGuy2pRdnQ7Bhe9oj6Y4l2T0AadGvUHm4VsAtdOlSJNWlGjiGjNLw
4zwlQL0Zptha+4bKUxFEHSu9q3nqsPaGF47JydVX03oolFmOnJK79uOk971UD5s=
=gHKO
-----END PGP SIGNATURE-----

Patch

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 86f26728..88743d6 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -37,6 +37,8 @@ 
   (UNSPEC_GOTOFF	3)
   (UNSPEC_PLT		4)
   (UNSPEC_GOTSYM_OFF	5)
+
+  (UNSPEC_EXT		6)
 ])
 
 (include "predicates.md")
@@ -160,6 +162,8 @@ 
   (eq_attr "timings" "4040") "throughput*40")
 (define_insn_reservation "throughput_41_latency_42" 42
   (eq_attr "timings" "4142") "throughput*41,nothing")
+(define_insn_reservation "throughput_42_latency_43" 44
+  (eq_attr "timings" "4243") "throughput*42,nothing")
 (define_insn_reservation "throughput_43_latency_44" 44
   (eq_attr "timings" "4344") "throughput*43,nothing")
 (define_insn_reservation "throughput_45_latency_46" 46
@@ -708,148 +712,183 @@ 
 ;; MULTIPLY INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "mulsidi3"
-  [(set (match_operand:DI 0 "register_operand" "=dax")
-        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "dax"))
-                 (sign_extend:DI (match_operand:SI 2 "register_operand" "dax"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "mul %1,%2,%H0,%L0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 24) (const_int 23)))]
-)
+;; ??? Note that AM33 has a third multiply variant that puts the high part
+;; into the MDRQ register, however this variant also constrains the inputs
+;; to be in DATA_REGS and thus isn't as helpful as it might be considering
+;; the existance of the 4-operand multiply.  Nor is there a set of divide
+;; insns that use MDRQ.  Given that there is an IMM->MDRQ insn, this would
+;; have been very handy for starting udivmodsi4...
+
+(define_expand "mulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+                 (sign_extend:DI (match_operand:SI 2 "register_operand" ""))))]
+  ""
+{
+  emit_insn (gen_mulsidi3_internal (gen_lowpart (SImode, operands[0]),
+				    gen_highpart (SImode, operands[0]),
+				    operands[1], operands[2]));
+  DONE;
+})
 
-(define_insn "umulsidi3"
-  [(set (match_operand:DI                          0 "register_operand" "=dax")
-        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "dax"))
-                 (zero_extend:DI (match_operand:SI 2 "register_operand" "dax"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "mulu %1,%2,%H0,%L0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 24) (const_int 23)))]
+(define_insn "mulsidi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=D,r")
+	(mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+		 (match_operand:SI 3 "register_operand" " D,r")))
+   (set (match_operand:SI          1 "register_operand" "=z,r")
+	(truncate:SI
+	  (ashiftrt:DI
+	    (mult:DI (sign_extend:DI (match_dup 2))
+		     (sign_extend:DI (match_dup 3)))
+	    (const_int 32))))
+   (clobber (reg:CC CC_REG))]
+  ""
+{
+  if (which_alternative == 1)
+    return "mul %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mul %3,%0";
+  else
+    return "mul %3,%0";
+}
+  [(set_attr "isa" "*,am33")
+   (set (attr "timings")
+        (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-(define_expand "mulsi3"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
-		   (mult:SI (match_operand:SI 1 "register_operand")
-			    (match_operand:SI 2 "register_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+(define_expand "umulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+                 (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
+{
+  emit_insn (gen_umulsidi3_internal (gen_lowpart (SImode, operands[0]),
+				     gen_highpart (SImode, operands[0]),
+				     operands[1], operands[2]));
+  DONE;
+})
 
-(define_insn "*am33_mulsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,!dax")
-	(mult:SI (match_operand:SI 1 "register_operand" "%0,0")
-		 (match_operand:SI 2 "nonmemory_operand" "dx,daxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
+(define_insn "umulsidi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=D,r")
+	(mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+		 (match_operand:SI 3 "register_operand" " D,r")))
+   (set (match_operand:SI          1 "register_operand" "=z,r")
+	(truncate:SI
+	  (lshiftrt:DI
+	    (mult:DI (zero_extend:DI (match_dup 2))
+		     (zero_extend:DI (match_dup 3)))
+	    (const_int 32))))
+   (clobber (reg:CC CC_REG))]
+  ""
 {
-  if (TARGET_MULT_BUG)
-    return \"nop\;nop\;mul %2,%0\";
+  if (which_alternative == 1)
+    return "mulu %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mulu %3,%0";
   else
-    return \"mul %2,%0\";
-}"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+    return "mulu %3,%0";
+}
+  [(set_attr "isa" "*,am33")
+   (set (attr "timings")
+        (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-(define_insn "*mn10300_mulsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-	(mult:SI (match_operand:SI 1 "register_operand" "%0")
-		 (match_operand:SI 2 "register_operand" "dx")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_expand "mulsi3"
+  [(parallel [(set (match_operand:SI          0 "register_operand"  "")
+		   (mult:SI (match_operand:SI 1 "register_operand"  "")
+			    (match_operand:SI 2 "nonmemory_operand" "")))
+	      (clobber (match_scratch:SI      3 ""))
+	      (clobber (reg:CC CC_REG))])]
   ""
-  "*
-{
-  if (TARGET_MULT_BUG)
-    return \"nop\;nop\;mul %2,%0\";
-  else
-    return \"mul %2,%0\";
-}"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-  	      		 	       (const_int 24) (const_int 23)))]
 )
 
-;; ??? This pattern causes too-high register pressure for MN103.
-;; ??? To be fixed by exposing the MDR register properly.
-(define_insn "udivmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=D")
-	(udiv:SI (match_operand:SI 1 "register_operand" "0")
-		 (match_operand:SI 2 "register_operand" "D")))
-   (set (match_operand:SI          3 "register_operand" "=&d")
-	(umod:SI (match_dup 1) (match_dup 2)))
+(define_insn "*mulsi3"
+  [(set (match_operand:SI          0 "register_operand"  "=D, r,r")
+	(mult:SI (match_operand:SI 2 "register_operand"  "%0, 0,r")
+		 (match_operand:SI 3 "nonmemory_operand" " D,ri,r")))
+   (clobber (match_scratch:SI      1                     "=z, z,r"))
    (clobber (reg:CC CC_REG))]
-  "TARGET_AM33"
+  ""
 {
-  output_asm_insn ("clr %3\;ext %3", operands);
-  if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return "divu %2,%0";
+  if (which_alternative == 2)
+    return "mul %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mul %3,%0";
   else
-    return "divu %2,%0\;mov mdr,%3";
+    return "mul %3,%0";
 }
-  ;; Timings:  AM33   AM34
-  ;;  SUB       1/1    1/1
-  ;;  MOV       1/1    1/1
-  ;;  DIVU     38/39  42/43
-  ;;  MOV       1/1    1/1
-  ;;  --------------------
-  ;;  total    41/42  45/46  (worst case sceanario)
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-  	      		 	       (const_int 4546) (const_int 4142)))]
+  [(set_attr "isa" "*,am33,am33")
+   (set (attr "timings")
+	(if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-;; ??? In the meantime MN103 can use these two patterns,
-;; which reduce the register pressure by one.
-(define_insn "udivsi3"
-  [(set (match_operand:SI          0 "register_operand" "=&d")
-	(udiv:SI (match_operand:SI 1 "register_operand" "d")
-		 (match_operand:SI 2 "register_operand" "d")))
-   (clobber (reg:CC CC_REG))]
-  "!TARGET_AM33"
-  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0"
-  [(set_attr "timings" "4142")]
+(define_expand "udivmodsi4"
+  [(parallel [(set (match_operand:SI          0 "register_operand")
+		   (udiv:SI (match_operand:SI 1 "register_operand")
+			    (match_operand:SI 2 "register_operand")))
+	      (set (match_operand:SI          3 "register_operand")
+		   (umod:SI (match_dup 1) (match_dup 2)))
+	      (use (const_int 0))
+	      (clobber (reg:CC CC_REG))])]
+  ""
 )
 
-(define_insn "umodsi3"
-  [(set (match_operand:SI          0 "register_operand" "=&d")
-	(umod:SI (match_operand:SI 1 "register_operand" "d")
-		 (match_operand:SI 2 "register_operand" "d")))
+;; Note the trick to get reload to put the zero into the MDR register,
+;; rather than exposing the load early and letting CSE or someone try
+;; to share the zeros between division insns.  Which tends to result
+;; in sequences like 0->r0->d0->mdr.
+
+(define_insn "*udivmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
+	(udiv:SI (match_operand:SI 2 "register_operand" " 0")
+		 (match_operand:SI 3 "register_operand" " D")))
+   (set (match_operand:SI          1 "register_operand" "=z")
+	(umod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI          4 "nonmemory_operand" " 1"))
    (clobber (reg:CC CC_REG))]
-  "!TARGET_AM33"
-  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0\;mov mdr,%0"
-  [(set_attr "timings" "4142")]
+  ""
+  "divu %3,%0"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+  	      		 	       (const_int 3839) (const_int 4243)))]
 )
 
-(define_insn "divmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-	(div:SI (match_operand:SI  1 "register_operand"  "0")
-		 (match_operand:SI 2 "register_operand"  "dx")))
-   (set (match_operand:SI          3 "register_operand" "=d")
-	(mod:SI (match_dup 1) (match_dup 2)))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_expand "divmodsi4"
+  [(parallel [(set (match_operand:SI          0 "register_operand" "")
+		   (div:SI (match_operand:SI  1 "register_operand" "")
+			   (match_operand:SI  2 "register_operand" "")))
+	      (set (match_operand:SI          3 "register_operand" "")
+		   (mod:SI (match_dup 1) (match_dup 2)))
+	      (use (match_dup 4))
+	      (clobber (reg:CC CC_REG))])]
   ""
-  "*
 {
-  if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return \"ext %0\;div %2,%0\";
-  else
-    return \"ext %0\;div %2,%0\;mov mdr,%3\";
-}"
-  ;; Timings:  AM33   AM34
-  ;;  EXT       1/1    1/1
-  ;;  DIV      38/39  42/43
-  ;;  --------------------
-  ;;  total    39/40  43/44  (worst case sceanario)
+  operands[4] = gen_reg_rtx (SImode);
+  emit_insn (gen_ext_internal (operands[4], operands[1]));
+})
+
+;; ??? Ideally we'd represent this via shift, but it seems like adding a
+;; special-case pattern for (ashiftrt x 31) is just as likely to result
+;; in poor register allocation choices.
+(define_insn "ext_internal"
+  [(set (match_operand:SI 0 "register_operand" "=z")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "D")] UNSPEC_EXT))]
+  ""
+  "ext %1"
+)
+
+(define_insn "*divmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
+	(div:SI (match_operand:SI  2 "register_operand" " 0")
+		(match_operand:SI  3 "register_operand" " D")))
+   (set (match_operand:SI          1 "register_operand" "=z")
+	(mod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI          4 "register_operand" " 1"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "div %3,%0";
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-  	      		 	       (const_int 4344) (const_int 3940)))]
+  	      		 	       (const_int 3839) (const_int 4243)))]
 )