diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6e5dc0e1c8e..e2bda22f2e4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,20 @@ 2011-01-19 Richard Henderson + * 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. diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index 5f4f17a4e95..bc68ca5d8fd 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -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)))] )