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
This commit is contained in:
Richard Henderson 2011-01-19 09:27:58 -08:00 committed by Richard Henderson
parent c25a21f581
commit 9efb4993cb
2 changed files with 179 additions and 126 deletions

View 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.

View File

@ -38,6 +38,7 @@
(UNSPEC_PLT 4)
(UNSPEC_GOTSYM_OFF 5)
(UNSPEC_EXT 6)
(UNSPEC_BSCH 7)
])
@ -167,6 +168,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
@ -748,148 +751,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 "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_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_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 "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 (which_alternative == 1)
return "mulu %2,%3,%1,%0";
else if (TARGET_MULT_BUG)
return "nop\;nop\;mulu %3,%0";
else
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_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))
])
]
[(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))])]
""
"")
(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"
"*
{
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)))]
)
(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))
]
""
"*
{
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_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")))
(clobber (reg:CC CC_REG))]
"!TARGET_AM33"
"clr %0\;ext %0\;mov %1,%0\;divu %2,%0\;mov mdr,%0"
[(set_attr "timings" "4142")]
)
(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 "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))])]
""
"*
{
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)
)
;; 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))]
""
"divu %3,%0"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 4344) (const_int 3940)))]
(const_int 3839) (const_int 4243)))]
)
(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))])]
""
{
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 3839) (const_int 4243)))]
)