--- gcc/config/mips/mips.md 2018/04/24 18:22:11 1.1.1.3 +++ gcc/config/mips/mips.md 2018/04/24 18:29:52 1.1.1.4 @@ -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, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. +;; Copyright (C) 1989, 90, 91, 92, 93, 94, 95 Free Software Foundation, Inc. ;; This file is part of GNU CC. @@ -19,7 +19,17 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; ??? MIPS4 has 8 floating point condition codes. This is not supported yet. + +;; ??? MIPS4 has floating point doubleword/word load/stores that accept a +;; base+index addressing mode. There are no such load/stores for the integer +;; registers. This is not supported yet. + +;; ??? Currently does not have define_function_unit support for the R8000. +;; Must include new entries for fmadd in addition to existing entries. @@ -45,6 +55,7 @@ ;; icmp integer compare ;; fadd floating point add/subtract ;; fmul floating point multiply +;; fmadd floating point multiply-add ;; fdiv floating point divide ;; fabs floating point absolute value ;; fneg floating point negation @@ -55,7 +66,7 @@ ;; nop no operation (define_attr "type" - "unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,idiv,icmp,fadd,fmul,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop" + "unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop" (const_string "unknown")) ;; Main data type used by the insn @@ -81,7 +92,8 @@ ;; (eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R6000")) (const_string "r6000")] ;; (const_string "default")))) -(define_attr "cpu" "default,r3000,r6000,r4000,r4600" +;; ??? Fix everything that tests this attribute. +(define_attr "cpu" "default,r3000,r6000,r4000,r4600,r4650,r8000" (const (symbol_ref "mips_cpu_attr"))) ;; Attribute defining whether or not we can use the branch-likely instructions @@ -139,11 +151,11 @@ ;; Make the default case (PROCESSOR_DEFAULT) handle the worst case (define_function_unit "memory" 1 0 - (and (eq_attr "type" "load") (eq_attr "cpu" "!r3000,r4600")) + (and (eq_attr "type" "load") (eq_attr "cpu" "!r3000,r4600,r4650")) 3 0) (define_function_unit "memory" 1 0 - (and (eq_attr "type" "load") (eq_attr "cpu" "r3000,r4600")) + (and (eq_attr "type" "load") (eq_attr "cpu" "r3000,r4600,r4650")) 2 0) (define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0) @@ -155,7 +167,7 @@ 1 3) (define_function_unit "imuldiv" 1 0 - (and (eq_attr "type" "imul") (eq_attr "cpu" "!r3000,r4000,r4600")) + (and (eq_attr "type" "imul") (eq_attr "cpu" "!r3000,r4000,r4600,r4650")) 17 17) (define_function_unit "imuldiv" 1 0 @@ -167,7 +179,11 @@ 10 10) (define_function_unit "imuldiv" 1 0 - (and (eq_attr "type" "idiv") (eq_attr "cpu" "!r3000,r4000,r4600")) + (and (eq_attr "type" "imul") (eq_attr "cpu" "r4650")) + 4 4) + +(define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "idiv") (eq_attr "cpu" "!r3000,r4000,r4600,r4650")) 38 38) (define_function_unit "imuldiv" 1 0 @@ -179,6 +195,10 @@ 42 42) (define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "idiv") (eq_attr "cpu" "r4650")) + 36 36) + +(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "r4000")) 69 69) @@ -203,15 +223,15 @@ 3 0) (define_function_unit "adder" 1 1 - (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "!r3000,r4600")) + (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "!r3000,r4600,r4650")) 2 0) (define_function_unit "adder" 1 1 - (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000,r4600")) + (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000,r4600,r4650")) 1 0) (define_function_unit "mult" 1 1 - (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000,r4600"))) + (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000,r4600,r4650"))) 7 0) (define_function_unit "mult" 1 1 @@ -223,7 +243,7 @@ 5 0) (define_function_unit "mult" 1 1 - (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600"))) + (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650"))) 8 0) (define_function_unit "mult" 1 1 @@ -239,7 +259,7 @@ 6 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000,r4600"))) + (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000,r4600,r4650"))) 23 0) (define_function_unit "divide" 1 1 @@ -251,11 +271,11 @@ 15 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600"))) + (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650"))) 32 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000,r4600"))) + (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000,r4600,r4650"))) 36 0) (define_function_unit "divide" 1 1 @@ -267,23 +287,23 @@ 16 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600"))) + (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650"))) 61 0) ;;; ??? Is this number right? (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600"))) + (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650"))) 54 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600"))) + (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650"))) 31 0) ;;; ??? Is this number right? (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600"))) + (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650"))) 112 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600"))) + (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650"))) 60 0) @@ -326,7 +346,7 @@ [(set (match_operand:DF 0 "register_operand" "=f") (plus:DF (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "add.d\\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "DF") @@ -563,7 +583,7 @@ [(set (match_operand:DF 0 "register_operand" "=f") (minus:DF (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "sub.d\\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "DF") @@ -787,7 +807,7 @@ [(set (match_operand:DF 0 "register_operand" "=f") (mult:DF (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "mul.d\\t%0,%1,%2" [(set_attr "type" "fmul") (set_attr "mode" "DF") @@ -803,13 +823,48 @@ (set_attr "mode" "SF") (set_attr "length" "1")]) -(define_insn "mulsi3" - [(set (match_operand:SI 0 "register_operand" "=d") +;; ??? The R4000 (only) has a cpu bug. If a double-word shift executes while +;; a multiply is in progress, it may give an incorrect result. Avoid +;; this by keeping the mflo with the mult on the R4000. + +(define_expand "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=l") (mult:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] "" + " +{ + if (TARGET_MAD) + emit_insn (gen_mulsi3_r4650 (operands[0], operands[1], operands[2])); + else if (mips_cpu != PROCESSOR_R4000) + emit_insn (gen_mulsi3_internal (operands[0], operands[1], operands[2])); + else + emit_insn (gen_mulsi3_r4000 (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "mulsi3_internal" + [(set (match_operand:SI 0 "register_operand" "=l") + (mult:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] + "mips_cpu != PROCESSOR_R4000" + "mult\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "mulsi3_r4000" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=l")) + (clobber (match_scratch:SI 5 "=a"))] + "mips_cpu == PROCESSOR_R4000" "* { rtx xoperands[10]; @@ -825,43 +880,55 @@ (set_attr "mode" "SI") (set_attr "length" "3")]) ;; mult + mflo + delay -;; ??? The R4000 (only) has a cpu bug. If a double-word shift executes while -;; a multiply is in progress, it may give an incorrect result. We solve -;; this by not splitting on the r4000. +(define_insn "mulsi3_r4650" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d"))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=l")) + (clobber (match_scratch:SI 5 "=a"))] + "TARGET_MAD" + "mul\\t%0,%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (mult:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "register_operand" ""))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] - "!TARGET_DEBUG_D_MODE && mips_cpu != PROCESSOR_R4000" - [(parallel [(set (reg:SI 65) ;; low register - (mult:SI (match_dup 1) - (match_dup 2))) - (clobber (reg:SI 64))]) - (set (match_dup 0) - (reg:SI 65))] - "") +(define_expand "muldi3" + [(set (match_operand:DI 0 "register_operand" "=l") + (mult:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d"))) + (clobber (match_scratch:DI 3 "=h")) + (clobber (match_scratch:DI 4 "=a"))] + "TARGET_64BIT" + " +{ + if (mips_cpu != PROCESSOR_R4000) + emit_insn (gen_muldi3_internal (operands[0], operands[1], operands[2])); + else + emit_insn (gen_muldi3_r4000 (operands[0], operands[1], operands[2])); + DONE; +}") -(define_insn "mulsi3_internal" - [(set (reg:SI 65) ;; low register - (mult:SI (match_operand:SI 0 "register_operand" "d") - (match_operand:SI 1 "register_operand" "d"))) - (clobber (reg:SI 64))] - "" - "mult\\t%0,%1" +(define_insn "muldi3_internal" + [(set (match_operand:DI 0 "register_operand" "=l") + (mult:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d"))) + (clobber (match_scratch:DI 3 "=h")) + (clobber (match_scratch:DI 4 "=a"))] + "TARGET_64BIT && mips_cpu != PROCESSOR_R4000" + "dmult\\t%1,%2" [(set_attr "type" "imul") - (set_attr "mode" "SI") + (set_attr "mode" "DI") (set_attr "length" "1")]) -(define_insn "muldi3" +(define_insn "muldi3_r4000" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d"))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] - "TARGET_64BIT" + (clobber (match_scratch:DI 3 "=h")) + (clobber (match_scratch:DI 4 "=l")) + (clobber (match_scratch:DI 5 "=a"))] + "TARGET_64BIT && mips_cpu == PROCESSOR_R4000" "* { rtx xoperands[10]; @@ -877,309 +944,301 @@ (set_attr "mode" "DI") (set_attr "length" "3")]) ;; mult + mflo + delay -;; ??? The R4000 (only) has a cpu bug. If a double-word shift executes while -;; a multiply is in progress, it may give an incorrect result. We solve -;; this by not splitting on the r4000. +;; ??? We could define a mulditi3 pattern when TARGET_64BIT. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "register_operand" ""))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] - "TARGET_64BIT && !TARGET_DEBUG_D_MODE && mips_cpu != PROCESSOR_R4000" - [(parallel [(set (reg:DI 65) ;; low register - (mult:DI (match_dup 1) - (match_dup 2))) - (clobber (reg:DI 64))]) - (set (match_dup 0) - (reg:DI 65))] - "") +(define_expand "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=x") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) + (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))] + "" + " +{ + if (TARGET_64BIT) + emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2])); + else + emit_insn (gen_mulsidi3_internal (operands[0], operands[1], operands[2])); + DONE; +}") -(define_insn "muldi3_internal" - [(set (reg:DI 65) ;; low register - (mult:DI (match_operand:DI 0 "register_operand" "d") - (match_operand:DI 1 "register_operand" "d"))) - (clobber (reg:DI 64))] - "TARGET_64BIT" - "dmult\\t%0,%1" +(define_insn "mulsidi3_internal" + [(set (match_operand:DI 0 "register_operand" "=x") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) + (sign_extend:DI (match_operand:SI 2 "register_operand" "d")))) + (clobber (match_scratch:SI 3 "=a"))] + "!TARGET_64BIT" + "mult\\t%1,%2" [(set_attr "type" "imul") - (set_attr "mode" "DI") + (set_attr "mode" "SI") (set_attr "length" "1")]) -;; In 64 bit mode the mult instruction still writes 32 bits each to HI -;; and LO, so to do mulsidi3 and umultsidi3 we need to pull the values -;; out and combine them by hand into the single output register. Not -;; supported for now. - -;; ??? We could define a mulditi3 pattern when TARGET_64BIT. - -(define_insn "mulsidi3" - [(set (match_operand:DI 0 "register_operand" "=d") +(define_insn "mulsidi3_64bit" + [(set (match_operand:DI 0 "register_operand" "=a") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) (sign_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] - "!TARGET_64BIT" - "* -{ - rtx xoperands[10]; - - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, DImode, MD_REG_FIRST); - - output_asm_insn (\"mult\\t%1,%2\", operands); - output_asm_insn (mips_move_2words (xoperands, insn), xoperands); - return \"\"; -}" + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h"))] + "TARGET_64BIT" + "mult\\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") - (set_attr "length" "4")]) ;; mult + mflo + mfhi + delay + (set_attr "length" "1")]) (define_insn "smulsi3_highpart" - [(set (match_operand:SI 0 "register_operand" "=d") + [(set (match_operand:SI 0 "register_operand" "=h") (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))) (const_int 32)))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] "" - "* -{ - rtx xoperands[10]; - - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, SImode, HI_REGNUM); - - output_asm_insn (\"mult\\t%1,%2\", operands); - output_asm_insn (mips_move_1word (xoperands, insn, TRUE), xoperands); - return \"\"; -}" + "mult\\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") - (set_attr "length" "3")]) ;; mult + mfhi + delay - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (truncate:SI - (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) - (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))) - (const_int 32)))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] - "!TARGET_DEBUG_D_MODE" - [(parallel [(set (reg:SI 64) ;; high register - (truncate:SI - (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) - (sign_extend:DI (match_dup 2))) - (const_int 32)))) - (clobber (reg:SI 65))]) - (set (match_dup 0) - (reg:SI 64))] - "") + (set_attr "length" "1")]) -(define_insn "smulsi3_highpart_internal" - [(set (reg:SI 64) ;; high register - (truncate:SI - (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 0 "register_operand" "d")) - (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))) - (const_int 32)))) - (clobber (reg:SI 65))] +(define_expand "umulsidi3" + [(set (match_operand:DI 0 "register_operand" "=x") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) + (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))] "" - "mult\\t%0,%1" - [(set_attr "type" "imul") - (set_attr "mode" "SI") - (set_attr "length" "1")]) + " +{ + if (TARGET_64BIT) + emit_insn (gen_umulsidi3_64bit (operands[0], operands[1], operands[2])); + else + emit_insn (gen_umulsidi3_internal (operands[0], operands[1], operands[2])); + DONE; +}") -(define_insn "umulsidi3" - [(set (match_operand:DI 0 "register_operand" "=d") +(define_insn "umulsidi3_internal" + [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) (zero_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=a"))] "!TARGET_64BIT" - "* -{ - rtx xoperands[10]; - - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, DImode, MD_REG_FIRST); - - output_asm_insn (\"multu\\t%1,%2\", operands); - output_asm_insn (mips_move_2words (xoperands, insn), xoperands); - return \"\"; -}" + "multu\\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") - (set_attr "length" "4")]) ;; mult + mflo + mfhi + delay - -(define_insn "umulsi3_highpart" - [(set (match_operand:SI 0 "register_operand" "=d") - (truncate:SI - (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) - (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))) - (const_int 32)))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] - "" - "* -{ - rtx xoperands[10]; - - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, SImode, HI_REGNUM); + (set_attr "length" "1")]) - output_asm_insn (\"multu\\t%1,%2\", operands); - output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands); - return \"\"; -}" +(define_insn "umulsidi3_64bit" + [(set (match_operand:DI 0 "register_operand" "=a") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) + (zero_extend:DI (match_operand:SI 2 "register_operand" "d")))) + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h"))] + "TARGET_64BIT" + "multu\\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") - (set_attr "length" "3")]) ;; multu + mfhi + delay + (set_attr "length" "1")]) -(define_split - [(set (match_operand:SI 0 "register_operand" "") +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=h") (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))) (const_int 32)))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] - "!TARGET_DEBUG_D_MODE" - [(parallel [(set (reg:SI 64) ;; high register - (truncate:SI - (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) - (zero_extend:DI (match_dup 2))) - (const_int 32)))) - (clobber (reg:SI 65))]) - (set (match_dup 0) - (reg:SI 64))] - "") - -(define_insn "umulsi3_highpart_internal" - [(set (reg:SI 64) ;; high register - (truncate:SI - (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 0 "register_operand" "d")) - (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))) - (const_int 32)))) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] "" - "multu\\t%0,%1" + "multu\\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "1")]) (define_insn "smuldi3_highpart" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=h") (truncate:DI (lshiftrt:TI (mult:TI (sign_extend:TI (match_operand:DI 1 "register_operand" "d")) (sign_extend:TI (match_operand:DI 2 "register_operand" "d"))) (const_int 64)))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT" - "* -{ - rtx xoperands[10]; - - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, DImode, HI_REGNUM); - - output_asm_insn (\"dmult\\t%1,%2\", operands); - output_asm_insn (mips_move_1word (xoperands, insn, TRUE), xoperands); - return \"\"; -}" - [(set_attr "type" "imul") - (set_attr "mode" "DI") - (set_attr "length" "3")]) ;; mult + mfhi + delay - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (truncate:DI - (lshiftrt:TI (mult:TI (sign_extend:TI (match_operand:DI 1 "register_operand" "d")) - (sign_extend:TI (match_operand:DI 2 "register_operand" "d"))) - (const_int 64)))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] - "TARGET_64BIT && !TARGET_DEBUG_D_MODE" - [(parallel [(set (reg:DI 64) ;; high register - (truncate:DI - (lshiftrt:TI (mult:TI (sign_extend:TI (match_dup 1)) - (sign_extend:TI (match_dup 2))) - (const_int 64)))) - (clobber (reg:DI 65))]) - (set (match_dup 0) - (reg:DI 64))] - "") - -(define_insn "smuldi3_highpart_internal" - [(set (reg:DI 64) ;; high register - (truncate:DI - (lshiftrt:TI (mult:TI (sign_extend:TI (match_operand:DI 0 "register_operand" "d")) - (sign_extend:TI (match_operand:DI 1 "register_operand" "d"))) - (const_int 64)))) - (clobber (reg:DI 65))] - "TARGET_64BIT" - "dmult\\t%0,%1" + "dmult\\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "DI") (set_attr "length" "1")]) (define_insn "umuldi3_highpart" - [(set (match_operand:DI 0 "register_operand" "=d") + [(set (match_operand:DI 0 "register_operand" "=h") (truncate:DI (lshiftrt:TI (mult:TI (zero_extend:TI (match_operand:DI 1 "register_operand" "d")) (zero_extend:TI (match_operand:DI 2 "register_operand" "d"))) (const_int 64)))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT" - "* -{ - rtx xoperands[10]; + "dmultu\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "DI") + (set_attr "length" "1")]) - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, DImode, HI_REGNUM); +;; The R4650 supports a 32 bit multiply/ 64 bit accumulate +;; instruction. The HI/LO registers are used as a 64 bit accumulator. - output_asm_insn (\"dmultu\\t%1,%2\", operands); - output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands); - return \"\"; -}" +(define_insn "madsi" + [(set (match_operand:SI 0 "register_operand" "+l") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d")) + (match_dup 0))) + (clobber (match_scratch:SI 3 "=h")) + (clobber (match_scratch:SI 4 "=a"))] + "TARGET_MAD" + "mad\\t%1,%2" [(set_attr "type" "imul") - (set_attr "mode" "DI") - (set_attr "length" "3")]) ;; multu + mfhi + delay + (set_attr "mode" "SI") + (set_attr "length" "1")]) -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (truncate:DI - (lshiftrt:TI (mult:TI (zero_extend:TI (match_operand:DI 1 "register_operand" "d")) - (zero_extend:TI (match_operand:DI 2 "register_operand" "d"))) - (const_int 64)))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] - "TARGET_64BIT && !TARGET_DEBUG_D_MODE" - [(parallel [(set (reg:DI 64) ;; high register - (truncate:DI - (lshiftrt:TI (mult:TI (zero_extend:TI (match_dup 1)) - (zero_extend:TI (match_dup 2))) - (const_int 64)))) - (clobber (reg:DI 65))]) - (set (match_dup 0) - (reg:DI 64))] - "") +(define_insn "maddi" + [(set (match_operand:DI 0 "register_operand" "+x") + (plus:DI (mult:DI (sign_extend:DI + (match_operand:SI 1 "register_operand" "d")) + (sign_extend:DI + (match_operand:SI 2 "register_operand" "d"))) + (match_dup 0))) + (clobber (match_scratch:SI 3 "=a"))] + "TARGET_MAD && ! TARGET_64BIT" + "mad\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) -(define_insn "umuldi3_highpart_internal" - [(set (reg:DI 64) ;; high register - (truncate:DI - (lshiftrt:TI (mult:TI (zero_extend:TI (match_operand:DI 0 "register_operand" "d")) - (zero_extend:TI (match_operand:DI 1 "register_operand" "d"))) - (const_int 64)))) - (clobber (reg:DI 65))] - "TARGET_64BIT" - "dmultu\\t%0,%1" +(define_insn "maddi_64bit" + [(set (match_operand:DI 0 "register_operand" "+a") + (plus:DI (mult:DI (sign_extend:DI + (match_operand:SI 1 "register_operand" "d")) + (sign_extend:DI + (match_operand:SI 2 "register_operand" "d"))) + (match_dup 0))) + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h"))] + "TARGET_MAD && TARGET_64BIT" + "mad\\t%1,%2" [(set_attr "type" "imul") - (set_attr "mode" "DI") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "umaddi" + [(set (match_operand:DI 0 "register_operand" "+x") + (plus:DI (mult:DI (zero_extend:DI + (match_operand:SI 1 "register_operand" "d")) + (zero_extend:DI + (match_operand:SI 2 "register_operand" "d"))) + (match_dup 0))) + (clobber (match_scratch:SI 3 "=a"))] + "TARGET_MAD && ! TARGET_64BIT" + "madu\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "umaddi_64bit" + [(set (match_operand:DI 0 "register_operand" "+a") + (plus:DI (mult:DI (zero_extend:DI + (match_operand:SI 1 "register_operand" "d")) + (zero_extend:DI + (match_operand:SI 2 "register_operand" "d"))) + (match_dup 0))) + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h"))] + "TARGET_MAD && TARGET_64BIT" + "madu\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +;; Floating point multiply accumulate instructions. + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")) + (match_operand:DF 3 "register_operand" "f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "madd.d\\t%0,%3,%1,%2" + [(set_attr "type" "fmadd") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")) + (match_operand:SF 3 "register_operand" "f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "madd.s\\t%0,%3,%1,%2" + [(set_attr "type" "fmadd") + (set_attr "mode" "SF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")) + (match_operand:DF 3 "register_operand" "f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "msub.d\\t%0,%3,%1,%2" + [(set_attr "type" "fmadd") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")) + (match_operand:SF 3 "register_operand" "f")))] + + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "msub.s\\t%0,%3,%1,%2" + [(set_attr "type" "fmadd") + (set_attr "mode" "SF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")) + (match_operand:DF 3 "register_operand" "f"))))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "nmadd.d\\t%0,%3,%1,%2" + [(set_attr "type" "fmadd") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "register_operand" "f")) + (match_operand:SF 3 "register_operand" "f"))))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "nmadd.s\\t%0,%3,%1,%2" + [(set_attr "type" "fmadd") + (set_attr "mode" "SF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (mult:DF (match_operand:DF 2 "register_operand" "f") + (match_operand:DF 3 "register_operand" "f"))))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "nmsub.d\\t%0,%1,%2,%3" + [(set_attr "type" "fmadd") + (set_attr "mode" "DF") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (match_operand:SF 1 "register_operand" "f") + (mult:SF (match_operand:SF 2 "register_operand" "f") + (match_operand:SF 3 "register_operand" "f"))))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "nmsub.s\\t%0,%1,%2,%3" + [(set_attr "type" "fmadd") + (set_attr "mode" "SF") (set_attr "length" "1")]) ;; @@ -1194,7 +1253,7 @@ [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "div.d\\t%0,%1,%2" [(set_attr "type" "fdiv") (set_attr "mode" "DF") @@ -1230,8 +1289,9 @@ (set (match_operand:SI 3 "register_operand" "=d") (mod:SI (match_dup 1) (match_dup 2))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 4 "=l")) + (clobber (match_scratch:SI 5 "=h")) + (clobber (match_scratch:SI 6 "=a"))] "optimize" "* { @@ -1254,8 +1314,9 @@ (set (match_operand:DI 3 "register_operand" "=d") (mod:DI (match_dup 1) (match_dup 2))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 4 "=l")) + (clobber (match_scratch:DI 5 "=h")) + (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && optimize" "* { @@ -1278,8 +1339,9 @@ (set (match_operand:SI 3 "register_operand" "=d") (umod:SI (match_dup 1) (match_dup 2))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 4 "=l")) + (clobber (match_scratch:SI 5 "=h")) + (clobber (match_scratch:SI 6 "=a"))] "optimize" "* { @@ -1302,8 +1364,9 @@ (set (match_operand:DI 3 "register_operand" "=d") (umod:DI (match_dup 1) (match_dup 2))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 4 "=l")) + (clobber (match_scratch:DI 5 "=h")) + (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && optimize" "* { @@ -1323,8 +1386,9 @@ [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=h")) + (clobber (match_scratch:SI 6 "=a"))] "!optimize" "div\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1335,8 +1399,9 @@ [(set (match_operand:DI 0 "register_operand" "=d") (div:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "nonmemory_operand" "di"))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h")) + (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && !optimize" "ddiv\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1347,8 +1412,9 @@ [(set (match_operand:SI 0 "register_operand" "=d") (mod:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=h")) + (clobber (match_scratch:SI 6 "=a"))] "!optimize" "rem\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1359,8 +1425,9 @@ [(set (match_operand:DI 0 "register_operand" "=d") (mod:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "nonmemory_operand" "di"))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h")) + (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && !optimize" "drem\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1371,8 +1438,9 @@ [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=h")) + (clobber (match_scratch:SI 6 "=a"))] "!optimize" "divu\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1383,8 +1451,9 @@ [(set (match_operand:DI 0 "register_operand" "=d") (udiv:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "nonmemory_operand" "di"))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h")) + (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && !optimize" "ddivu\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1395,8 +1464,9 @@ [(set (match_operand:SI 0 "register_operand" "=d") (umod:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=h")) + (clobber (match_scratch:SI 6 "=a"))] "!optimize" "remu\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1407,8 +1477,9 @@ [(set (match_operand:DI 0 "register_operand" "=d") (umod:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "nonmemory_operand" "di"))) - (clobber (reg:DI 64)) - (clobber (reg:DI 65))] + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h")) + (clobber (match_scratch:DI 6 "=a"))] "TARGET_64BIT && !optimize" "dremu\\t%0,%1,%2" [(set_attr "type" "idiv") @@ -1426,7 +1497,7 @@ (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && HAVE_SQRT_P()" + "TARGET_HARD_FLOAT && HAVE_SQRT_P() && TARGET_DOUBLE_FLOAT" "sqrt.d\\t%0,%1" [(set_attr "type" "fsqrt") (set_attr "mode" "DF") @@ -1498,7 +1569,7 @@ (define_insn "absdf2" [(set (match_operand:DF 0 "register_operand" "=f") (abs:DF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "abs.d\\t%0,%1" [(set_attr "type" "fabs") (set_attr "mode" "DF") @@ -1661,7 +1732,7 @@ move\\t%0,%z4\\n\\ (define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=f") (neg:DF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "neg.d\\t%0,%1" [(set_attr "type" "fneg") (set_attr "mode" "DF") @@ -1939,17 +2010,12 @@ move\\t%0,%z4\\n\\ (define_insn "truncdfsf2" [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "cvt.s.d\\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF") (set_attr "length" "1")]) -;; ??? This should be a define expand. -;; See the zero_extendsidi2 pattern. -;; ??? We tried define expands, but they did not work. Too many shift -;; instructions were optimized away. Perhaps add combiner patterns to -;; recognize cases where shifts and truncates can be combined. (define_insn "truncdisi2" [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (match_operand:DI 1 "register_operand" "d")))] @@ -1976,6 +2042,110 @@ move\\t%0,%z4\\n\\ [(set_attr "type" "darith") (set_attr "mode" "QI") (set_attr "length" "1")]) + +;; Combiner patterns to optimize shift/truncate combinations. +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "small_int" "I"))))] + "TARGET_64BIT" + "* +{ + int shift_amt = INTVAL (operands[2]) & 0x3f; + + if (shift_amt < 32) + { + operands[2] = GEN_INT (32 - shift_amt); + return \"dsll\\t%0,%1,%2\;dsra\\t%0,%0,32\"; + } + else + { + operands[2] = GEN_INT (shift_amt); + return \"dsra\\t%0,%1,%2\"; + } +}" + [(set_attr "type" "darith") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "small_int" "I"))))] + "TARGET_64BIT" + "* +{ + int shift_amt = INTVAL (operands[2]) & 0x3f; + + if (shift_amt < 32) + { + operands[2] = GEN_INT (32 - shift_amt); + return \"dsll\\t%0,%1,%2\;dsra\\t%0,%0,32\"; + } + else if (shift_amt == 32) + return \"dsra\\t%0,%1,32\"; + else + { + operands[2] = GEN_INT (shift_amt); + return \"dsrl\\t%0,%1,%2\"; + } +}" + [(set_attr "type" "darith") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (ashift:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "small_int" "I"))))] + "TARGET_64BIT" + "* +{ + int shift_amt = INTVAL (operands[2]) & 0x3f; + + if (shift_amt < 32) + { + operands[2] = GEN_INT (32 + shift_amt); + return \"dsll\\t%0,%1,%2\;dsra\\t%0,%0,32\"; + } + else + return \"move\\t%0,%.\"; +}" + [(set_attr "type" "darith") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +;; Combiner patterns to optimize truncate/zero_extend combinations. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (zero_extend:SI (truncate:HI + (match_operand:DI 1 "register_operand" "d"))))] + "TARGET_64BIT" + "andi\\t%0,%1,0xffff" + [(set_attr "type" "darith") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (zero_extend:SI (truncate:QI + (match_operand:DI 1 "register_operand" "d"))))] + "TARGET_64BIT" + "andi\\t%0,%1,0xff" + [(set_attr "type" "darith") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=d") + (zero_extend:HI (truncate:QI + (match_operand:DI 1 "register_operand" "d"))))] + "TARGET_64BIT" + "andi\\t%0,%1,0xff" + [(set_attr "type" "darith") + (set_attr "mode" "HI") + (set_attr "length" "1")]) ;; ;; .................... @@ -2293,7 +2463,7 @@ move\\t%0,%z4\\n\\ (define_insn "extendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f") (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "cvt.d.s\\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF") @@ -2317,7 +2487,7 @@ move\\t%0,%z4\\n\\ (fix:SI (match_operand:DF 1 "register_operand" "f,*f,f,f"))) (clobber (match_scratch:SI 2 "=d,*d,&d,&d")) (clobber (match_scratch:DF 3 "=f,*X,f,f"))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -2375,7 +2545,7 @@ move\\t%0,%z4\\n\\ [(set (match_operand:DI 0 "general_operand" "=d,*f,R,o") (fix:DI (match_operand:DF 1 "register_operand" "f,*f,f,f"))) (clobber (match_scratch:DF 2 "=f,*X,f,f"))] - "TARGET_HARD_FLOAT && TARGET_64BIT" + "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -2402,7 +2572,7 @@ move\\t%0,%z4\\n\\ [(set (match_operand:DI 0 "general_operand" "=d,*f,R,o") (fix:DI (match_operand:SF 1 "register_operand" "f,*f,f,f"))) (clobber (match_scratch:DF 2 "=f,*X,f,f"))] - "TARGET_HARD_FLOAT && TARGET_64BIT" + "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -2425,7 +2595,7 @@ move\\t%0,%z4\\n\\ (define_insn "floatsidf2" [(set (match_operand:DF 0 "register_operand" "=f,f,f") (float:DF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { dslots_load_total++; @@ -2442,7 +2612,7 @@ move\\t%0,%z4\\n\\ (define_insn "floatdidf2" [(set (match_operand:DF 0 "register_operand" "=f,f,f") (float:DF (match_operand:DI 1 "nonimmediate_operand" "d,R,m")))] - "TARGET_HARD_FLOAT && TARGET_64BIT" + "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" "* { dslots_load_total++; @@ -2476,7 +2646,7 @@ move\\t%0,%z4\\n\\ (define_insn "floatdisf2" [(set (match_operand:SF 0 "register_operand" "=f,f,f") (float:SF (match_operand:DI 1 "nonimmediate_operand" "d,R,m")))] - "TARGET_HARD_FLOAT && TARGET_64BIT" + "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" "* { dslots_load_total++; @@ -2493,7 +2663,7 @@ move\\t%0,%z4\\n\\ (define_expand "fixuns_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "") (unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" " { rtx reg1 = gen_reg_rtx (DFmode); @@ -2536,7 +2706,7 @@ move\\t%0,%z4\\n\\ (define_expand "fixuns_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "") (unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))] - "TARGET_HARD_FLOAT && TARGET_64BIT" + "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" " { rtx reg1 = gen_reg_rtx (DFmode); @@ -2623,7 +2793,7 @@ move\\t%0,%z4\\n\\ (define_expand "fixuns_truncsfdi2" [(set (match_operand:DI 0 "register_operand" "") (unsigned_fix:DI (match_operand:SF 1 "register_operand" "")))] - "TARGET_HARD_FLOAT && TARGET_64BIT" + "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" " { rtx reg1 = gen_reg_rtx (SFmode); @@ -2821,6 +2991,37 @@ move\\t%0,%z4\\n\\ "" " { + /* If we are generating embedded PIC code, and we are referring to a + symbol in the .text section, we must use an offset from the start + of the function. */ + if (TARGET_EMBEDDED_PIC + && (GET_CODE (operands[1]) == LABEL_REF + || (GET_CODE (operands[1]) == SYMBOL_REF + && ! SYMBOL_REF_FLAG (operands[1])))) + { + rtx temp; + + temp = embedded_pic_offset (operands[1]); + temp = gen_rtx (PLUS, Pmode, embedded_pic_fnaddr_rtx, + force_reg (DImode, temp)); + emit_move_insn (operands[0], force_reg (DImode, temp)); + DONE; + } + + /* If operands[1] is a constant address illegal for pic, then we need to + handle it just like LEGITIMIZE_ADDRESS does. */ + if (flag_pic && pic_address_needs_scratch (operands[1])) + { + rtx temp = force_reg (DImode, XEXP (XEXP (operands[1], 0), 0)); + rtx temp2 = XEXP (XEXP (operands[1], 0), 1); + + if (! SMALL_INT (temp2)) + temp2 = force_reg (DImode, temp2); + + emit_move_insn (operands[0], gen_rtx (PLUS, DImode, temp, temp2)); + DONE; + } + if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], DImode) && !register_operand (operands[1], DImode) @@ -2858,18 +3059,149 @@ move\\t%0,%z4\\n\\ "") (define_insn "movdi_internal2" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*x") - (match_operand:DI 1 "general_operand" " d,S,IKL,Mnis,R,m,dJ,dJ,*x,*d"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*x,*a") + (match_operand:DI 1 "general_operand" " d,S,IKL,Mnis,R,m,dJ,dJ,*x,*d,*I"))] "TARGET_64BIT && (register_operand (operands[0], DImode) || register_operand (operands[1], DImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) || operands[1] == CONST0_RTX (DImode))" "* return mips_move_2words (operands, insn); " - [(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo") + [(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo,hilo") (set_attr "mode" "DI") - (set_attr "length" "1,2,1,2,1,2,1,2,1,1")]) + (set_attr "length" "1,2,1,2,1,2,1,2,1,1,2")]) +;; Handle input reloads in DImode. +;; This is mainly to handle reloading HILO_REGNUM. Note that we may +;; see it as the source or the destination, depending upon which way +;; reload handles the instruction. +;; Making the second operand TImode is a trick. The compiler may +;; reuse the same register for operand 0 and operand 2. Using TImode +;; gives us two registers, so we can always use the one which is not +;; used. + +(define_expand "reload_indi" + [(set (match_operand:DI 0 "register_operand" "=b") + (match_operand:DI 1 "general_operand" "b")) + (clobber (match_operand:TI 2 "register_operand" "=&d"))] + "TARGET_64BIT" + " +{ + rtx scratch = gen_rtx (REG, DImode, + (REGNO (operands[0]) == REGNO (operands[2]) + ? REGNO (operands[2]) + 1 + : REGNO (operands[2]))); + + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM) + { + if (GET_CODE (operands[1]) == MEM) + { + rtx memword, offword, hiword, loword; + + scratch = gen_rtx (REG, SImode, REGNO (scratch)); + memword = change_address (operands[1], SImode, NULL_RTX); + offword = change_address (adj_offsettable_operand (operands[1], 4), + SImode, NULL_RTX); + if (BYTES_BIG_ENDIAN) + { + hiword = memword; + loword = offword; + } + else + { + hiword = offword; + loword = memword; + } + emit_move_insn (scratch, hiword); + emit_move_insn (gen_rtx (REG, SImode, 64), scratch); + emit_move_insn (scratch, loword); + emit_move_insn (gen_rtx (REG, SImode, 65), scratch); + } + else + { + emit_insn (gen_ashrdi3 (scratch, operands[1], GEN_INT (32))); + emit_insn (gen_movdi (gen_rtx (REG, DImode, 64), scratch)); + 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)); + } + DONE; + } + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM) + { + emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 65))); + emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32))); + emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32))); + 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)); + DONE; + } + /* This handles moves between a float register and HI/LO. */ + emit_move_insn (scratch, operands[1]); + emit_move_insn (operands[0], scratch); + DONE; +}") + +;; Handle output reloads in DImode. + +(define_expand "reload_outdi" + [(set (match_operand:DI 0 "general_operand" "=b") + (match_operand:DI 1 "register_operand" "b")) + (clobber (match_operand:DI 2 "register_operand" "=&d"))] + "TARGET_64BIT" + " +{ + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM) + { + emit_insn (gen_ashrdi3 (operands[2], operands[1], GEN_INT (32))); + emit_insn (gen_movdi (gen_rtx (REG, DImode, 64), operands[2])); + emit_insn (gen_ashldi3 (operands[2], operands[1], GEN_INT (32))); + emit_insn (gen_ashrdi3 (operands[2], operands[2], GEN_INT (32))); + emit_insn (gen_movdi (gen_rtx (REG, DImode, 65), operands[2])); + DONE; + } + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM) + { + if (GET_CODE (operands[0]) == MEM) + { + rtx scratch, memword, offword, hiword, loword; + + scratch = gen_rtx (REG, SImode, REGNO (operands[2])); + memword = change_address (operands[0], SImode, NULL_RTX); + offword = change_address (adj_offsettable_operand (operands[0], 4), + SImode, NULL_RTX); + if (BYTES_BIG_ENDIAN) + { + hiword = memword; + loword = offword; + } + else + { + hiword = offword; + loword = memword; + } + emit_move_insn (scratch, gen_rtx (REG, SImode, 64)); + emit_move_insn (hiword, scratch); + emit_move_insn (scratch, gen_rtx (REG, SImode, 65)); + emit_move_insn (loword, scratch); + } + else + { + emit_insn (gen_movdi (operands[2], gen_rtx (REG, DImode, 65))); + emit_insn (gen_ashldi3 (operands[2], operands[2], GEN_INT (32))); + emit_insn (gen_lshrdi3 (operands[2], operands[2], GEN_INT (32))); + 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], operands[2])); + } + DONE; + } + /* This handles moves between a float register and HI/LO. */ + emit_move_insn (operands[2], operands[1]); + emit_move_insn (operands[0], operands[2]); + DONE; +}") ;; 32-bit Integer moves @@ -2915,7 +3247,7 @@ move\\t%0,%z4\\n\\ DONE; } - /* If operands[1] is a constant address illegal for pic, then we need to + /* If operands[1] is a constant address invalid for pic, then we need to handle it just like LEGITIMIZE_ADDRESS does. */ if (flag_pic && pic_address_needs_scratch (operands[1])) { @@ -2944,29 +3276,51 @@ move\\t%0,%z4\\n\\ ;; in FP registers (off by default, use -mdebugh to enable). (define_insn "movsi_internal1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*d") - (match_operand:SI 1 "general_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,*d,*x"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d") + (match_operand:SI 1 "general_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,I,*d,*x,*a"))] "TARGET_DEBUG_H_MODE && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" "* return mips_move_1word (operands, insn, FALSE);" - [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo") + [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo,hilo,hilo") (set_attr "mode" "SI") - (set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,1,2,1,2,1,1")]) + (set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,1,2,1,2,1,1,1,1")]) (define_insn "movsi_internal2" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*d,*x") - (match_operand:SI 1 "general_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,*x,*d"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d") + (match_operand:SI 1 "general_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,I,*x,*d,*a"))] "!TARGET_DEBUG_H_MODE && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" "* return mips_move_1word (operands, insn, FALSE);" - [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo") + [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo") (set_attr "mode" "SI") - (set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,1")]) + (set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,1,1,1")]) +;; Reload HILO_REGNUM in SI mode. This needs a scratch register in +;; order to set the sign bit correctly in the HI register. + +(define_expand "reload_outsi" + [(set (match_operand:SI 0 "general_operand" "=b") + (match_operand:SI 1 "register_operand" "d")) + (clobber (match_operand:SI 2 "register_operand" "=&d"))] + "TARGET_64BIT" + " +{ + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM) + { + 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])); + DONE; + } + /* This handles moves between a float register and HI/LO. */ + emit_move_insn (operands[2], operands[1]); + emit_move_insn (operands[0], operands[2]); + DONE; +}") ;; 16-bit Integer moves @@ -3144,6 +3498,7 @@ move\\t%0,%z4\\n\\ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,o,f,*f,*d,*d,*d,*d,*R,*o") (match_operand:DF 1 "general_operand" "f,R,o,fG,fG,F,*d,*f,*d*G,*R,*o*F,*d,*d"))] "TARGET_HARD_FLOAT && !(TARGET_FLOAT64 && !TARGET_64BIT) + && TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) @@ -3157,6 +3512,7 @@ move\\t%0,%z4\\n\\ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,R,R,o,o,f,*d,*d,*d,*o,*R") (match_operand:DF 1 "general_operand" " f,o,f,G,f,G,F,*F,*o,*R,*d,*d"))] "TARGET_HARD_FLOAT && (TARGET_FLOAT64 && !TARGET_64BIT) + && TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)) || (GET_CODE (operands [0]) == MEM @@ -3171,7 +3527,7 @@ move\\t%0,%z4\\n\\ (define_insn "movdf_internal2" [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,R,o") (match_operand:DF 1 "general_operand" "dG,R,oF,d,d"))] - "TARGET_SOFT_FLOAT + "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0) @@ -3191,6 +3547,19 @@ move\\t%0,%z4\\n\\ (set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))] "") +;; Instructions to load the global pointer register. +;; This is volatile to make sure that the scheduler won't move any symbol_ref +;; uses in front of it. All symbol_refs implicitly use the gp reg. + +(define_insn "loadgp" + [(set (reg:DI 28) + (unspec_volatile [(match_operand:DI 0 "address_operand" "")] 2)) + (clobber (reg:DI 1))] + "" + "%[lui\\t$1,%%hi(%%neg(%%gp_rel(%a0)))\\n\\taddiu\\t$1,$1,%%lo(%%neg(%%gp_rel(%a0)))\\n\\tdaddu\\t$gp,$1,$25%]" + [(set_attr "type" "move") + (set_attr "mode" "DI") + (set_attr "length" "3")]) ;; Block moves, see mips.c for more details. ;; Argument 0 is the destination @@ -3322,7 +3691,7 @@ move\\t%0,%z4\\n\\ "* { if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f); return \"sll\\t%0,%1,%2\"; }" @@ -3392,7 +3761,7 @@ move\\t%0,%z4\\n\\ "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" "* { - operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f); operands[4] = const0_rtx; return \"sll\\t%M0,%L1,%2\;move\\t%L0,%z4\"; }" @@ -3414,7 +3783,7 @@ move\\t%0,%z4\\n\\ [(set (subreg:SI (match_dup 0) 1) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (const_int 0))] - "operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);") + "operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f);") (define_split @@ -3430,7 +3799,7 @@ move\\t%0,%z4\\n\\ [(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 1) (match_dup 2))) (set (subreg:SI (match_dup 0) 1) (const_int 0))] - "operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);") + "operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f);") (define_insn "ashldi3_internal3" @@ -3549,7 +3918,7 @@ move\\t%0,%z4\\n\\ "* { if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f); return \"sra\\t%0,%1,%2\"; }" @@ -3619,7 +3988,7 @@ move\\t%0,%z4\\n\\ "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" "* { - operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f); return \"sra\\t%L0,%M1,%2\;sra\\t%M0,%M1,31\"; }" [(set_attr "type" "darith") @@ -3640,7 +4009,7 @@ move\\t%0,%z4\\n\\ [(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 1) (match_dup 2))) (set (subreg:SI (match_dup 0) 1) (ashiftrt:SI (subreg:SI (match_dup 1) 1) (const_int 31)))] - "operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);") + "operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f);") (define_split @@ -3656,7 +4025,7 @@ move\\t%0,%z4\\n\\ [(set (subreg:SI (match_dup 0) 1) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (const_int 31)))] - "operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);") + "operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f);") (define_insn "ashrdi3_internal3" @@ -3774,7 +4143,7 @@ move\\t%0,%z4\\n\\ "* { if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f); return \"srl\\t%0,%1,%2\"; }" @@ -3844,7 +4213,7 @@ move\\t%0,%z4\\n\\ "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" "* { - operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f); operands[4] = const0_rtx; return \"srl\\t%L0,%M1,%2\;move\\t%M0,%z4\"; }" @@ -3866,7 +4235,7 @@ move\\t%0,%z4\\n\\ [(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 1) (match_dup 2))) (set (subreg:SI (match_dup 0) 1) (const_int 0))] - "operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);") + "operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f);") (define_split @@ -3882,7 +4251,7 @@ move\\t%0,%z4\\n\\ [(set (subreg:SI (match_dup 0) 1) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (const_int 0))] - "operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);") + "operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0x1f);") (define_insn "lshrdi3_internal3" @@ -4081,7 +4450,7 @@ move\\t%0,%z4\\n\\ [(set (cc0) (compare:CC_FP (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "register_operand" "")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" " { if (operands[0]) /* avoid unused code message */ @@ -4119,7 +4488,7 @@ move\\t%0,%z4\\n\\ (define_insn "branch_fp_ne" [(set (pc) - (if_then_else (ne:CC_FP (reg:CC_FP 66) + (if_then_else (ne:CC_FP (reg:CC_FP 67) (const_int 0)) (match_operand 0 "pc_or_label_operand" "") (match_operand 1 "pc_or_label_operand" "")))] @@ -4135,7 +4504,7 @@ move\\t%0,%z4\\n\\ (define_insn "branch_fp_ne_rev" [(set (pc) - (if_then_else (ne:CC_REV_FP (reg:CC_REV_FP 66) + (if_then_else (ne:CC_REV_FP (reg:CC_REV_FP 67) (const_int 0)) (match_operand 0 "pc_or_label_operand" "") (match_operand 1 "pc_or_label_operand" "")))] @@ -4151,7 +4520,7 @@ move\\t%0,%z4\\n\\ (define_insn "branch_fp_eq" [(set (pc) - (if_then_else (eq:CC_FP (reg:CC_FP 66) + (if_then_else (eq:CC_FP (reg:CC_FP 67) (const_int 0)) (match_operand 0 "pc_or_label_operand" "") (match_operand 1 "pc_or_label_operand" "")))] @@ -4167,7 +4536,7 @@ move\\t%0,%z4\\n\\ (define_insn "branch_fp_eq_rev" [(set (pc) - (if_then_else (eq:CC_REV_FP (reg:CC_REV_FP 66) + (if_then_else (eq:CC_REV_FP (reg:CC_REV_FP 67) (const_int 0)) (match_operand 0 "pc_or_label_operand" "") (match_operand 1 "pc_or_label_operand" "")))] @@ -5203,10 +5572,10 @@ move\\t%0,%z4\\n\\ ;; .................... (define_insn "seq_df" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (eq:CC_FP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -5221,10 +5590,10 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sne_df" - [(set (reg:CC_REV_FP 66) + [(set (reg:CC_REV_FP 67) (ne:CC_REV_FP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -5239,10 +5608,10 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "slt_df" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (lt:CC_FP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -5257,10 +5626,10 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sle_df" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (le:CC_FP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -5275,10 +5644,10 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sgt_df" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (gt:CC_FP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -5293,10 +5662,10 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sge_df" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (ge:CC_FP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -5311,7 +5680,7 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "seq_sf" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (eq:CC_FP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" @@ -5329,7 +5698,7 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sne_sf" - [(set (reg:CC_REV_FP 66) + [(set (reg:CC_REV_FP 67) (ne:CC_REV_FP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" @@ -5347,7 +5716,7 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "slt_sf" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (lt:CC_FP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" @@ -5365,7 +5734,7 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sle_sf" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (le:CC_FP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" @@ -5383,7 +5752,7 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sgt_sf" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (gt:CC_FP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" @@ -5401,7 +5770,7 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) (define_insn "sge_sf" - [(set (reg:CC_FP 66) + [(set (reg:CC_FP 67) (ge:CC_FP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" @@ -5436,7 +5805,12 @@ move\\t%0,%z4\\n\\ { if (GET_CODE (operands[0]) == REG) return \"%*j\\t%0\"; - else + /* ??? 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 (ABI_64BIT && mips_isa >= 3) + return \"%*b\\t%l0\"; + else return \"%*j\\t%l0\"; }" [(set_attr "type" "jump") @@ -5512,7 +5886,7 @@ move\\t%0,%z4\\n\\ "* { /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */ - if (TARGET_ABICALLS) + if (TARGET_ABICALLS && (! ABI_64BIT || mips_isa < 3)) output_asm_insn (\".cpadd\\t%0\", operands); return \"%*j\\t%0\"; }" @@ -5531,8 +5905,9 @@ move\\t%0,%z4\\n\\ "* { /* .cpdadd expands to dadd REG,REG,$gp when pic, and nothing when not pic. */ - if (TARGET_ABICALLS) - output_asm_insn (\".cpdadd\\t%0\", operands); + /* ??? SGI as does not have a .cpdadd. */ + if (TARGET_ABICALLS && (! ABI_64BIT || mips_isa < 3)) + output_asm_insn (\".cpadd\\t%0\", operands); return \"%*j\\t%0\"; }" [(set_attr "type" "jump") @@ -5694,7 +6069,7 @@ move\\t%0,%z4\\n\\ ;; current function. This specialized instruction does just that. (define_insn "get_fnaddr" - [(set (match_operand 0 "register_operand" "d") + [(set (match_operand 0 "register_operand" "=d") (unspec [(match_operand 1 "" "")] 1)) (clobber (reg:SI 31))] "TARGET_EMBEDDED_PIC @@ -5770,7 +6145,7 @@ move\\t%0,%z4\\n\\ else if (GET_CODE (target) == CONST_INT) { operands[0] = target; - return \"%*%[li\\t%@,%0\\n\\tjal\\t%2,%@%]\"; + return \"%[li\\t%@,%0\\n\\t%*jal\\t%2,%@%]\"; } else @@ -5927,7 +6302,7 @@ move\\t%0,%z4\\n\\ else if (GET_CODE (target) == CONST_INT) { operands[1] = target; - return \"%*%[li\\t%@,%1\\n\\tjal\\t%3,%@%]\"; + return \"%[li\\t%@,%1\\n\\t%*jal\\t%3,%@%]\"; } else @@ -6083,3 +6458,217 @@ move\\t%0,%z4\\n\\ /* fall through and generate default code */ }") + +;; +;; MIPS4 Conditional move instructions. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (if_then_else:SI + (match_operator 4 "equality_op" + [(match_operand:SI 1 "register_operand" "d,d") + (const_int 0)]) + (match_operand:SI 2 "reg_or_0_operand" "dJ,0") + (match_operand:SI 3 "reg_or_0_operand" "0,dJ")))] + "mips_isa >= 4" + "@ + mov%B4\\t%0,%z2,%1 + mov%b4\\t%0,%z3,%1" + [(set_attr "type" "move") + (set_attr "mode" "SI")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (if_then_else:SI + (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)]) + (match_operand:SI 1 "reg_or_0_operand" "dJ,0") + (match_operand:SI 2 "reg_or_0_operand" "0,dJ")))] + "mips_isa >= 4" + "@ + mov%T3\\t%0,%z1,$fcc0 + mov%t3\\t%0,%z2,$fcc0" + [(set_attr "type" "move") + (set_attr "mode" "SI")]) + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (if_then_else:DI + (match_operator 4 "equality_op" + [(match_operand:DI 1 "register_operand" "d,d") + (const_int 0)]) + (match_operand:DI 2 "reg_or_0_operand" "dJ,0") + (match_operand:DI 3 "reg_or_0_operand" "0,dJ")))] + "mips_isa >= 4" + "@ + mov%B4\\t%0,%z2,%1 + mov%b4\\t%0,%z3,%1" + [(set_attr "type" "move") + (set_attr "mode" "DI")]) + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (if_then_else:DI + (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)]) + (match_operand:DI 1 "reg_or_0_operand" "dJ,0") + (match_operand:DI 2 "reg_or_0_operand" "0,dJ")))] + "mips_isa >= 4" + "@ + mov%T3\\t%0,%z1,$fcc0 + mov%t3\\t%0,%z2,$fcc0" + [(set_attr "type" "move") + (set_attr "mode" "DI")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF + (match_operator 4 "equality_op" + [(match_operand:SI 1 "register_operand" "d,d") + (const_int 0)]) + (match_operand:SF 2 "register_operand" "f,0") + (match_operand:SF 3 "register_operand" "0,f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "@ + mov%B4.s\\t%0,%2,%1 + mov%b4.s\\t%0,%3,%1" + [(set_attr "type" "move") + (set_attr "mode" "SF")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF + (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)]) + (match_operand:SF 1 "register_operand" "f,0") + (match_operand:SF 2 "register_operand" "0,f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "@ + mov%T3.s\\t%0,%1,$fcc0 + mov%t3.s\\t%0,%2,$fcc0" + [(set_attr "type" "move") + (set_attr "mode" "SF")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF + (match_operator 4 "equality_op" + [(match_operand:SI 1 "register_operand" "d,d") + (const_int 0)]) + (match_operand:DF 2 "register_operand" "f,0") + (match_operand:DF 3 "register_operand" "0,f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "@ + mov%B4.d\\t%0,%2,%1 + mov%b4.d\\t%0,%3,%1" + [(set_attr "type" "move") + (set_attr "mode" "DF")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF + (match_operator 3 "equality_op" [(reg:CC_FP 67) (const_int 0)]) + (match_operand:DF 1 "register_operand" "f,0") + (match_operand:DF 2 "register_operand" "0,f")))] + "mips_isa >= 4 && TARGET_HARD_FLOAT" + "@ + mov%T3.d\\t%0,%1,$fcc0 + mov%t3.d\\t%0,%2,$fcc0" + [(set_attr "type" "move") + (set_attr "mode" "DF")]) + +;; These are the main define_expand's used to make conditional moves. + +(define_expand "movsicc" + [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) + (set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_dup 5) + (match_operand:SI 2 "reg_or_0_operand" "") + (match_operand:SI 3 "reg_or_0_operand" "")))] + "mips_isa >= 4" + " +{ + rtx op0 = branch_cmp[0]; + rtx op1 = branch_cmp[1]; + enum machine_mode mode = GET_MODE (branch_cmp[0]); + enum rtx_code compare_code = GET_CODE (operands[1]); + enum rtx_code move_code = NE; + + if (GET_MODE_CLASS (mode) != MODE_FLOAT) + { + switch (compare_code) + { + case EQ: + compare_code = XOR; + move_code = EQ; + break; + case NE: + compare_code = XOR; + break; + case LT: + break; + case GE: + compare_code = LT; + move_code = EQ; + break; + case GT: + compare_code = LT; + op0 = force_reg (mode, branch_cmp[1]); + op1 = branch_cmp[0]; + break; + case LE: + compare_code = LT; + op0 = force_reg (mode, branch_cmp[1]); + op1 = branch_cmp[0]; + move_code = EQ; + break; + case LTU: + break; + case GEU: + compare_code = LTU; + move_code = EQ; + break; + case GTU: + compare_code = LTU; + op0 = force_reg (mode, branch_cmp[1]); + op1 = branch_cmp[0]; + break; + case LEU: + compare_code = LTU; + op0 = force_reg (mode, branch_cmp[1]); + op1 = branch_cmp[0]; + move_code = EQ; + break; + default: + abort (); + } + } + else + { + if (compare_code == NE) + { + /* ??? Perhaps we need to use CC_FP_REVmode here? */ + compare_code = EQ; + move_code = EQ; + } + } + + if (mode == SImode || mode == DImode) + { + operands[1] = gen_rtx (compare_code, mode, op0, op1); + operands[4] = gen_reg_rtx (mode); + } + else if (mode == SFmode || mode == DFmode) + { + operands[1] = gen_rtx (compare_code, CC_FPmode, op0, op1); + operands[4] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM); + } + + if (mode == DImode) + operands[5] = gen_rtx (move_code, VOIDmode, + gen_lowpart (SImode, operands[4]), + CONST0_RTX (SImode)); + else + operands[5] = gen_rtx (move_code, VOIDmode, operands[4], + CONST0_RTX (SImode)); +}") + +;; ??? Need movdicc, movsfcc, and movdfcc patterns. They should be +;; very similar to the above movsicc pattern.