diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cb0176dbb4a..921b0ce6419 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2014-01-25 Richard Sandiford + + * config/mips/constraints.md (kl): Delete. + * config/mips/mips.md (divmod4, udivmod4): Turn into + define expands, using... + (divmod4_mips16, udivmod4_mips16): ...these new + instructions for MIPS16. + (*divmod4, *udivmod4): New patterns, taken from the + non-MIPS16 version of the old divmod4 and udivmod4. + 2014-01-25 Walter Lee * config/tilepro/tilepro.md (ctzdi2): Use register_operand diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md index 196b3e1bb02..49e48954f51 100644 --- a/gcc/config/mips/constraints.md +++ b/gcc/config/mips/constraints.md @@ -92,12 +92,6 @@ ;; but the DSP version allows any accumulator target. (define_register_constraint "ka" "ISA_HAS_DSP_MULT ? ACC_REGS : MD_REGS") -;; The register class to use for an allocatable division result. -;; MIPS16 uses M16_REGS because LO is fixed. -(define_register_constraint "kl" - "TARGET_MIPS16 ? M16_REGS : TARGET_BIG_ENDIAN ? MD1_REG : MD0_REG" - "@internal") - (define_constraint "kf" "@internal" (match_operand 0 "force_to_mem_operand")) diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index fb47a890c4c..4f643604008 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -2559,56 +2559,129 @@ ;; VR4120 errata MD(A1): signed division instructions do not work correctly ;; with negative operands. We use special libgcc functions instead. -;; +(define_expand "divmod4" + [(parallel + [(set (match_operand:GPR 0 "register_operand") + (div:GPR (match_operand:GPR 1 "register_operand") + (match_operand:GPR 2 "register_operand"))) + (set (match_operand:GPR 3 "register_operand") + (mod:GPR (match_dup 1) + (match_dup 2)))])] + "ISA_HAS_DIV && !TARGET_FIX_VR4120" +{ + if (TARGET_MIPS16) + { + rtx lo = gen_rtx_REG (mode, LO_REGNUM); + emit_insn (gen_divmod4_mips16 (operands[0], operands[1], + operands[2], operands[3], lo)); + DONE; + } +}) + +(define_insn_and_split "*divmod4" + [(set (match_operand:GPR 0 "register_operand" "=l") + (div:GPR (match_operand:GPR 1 "register_operand" "d") + (match_operand:GPR 2 "register_operand" "d"))) + (set (match_operand:GPR 3 "register_operand" "=d") + (mod:GPR (match_dup 1) + (match_dup 2)))] + "ISA_HAS_DIV && !TARGET_FIX_VR4120 && !TARGET_MIPS16" + "#" + "&& reload_completed" + [(const_int 0)] +{ + emit_insn (gen_divmod4_split (operands[3], operands[1], operands[2])); + DONE; +} + [(set_attr "type" "idiv") + (set_attr "mode" "") + (set_attr "insn_count" "2")]) + ;; Expand generates divmod instructions for individual division and modulus ;; operations. We then rely on CSE to reuse earlier divmods where possible. ;; This means that, when generating MIPS16 code, it is better not to expose ;; the fixed LO register until after CSE has finished. However, it's still ;; better to split before register allocation, so that we don't allocate ;; one of the scarce MIPS16 registers to an unused result. -(define_insn_and_split "divmod4" - [(set (match_operand:GPR 0 "register_operand" "=kl") +(define_insn_and_split "divmod4_mips16" + [(set (match_operand:GPR 0 "register_operand" "=d") (div:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) (set (match_operand:GPR 3 "register_operand" "=d") (mod:GPR (match_dup 1) - (match_dup 2)))] - "ISA_HAS_DIV && !TARGET_FIX_VR4120" + (match_dup 2))) + (clobber (match_operand:GPR 4 "lo_operand" "=l"))] + "ISA_HAS_DIV && !TARGET_FIX_VR4120 && TARGET_MIPS16" "#" - "&& ((TARGET_MIPS16 && cse_not_expected) || reload_completed)" + "&& cse_not_expected" [(const_int 0)] { emit_insn (gen_divmod4_split (operands[3], operands[1], operands[2])); - if (TARGET_MIPS16) - emit_move_insn (operands[0], gen_rtx_REG (mode, LO_REGNUM)); + emit_move_insn (operands[0], operands[4]); DONE; } [(set_attr "type" "idiv") (set_attr "mode" "") - ;; Worst case for MIPS16. (set_attr "insn_count" "3")]) -;; See the comment above "divmod4" for the MIPS16 handling. -(define_insn_and_split "udivmod4" - [(set (match_operand:GPR 0 "register_operand" "=kl") +(define_expand "udivmod4" + [(parallel + [(set (match_operand:GPR 0 "register_operand") + (udiv:GPR (match_operand:GPR 1 "register_operand") + (match_operand:GPR 2 "register_operand"))) + (set (match_operand:GPR 3 "register_operand") + (umod:GPR (match_dup 1) + (match_dup 2)))])] + "ISA_HAS_DIV && !TARGET_FIX_VR4120" +{ + if (TARGET_MIPS16) + { + rtx lo = gen_rtx_REG (mode, LO_REGNUM); + emit_insn (gen_udivmod4_mips16 (operands[0], operands[1], + operands[2], operands[3], lo)); + DONE; + } +}) + +(define_insn_and_split "*udivmod4" + [(set (match_operand:GPR 0 "register_operand" "=l") (udiv:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) (set (match_operand:GPR 3 "register_operand" "=d") (umod:GPR (match_dup 1) (match_dup 2)))] - "ISA_HAS_DIV" + "ISA_HAS_DIV && !TARGET_MIPS16" "#" - "(TARGET_MIPS16 && cse_not_expected) || reload_completed" + "reload_completed" [(const_int 0)] { emit_insn (gen_udivmod4_split (operands[3], operands[1], operands[2])); - if (TARGET_MIPS16) - emit_move_insn (operands[0], gen_rtx_REG (mode, LO_REGNUM)); DONE; } [(set_attr "type" "idiv") (set_attr "mode" "") - ;; Worst case for MIPS16. + (set_attr "insn_count" "2")]) + +;; See the comment above "divmod4_mips16" for the split timing. +(define_insn_and_split "udivmod4_mips16" + [(set (match_operand:GPR 0 "register_operand" "=d") + (udiv:GPR (match_operand:GPR 1 "register_operand" "d") + (match_operand:GPR 2 "register_operand" "d"))) + (set (match_operand:GPR 3 "register_operand" "=d") + (umod:GPR (match_dup 1) + (match_dup 2))) + (clobber (match_operand:GPR 4 "lo_operand" "=l"))] + "ISA_HAS_DIV && TARGET_MIPS16" + "#" + "cse_not_expected" + [(const_int 0)] +{ + emit_insn (gen_udivmod4_split (operands[3], operands[1], operands[2])); + emit_move_insn (operands[0], operands[4]); + DONE; +} + [(set_attr "type" "idiv") + (set_attr "mode" "") (set_attr "insn_count" "3")]) (define_expand "divmod4_split"