diff options
Diffstat (limited to 'gcc/config/mips/mips.md')
-rw-r--r-- | gcc/config/mips/mips.md | 562 |
1 files changed, 421 insertions, 141 deletions
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 18d4a76c303..6dde18bf372 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -3,7 +3,7 @@ ;; Changes by Michael Meissner, meissner@osf.org ;; 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and ;; Brendan Eich, brendan@microunity.com. -;; Copyright (C) 1989, 90-97, 1998 Free Software Foundation, Inc. +;; Copyright (C) 1989, 90-98, 1999 Free Software Foundation, Inc. ;; This file is part of GNU CC. @@ -1735,7 +1735,7 @@ && !TARGET_MIPS16" "* { - static char *const madd[] = { \"madd\\t%1,%2\", \"madd\\t%0,%1,%2\" }; + static const char *const madd[] = { \"madd\\t%1,%2\", \"madd\\t%0,%1,%2\" }; if (which_alternative == 2) return \"#\"; return madd[which_alternative]; @@ -2228,7 +2228,7 @@ ;; a divide by power of 2 with a shift, and then the remainder is no longer ;; available. -(define_insn "divmodsi4" +(define_expand "divmodsi4" [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) @@ -2239,21 +2239,44 @@ (clobber (match_scratch:SI 5 "=h")) (clobber (match_scratch:SI 6 "=a"))] "optimize" - "* + " { - if (find_reg_note (insn, REG_UNUSED, operands[3])) - return \"div\\t%0,%1,%2\"; - - if (find_reg_note (insn, REG_UNUSED, operands[0])) - return \"rem\\t%3,%1,%2\"; + emit_insn (gen_divmodsi4_internal (operands[0], operands[1], operands[2], + operands[3])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + if (TARGET_CHECK_RANGE_DIV) + { + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (SImode, GEN_INT (-1)), + GEN_INT (0x6))); + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (SImode, GEN_INT (0x80000000)), + GEN_INT (0x6))); + } + + DONE; +}") - return \"div\\t%0,%1,%2\;mfhi\\t%3\"; -}" +(define_insn "divmodsi4_internal" + [(set (match_operand:SI 0 "register_operand" "=l") + (div:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d"))) + (set (match_operand:SI 3 "register_operand" "=h") + (mod:SI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:SI 6 "=a"))] + "optimize" + "div\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "14")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) -(define_insn "divmoddi4" +(define_expand "divmoddi4" [(set (match_operand:DI 0 "register_operand" "=d") (div:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) @@ -2264,21 +2287,44 @@ (clobber (match_scratch:DI 5 "=h")) (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && optimize" - "* + " { - if (find_reg_note (insn, REG_UNUSED, operands[3])) - return \"ddiv\\t%0,%1,%2\"; - - if (find_reg_note (insn, REG_UNUSED, operands[0])) - return \"drem\\t%3,%1,%2\"; + emit_insn (gen_divmoddi4_internal (operands[0], operands[1], operands[2], + operands[3])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + if (TARGET_CHECK_RANGE_DIV) + { + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (DImode, GEN_INT (-1)), + GEN_INT (0x6))); + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (DImode, GEN_INT (0x80000000)), + GEN_INT (0x6))); + } + + DONE; +}") - return \"ddiv\\t%0,%1,%2\;mfhi\\t%3\"; -}" +(define_insn "divmoddi4_internal" + [(set (match_operand:DI 0 "register_operand" "=l") + (div:DI (match_operand:DI 1 "se_register_operand" "d") + (match_operand:DI 2 "se_register_operand" "d"))) + (set (match_operand:DI 3 "register_operand" "=h") + (mod:DI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:DI 6 "=a"))] + "TARGET_64BIT && optimize" + "ddiv\\t$0,%1,%2" [(set_attr "type" "idiv") - (set_attr "mode" "DI") - (set_attr "length" "15")]) ;; various tests for dividing by 0 and such + (set_attr "mode" "SI") + (set_attr "length" "1")]) -(define_insn "udivmodsi4" +(define_expand "udivmodsi4" [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) @@ -2289,21 +2335,35 @@ (clobber (match_scratch:SI 5 "=h")) (clobber (match_scratch:SI 6 "=a"))] "optimize" - "* + " { - if (find_reg_note (insn, REG_UNUSED, operands[3])) - return \"divu\\t%0,%1,%2\"; - - if (find_reg_note (insn, REG_UNUSED, operands[0])) - return \"remu\\t%3,%1,%2\"; + emit_insn (gen_udivmodsi4_internal (operands[0], operands[1], operands[2], + operands[3])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + + DONE; +}") - return \"divu\\t%0,%1,%2\;mfhi\\t%3\"; -}" +(define_insn "udivmodsi4_internal" + [(set (match_operand:SI 0 "register_operand" "=l") + (udiv:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d"))) + (set (match_operand:SI 3 "register_operand" "=h") + (umod:SI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:SI 6 "=a"))] + "optimize" + "divu\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "8")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) -(define_insn "udivmoddi4" +(define_expand "udivmoddi4" [(set (match_operand:DI 0 "register_operand" "=d") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) @@ -2314,220 +2374,418 @@ (clobber (match_scratch:DI 5 "=h")) (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && optimize" + " +{ + emit_insn (gen_udivmoddi4_internal (operands[0], operands[1], operands[2], + operands[3])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + + DONE; +}") + +(define_insn "udivmoddi4_internal" + [(set (match_operand:DI 0 "register_operand" "=l") + (udiv:DI (match_operand:DI 1 "se_register_operand" "d") + (match_operand:DI 2 "se_register_operand" "d"))) + (set (match_operand:DI 3 "register_operand" "=h") + (umod:DI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:DI 6 "=a"))] + "TARGET_64BIT && optimize" + "ddivu\\t$0,%1,%2" + [(set_attr "type" "idiv") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +;; Division trap + +(define_expand "div_trap" + [(trap_if (eq (match_operand 0 "register_operand" "d") + (match_operand 1 "true_reg_or_0_operand" "dJ")) + (match_operand 2 "immediate_operand" ""))] + "" + " +{ + if (TARGET_MIPS16) + emit_insn (gen_div_trap_mips16 (operands[0],operands[1],operands[2])); + else + emit_insn (gen_div_trap_normal (operands[0],operands[1],operands[2])); + DONE; +}") + +(define_insn "div_trap_normal" + [(trap_if (eq (match_operand 0 "register_operand" "d") + (match_operand 1 "true_reg_or_0_operand" "dJ")) + (match_operand 2 "immediate_operand" ""))] + "!TARGET_MIPS16" "* { - if (find_reg_note (insn, REG_UNUSED, operands[3])) - return \"ddivu\\t%0,%1,%2\"; + rtx link; + int have_dep_anti = 0; - if (find_reg_note (insn, REG_UNUSED, operands[0])) - return \"dremu\\t%3,%1,%2\"; + /* For divmod if one division is not needed then we don't need an extra + divide by zero trap, which is anti dependent on previous trap */ + for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) - return \"ddivu\\t%0,%1,%2\;mfhi\\t%3\"; + if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link) + && GET_CODE (XEXP (link, 0)) == INSN + && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF + && REGNO (operands[1]) == 0) + have_dep_anti = 1; + if (! have_dep_anti) + { + if (GENERATE_BRANCHLIKELY) + { + if (GET_CODE (operands[1]) == CONST_INT) + return \"%(beql\\t%0,$0,1f\\n\\tbreak\\t%2\\n1:%)\"; + else + return \"%(beql\\t%0,%1,1f\\n\\tbreak\\t%2\\n1:%)\"; + } + else + { + if (GET_CODE (operands[1]) == CONST_INT) + return \"%(bne\\t%0,$0,1f\\n\\tnop\\n\\tbreak\\t%2\\n1:%)\"; + else + return \"%(bne\\t%0,%1,1f\\n\\tnop\\n\\tbreak\\t%2\\n1:%)\"; + } + } + return \"\"; }" - [(set_attr "type" "idiv") - (set_attr "mode" "DI") - (set_attr "length" "8")]) ;; various tests for dividing by 0 and such + [(set_attr "type" "unknown") + (set_attr "length" "3")]) + + +;; The mips16 bne insns is a macro which uses reg 24 as an intermediate. + +(define_insn "div_trap_mips16" + [(trap_if (eq (match_operand 0 "register_operand" "d") + (match_operand 1 "true_reg_or_0_operand" "dJ")) + (match_operand 2 "immediate_operand" "")) + (clobber (reg:SI 24))] + "TARGET_MIPS16" + "* +{ + rtx link; + int have_dep_anti = 0; + + /* For divmod if one division is not needed then we don't need an extra + divide by zero trap, which is anti dependent on previous trap */ + for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) + + if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link) + && GET_CODE (XEXP (link, 0)) == INSN + && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF + && REGNO (operands[1]) == 0) + have_dep_anti = 1; + if (! have_dep_anti) + { + /* No branch delay slots on mips16. */ + if (GET_CODE (operands[1]) == CONST_INT) + return \"%(bnez\\t%0,1f\\n\\tbreak\\t%2\\n1:%)\"; + else + return \"%(bne\\t%0,%1,1f\\n\\tbreak\\t%2\\n1:%)\"; + } + return \"\"; +}" + [(set_attr "type" "unknown") + (set_attr "length" "3")]) (define_expand "divsi3" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=l") (div:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di"))) - (clobber (match_scratch:SI 3 "=l")) - (clobber (match_scratch:SI 4 "=h")) - (clobber (match_scratch:SI 6 "=a"))] + (match_operand:SI 2 "register_operand" "d"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "!optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (SImode, operands[2]); + emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + if (TARGET_CHECK_RANGE_DIV) + { + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (SImode, GEN_INT (-1)), + GEN_INT (0x6))); + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (SImode, GEN_INT (0x80000000)), + GEN_INT (0x6))); + } + + DONE; }") (define_insn "divsi3_internal" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=l") (div:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di")))] + (match_operand:SI 2 "nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "!optimize" - "div\\t%0,%1,%2" + "div\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "13")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "divdi3" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=l") (div:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di"))) - (clobber (match_scratch:DI 3 "=l")) - (clobber (match_scratch:DI 4 "=h")) - (clobber (match_scratch:DI 6 "=a"))] + (match_operand:DI 2 "se_register_operand" "d"))) + (clobber (match_scratch:DI 3 "=h")) + (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (DImode, operands[2]); + emit_insn (gen_divdi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + if (TARGET_CHECK_RANGE_DIV) + { + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (DImode, GEN_INT (-1)), + GEN_INT (0x6))); + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (DImode, GEN_INT (0x80000000)), + GEN_INT (0x6))); + } + + DONE; }") (define_insn "divdi3_internal" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=l") (div:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di")))] + (match_operand:DI 2 "se_nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" - "ddiv\\t%0,%1,%2" + "ddiv\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI") - (set_attr "length" "14")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "modsi3" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=h") (mod:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di"))) + (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SI 3 "=l")) - (clobber (match_scratch:SI 4 "=h")) - (clobber (match_scratch:SI 6 "=a"))] + (clobber (match_scratch:SI 4 "=a"))] "!optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (SImode, operands[2]); + emit_insn (gen_modsi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + if (TARGET_CHECK_RANGE_DIV) + { + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (SImode, GEN_INT (-1)), + GEN_INT (0x6))); + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (SImode, GEN_INT (0x80000000)), + GEN_INT (0x6))); + } + + DONE; }") (define_insn "modsi3_internal" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=h") (mod:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di")))] + (match_operand:SI 2 "nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] "!optimize" - "rem\\t%0,%1,%2" + "div\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "13")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "moddi3" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=h") (mod:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di"))) + (match_operand:DI 2 "se_register_operand" "d"))) (clobber (match_scratch:DI 3 "=l")) - (clobber (match_scratch:DI 4 "=h")) - (clobber (match_scratch:DI 6 "=a"))] + (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (DImode, operands[2]); + emit_insn (gen_moddi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + if (TARGET_CHECK_RANGE_DIV) + { + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (DImode, GEN_INT (-1)), + GEN_INT (0x6))); + emit_insn (gen_div_trap (operands[2], + copy_to_mode_reg (DImode, GEN_INT (0x80000000)), + GEN_INT (0x6))); + } + + DONE; }") (define_insn "moddi3_internal" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=h") (mod:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di")))] + (match_operand:DI 2 "se_nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" - "drem\\t%0,%1,%2" + "ddiv\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI") - (set_attr "length" "14")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "udivsi3" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=l") (udiv:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di"))) - (clobber (match_scratch:SI 3 "=l")) - (clobber (match_scratch:SI 4 "=h")) - (clobber (match_scratch:SI 6 "=a"))] + (match_operand:SI 2 "register_operand" "d"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "!optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (SImode, operands[2]); + emit_insn (gen_udivsi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + + DONE; }") (define_insn "udivsi3_internal" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=l") (udiv:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di")))] + (match_operand:SI 2 "nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "!optimize" - "divu\\t%0,%1,%2" + "divu\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "7")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "udivdi3" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=l") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di"))) - (clobber (match_scratch:DI 3 "=l")) - (clobber (match_scratch:DI 4 "=h")) - (clobber (match_scratch:DI 6 "=a"))] + (match_operand:DI 2 "se_register_operand" "di"))) + (clobber (match_scratch:DI 3 "=h")) + (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (DImode, operands[2]); + emit_insn (gen_udivdi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + + DONE; }") (define_insn "udivdi3_internal" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=l") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di")))] + (match_operand:DI 2 "se_nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" - "ddivu\\t%0,%1,%2" + "ddivu\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI") - (set_attr "length" "7")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "umodsi3" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=h") (umod:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di"))) + (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SI 3 "=l")) - (clobber (match_scratch:SI 4 "=h")) - (clobber (match_scratch:SI 6 "=a"))] + (clobber (match_scratch:SI 4 "=a"))] "!optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (SImode, operands[2]); + emit_insn (gen_umodsi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + + DONE; }") (define_insn "umodsi3_internal" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=h") (umod:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "nonmemory_operand" "di")))] + (match_operand:SI 2 "nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] "!optimize" - "remu\\t%0,%1,%2" + "divu\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "7")]) ;; various tests for dividing by 0 and such + (set_attr "length" "1")]) (define_expand "umoddi3" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=h") (umod:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di"))) + (match_operand:DI 2 "se_register_operand" "di"))) (clobber (match_scratch:DI 3 "=l")) - (clobber (match_scratch:DI 4 "=h")) - (clobber (match_scratch:DI 6 "=a"))] + (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { - /* MIPS16 needs div/rem ops in registers. */ - if (TARGET_MIPS16) - operands[2] = force_reg (DImode, operands[2]); + emit_insn (gen_umoddi3_internal (operands[0], operands[1], operands[2])); + if (!TARGET_NO_CHECK_ZERO_DIV) + { + emit_insn (gen_div_trap (operands[2], + GEN_INT (0), + GEN_INT (0x7))); + } + + DONE; }") (define_insn "umoddi3_internal" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=h") (umod:DI (match_operand:DI 1 "se_register_operand" "d") - (match_operand:DI 2 "se_nonmemory_operand" "di")))] + (match_operand:DI 2 "se_nonmemory_operand" "di"))) + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" - "dremu\\t%0,%1,%2" + "ddivu\\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI") - (set_attr "length" "7")]) ;; various tests for dividing by 0 and such - + (set_attr "length" "1")]) ;; ;; .................... @@ -4382,7 +4640,7 @@ move\\t%0,%z4\\n\\ rtx offset = const0_rtx; rtx addr = XEXP (operands[1], 0); rtx mem_addr = eliminate_constant_term (addr, &offset); - char *ret; + const char *ret; if (TARGET_STATS) mips_count_memory_refs (operands[1], 2); @@ -4441,7 +4699,7 @@ move\\t%0,%z4\\n\\ rtx offset = const0_rtx; rtx addr = XEXP (operands[1], 0); rtx mem_addr = eliminate_constant_term (addr, &offset); - char *ret; + const char *ret; if (TARGET_STATS) mips_count_memory_refs (operands[1], 2); @@ -4803,6 +5061,7 @@ move\\t%0,%z4\\n\\ emit_move_insn (gen_rtx (REG, SImode, 64), scratch); emit_move_insn (scratch, loword); emit_move_insn (gen_rtx (REG, SImode, 65), scratch); + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); } else { @@ -4811,6 +5070,7 @@ move\\t%0,%z4\\n\\ emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32))); emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32))); emit_insn (gen_movdi (gen_rtx (REG, DImode, 65), scratch)); + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); } DONE; } @@ -4822,6 +5082,7 @@ move\\t%0,%z4\\n\\ emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 64))); emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32))); emit_insn (gen_iordi3 (operands[0], operands[0], scratch)); + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); DONE; } /* This handles moves between a float register and HI/LO. */ @@ -4851,6 +5112,7 @@ move\\t%0,%z4\\n\\ emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32))); emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32))); emit_insn (gen_movdi (gen_rtx (REG, DImode, 65), scratch)); + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); DONE; } if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM) @@ -4879,6 +5141,7 @@ move\\t%0,%z4\\n\\ emit_move_insn (hiword, scratch); emit_move_insn (scratch, gen_rtx (REG, SImode, 65)); emit_move_insn (loword, scratch); + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); } else if (TARGET_MIPS16 && ! M16_REG_P (REGNO (operands[0]))) { @@ -4893,6 +5156,7 @@ move\\t%0,%z4\\n\\ emit_insn (gen_ashldi3 (scratch2, scratch2, GEN_INT (32))); emit_insn (gen_iordi3 (scratch, scratch, scratch2)); emit_insn (gen_movdi (operands[0], scratch)); + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); } else { @@ -4902,6 +5166,7 @@ move\\t%0,%z4\\n\\ emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 64))); emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32))); emit_insn (gen_iordi3 (operands[0], operands[0], scratch)); + emit_insn (gen_rtx_USE (VOIDmode, operands[1])); } DONE; } @@ -5225,6 +5490,7 @@ move\\t%0,%z4\\n\\ emit_insn (gen_movsi (gen_rtx (REG, SImode, 65), operands[1])); emit_insn (gen_ashrsi3 (operands[2], operands[1], GEN_INT (31))); emit_insn (gen_movsi (gen_rtx (REG, SImode, 64), operands[2])); + emit_insn (gen_rtx_USE (VOIDmode, operands[0])); DONE; } /* Use a mult to reload LO on mips16. ??? This is hideous. */ @@ -8761,7 +9027,7 @@ move\\t%0,%z4\\n\\ /* ??? I don't know why this is necessary. This works around an assembler problem that appears when a label is defined, then referenced in a switch table, then used in a `j' instruction. */ - else if (mips_abi != ABI_32) + else if (mips_abi != ABI_32 && mips_abi != ABI_O64) return \"%*b\\t%l0\"; else return \"%*j\\t%l0\"; @@ -8952,7 +9218,7 @@ move\\t%0,%z4\\n\\ "* { /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */ - if (mips_abi == ABI_32) + if (mips_abi == ABI_32 || mips_abi == ABI_O64) output_asm_insn (\".cpadd\\t%0\", operands); return \"%*j\\t%0\"; }" @@ -9537,7 +9803,8 @@ move\\t%0,%z4\\n\\ (call (mem:SI (match_operand:SI 1 "register_operand" "r")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS" + "!TARGET_MIPS16 + && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS" "%*jal\\t%3,%1" [(set_attr "type" "call") (set_attr "mode" "none") @@ -9548,7 +9815,20 @@ move\\t%0,%z4\\n\\ (call (mem:DI (match_operand:DI 1 "se_register_operand" "r")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "Pmode == DImode && !TARGET_ABICALLS && TARGET_LONG_CALLS" + "!TARGET_MIPS16 + && Pmode == DImode && !TARGET_ABICALLS && TARGET_LONG_CALLS" + "%*jal\\t%3,%1" + [(set_attr "type" "call") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +(define_insn "call_value_internal3c" + [(set (match_operand 0 "register_operand" "=df") + (call (mem:SI (match_operand:SI 1 "register_operand" "e")) + (match_operand 2 "" "i"))) + (clobber (match_operand:SI 3 "register_operand" "=y"))] + "TARGET_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS + && GET_CODE (operands[3]) == REG && REGNO (operands[3]) == 31" "%*jal\\t%3,%1" [(set_attr "type" "call") (set_attr "mode" "none") |