Commit 9efb4993 by Richard Henderson Committed by Richard Henderson

mn10300: Explicitly represent MDR in multiply and divide.

Note that the mulsidi3_internal pattern is structured so
as to let the lower-subregs pass fully split the result.

From-SVN: r169008
parent c25a21f5
2011-01-19 Richard Henderson <rth@redhat.com> 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/constraints.md ("z"): New constraint.
* config/mn10300/mn10300.h (MDR_REGNUM): Remove. * config/mn10300/mn10300.h (MDR_REGNUM): Remove.
(FIXED_REGISTERS): Don't fix MDR. (FIXED_REGISTERS): Don't fix MDR.
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
(UNSPEC_PLT 4) (UNSPEC_PLT 4)
(UNSPEC_GOTSYM_OFF 5) (UNSPEC_GOTSYM_OFF 5)
(UNSPEC_EXT 6)
(UNSPEC_BSCH 7) (UNSPEC_BSCH 7)
]) ])
...@@ -167,6 +168,8 @@ ...@@ -167,6 +168,8 @@
(eq_attr "timings" "4040") "throughput*40") (eq_attr "timings" "4040") "throughput*40")
(define_insn_reservation "throughput_41_latency_42" 42 (define_insn_reservation "throughput_41_latency_42" 42
(eq_attr "timings" "4142") "throughput*41,nothing") (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 (define_insn_reservation "throughput_43_latency_44" 44
(eq_attr "timings" "4344") "throughput*43,nothing") (eq_attr "timings" "4344") "throughput*43,nothing")
(define_insn_reservation "throughput_45_latency_46" 46 (define_insn_reservation "throughput_45_latency_46" 46
...@@ -748,148 +751,183 @@ ...@@ -748,148 +751,183 @@
;; MULTIPLY INSTRUCTIONS ;; MULTIPLY INSTRUCTIONS
;; ---------------------------------------------------------------------- ;; ----------------------------------------------------------------------
(define_insn "mulsidi3" ;; ??? Note that AM33 has a third multiply variant that puts the high part
[(set (match_operand:DI 0 "register_operand" "=dax") ;; into the MDRQ register, however this variant also constrains the inputs
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "dax")) ;; to be in DATA_REGS and thus isn't as helpful as it might be considering
(sign_extend:DI (match_operand:SI 2 "register_operand" "dax")))) ;; the existance of the 4-operand multiply. Nor is there a set of divide
(clobber (reg:CC CC_REG)) ;; insns that use MDRQ. Given that there is an IMM->MDRQ insn, this would
] ;; have been very handy for starting udivmodsi4...
"TARGET_AM33"
"mul %1,%2,%H0,%L0" (define_expand "mulsidi3"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") [(set (match_operand:DI 0 "register_operand" "")
(const_int 24) (const_int 23)))] (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" (define_insn "mulsidi3_internal"
[(set (match_operand:DI 0 "register_operand" "=dax") [(set (match_operand:SI 0 "register_operand" "=D,r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "dax")) (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
(zero_extend:DI (match_operand:SI 2 "register_operand" "dax")))) (match_operand:SI 3 "register_operand" " D,r")))
(clobber (reg:CC CC_REG)) (set (match_operand:SI 1 "register_operand" "=z,r")
] (truncate:SI
"TARGET_AM33" (ashiftrt:DI
"mulu %1,%2,%H0,%L0" (mult:DI (sign_extend:DI (match_dup 2))
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (sign_extend:DI (match_dup 3)))
(const_int 24) (const_int 23)))] (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" (define_expand "umulsidi3"
[(parallel [(set (match_operand:SI 0 "register_operand") [(set (match_operand:DI 0 "register_operand" "")
(mult:SI (match_operand:SI 1 "register_operand") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
(match_operand:SI 2 "register_operand"))) (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))
(clobber (reg:CC CC_REG)) (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" (define_insn "umulsidi3_internal"
[(set (match_operand:SI 0 "register_operand" "=dx,!dax") [(set (match_operand:SI 0 "register_operand" "=D,r")
(mult:SI (match_operand:SI 1 "register_operand" "%0,0") (mult:SI (match_operand:SI 2 "register_operand" "%0,r")
(match_operand:SI 2 "nonmemory_operand" "dx,daxi"))) (match_operand:SI 3 "register_operand" " D,r")))
(clobber (reg:CC CC_REG)) (set (match_operand:SI 1 "register_operand" "=z,r")
] (truncate:SI
"TARGET_AM33" (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) if (which_alternative == 1)
return \"nop\;nop\;mul %2,%0\"; return "mulu %2,%3,%1,%0";
else if (TARGET_MULT_BUG)
return "nop\;nop\;mulu %3,%0";
else else
return \"mul %2,%0\"; return "mulu %3,%0";
}" }
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))] [(set_attr "isa" "*,am33")
(set (attr "timings")
(if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
) )
(define_insn "*mn10300_mulsi3" (define_expand "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=dx") [(parallel [(set (match_operand:SI 0 "register_operand" "")
(mult:SI (match_operand:SI 1 "register_operand" "%0") (mult:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "dx"))) (match_operand:SI 2 "nonmemory_operand" "")))
(clobber (reg:CC CC_REG)) (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. (define_insn "*mulsi3"
;; ??? To be fixed by exposing the MDR register properly. [(set (match_operand:SI 0 "register_operand" "=D, r,r")
(define_insn "udivmodsi4" (mult:SI (match_operand:SI 2 "register_operand" "%0, 0,r")
[(set (match_operand:SI 0 "register_operand" "=D") (match_operand:SI 3 "nonmemory_operand" " D,ri,r")))
(udiv:SI (match_operand:SI 1 "register_operand" "0") (clobber (match_scratch:SI 1 "=z, z,r"))
(match_operand:SI 2 "register_operand" "D")))
(set (match_operand:SI 3 "register_operand" "=&d")
(umod:SI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REG))] (clobber (reg:CC CC_REG))]
"TARGET_AM33" ""
{ {
output_asm_insn ("clr %3\;ext %3", operands); if (which_alternative == 2)
if (find_reg_note (insn, REG_UNUSED, operands[3])) return "mul %2,%3,%1,%0";
return "divu %2,%0"; else if (TARGET_MULT_BUG)
return "nop\;nop\;mul %3,%0";
else else
return "divu %2,%0\;mov mdr,%3"; return "mul %3,%0";
} }
;; Timings: AM33 AM34 [(set_attr "isa" "*,am33,am33")
;; SUB 1/1 1/1 (set (attr "timings")
;; MOV 1/1 1/1 (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
;; 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)))]
) )
;; ??? In the meantime MN103 can use these two patterns, (define_expand "udivmodsi4"
;; which reduce the register pressure by one. [(parallel [(set (match_operand:SI 0 "register_operand")
(define_insn "udivsi3" (udiv:SI (match_operand:SI 1 "register_operand")
[(set (match_operand:SI 0 "register_operand" "=&d") (match_operand:SI 2 "register_operand")))
(udiv:SI (match_operand:SI 1 "register_operand" "d") (set (match_operand:SI 3 "register_operand")
(match_operand:SI 2 "register_operand" "d"))) (umod:SI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REG))] (use (const_int 0))
"!TARGET_AM33" (clobber (reg:CC CC_REG))])]
"clr %0\;ext %0\;mov %1,%0\;divu %2,%0" ""
[(set_attr "timings" "4142")]
) )
(define_insn "umodsi3" ;; Note the trick to get reload to put the zero into the MDR register,
[(set (match_operand:SI 0 "register_operand" "=&d") ;; rather than exposing the load early and letting CSE or someone try
(umod:SI (match_operand:SI 1 "register_operand" "d") ;; to share the zeros between division insns. Which tends to result
(match_operand:SI 2 "register_operand" "d"))) ;; 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))] (clobber (reg:CC CC_REG))]
"!TARGET_AM33" ""
"clr %0\;ext %0\;mov %1,%0\;divu %2,%0\;mov mdr,%0" "divu %3,%0"
[(set_attr "timings" "4142")] [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 3839) (const_int 4243)))]
) )
(define_insn "divmodsi4" (define_expand "divmodsi4"
[(set (match_operand:SI 0 "register_operand" "=dx") [(parallel [(set (match_operand:SI 0 "register_operand" "")
(div:SI (match_operand:SI 1 "register_operand" "0") (div:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "dx"))) (match_operand:SI 2 "register_operand" "")))
(set (match_operand:SI 3 "register_operand" "=d") (set (match_operand:SI 3 "register_operand" "")
(mod:SI (match_dup 1) (match_dup 2))) (mod:SI (match_dup 1) (match_dup 2)))
(clobber (reg:CC CC_REG)) (use (match_dup 4))
] (clobber (reg:CC CC_REG))])]
"" ""
"*
{ {
if (find_reg_note (insn, REG_UNUSED, operands[3])) operands[4] = gen_reg_rtx (SImode);
return \"ext %0\;div %2,%0\"; emit_insn (gen_ext_internal (operands[4], operands[1]));
else })
return \"ext %0\;div %2,%0\;mov mdr,%3\";
}" ;; ??? Ideally we'd represent this via shift, but it seems like adding a
;; Timings: AM33 AM34 ;; special-case pattern for (ashiftrt x 31) is just as likely to result
;; EXT 1/1 1/1 ;; in poor register allocation choices.
;; DIV 38/39 42/43 (define_insn "ext_internal"
;; -------------------- [(set (match_operand:SI 0 "register_operand" "=z")
;; total 39/40 43/44 (worst case sceanario) (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") [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 4344) (const_int 3940)))] (const_int 3839) (const_int 4243)))]
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment