OSDN Git Service

mn10300: Explicitly represent MDR in multiply and divide.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 19 Jan 2011 17:27:58 +0000 (17:27 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 19 Jan 2011 17:27:58 +0000 (17:27 +0000)
Note that the mulsidi3_internal pattern is structured so
as to let the lower-subregs pass fully split the result.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@169008 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mn10300/mn10300.md

index 6e5dc0e..e2bda22 100644 (file)
@@ -1,5 +1,20 @@
 2011-01-19  Richard Henderson  <rth@redhat.com>
 
+       * config/mn10300/mn10300.md (UNSPEC_EXT): New.
+       (throughput_42_latency_43): New reservation.
+       (mulsidi3, umulsidi3): New expanders.
+       (mulsidi3_internal): Rewrite from old mulsidi3 pattern.  Expose
+       the MDR register to allocation; separately allocate the low and
+       high parts of the DImode result.
+       (umulsidi3_internal): Similarly.
+       (*am33_mulsi3, *mn10300_mulsi3): Merge into ...
+       (*mulsi3): ... here.  Clobber MDR as a scratch as necessary.
+       (udivsi3, umodsi3): Remove.
+       (udivmodsi4, divmodsi4): New expanders.
+       (*udivmodsi4): Rename from udivmodsi4.  Expose MDR properly.
+       (*divmodsi4): Simiarly.
+       (ext_internal): New.
+
        * config/mn10300/constraints.md ("z"): New constraint.
        * config/mn10300/mn10300.h (MDR_REGNUM): Remove.
        (FIXED_REGISTERS): Don't fix MDR.
index 5f4f17a..bc68ca5 100644 (file)
@@ -38,6 +38,7 @@
   (UNSPEC_PLT          4)
   (UNSPEC_GOTSYM_OFF   5)
 
+  (UNSPEC_EXT          6)
   (UNSPEC_BSCH         7)
 ])
 
   (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
 ;; 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)))]
 )
 
 \f