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:
parent
c25a21f581
commit
9efb4993cb
@ -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.
|
||||
|
@ -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)))]
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user