--- gcc/config/mips/mips.md 2018/04/24 18:15:56 1.1.1.2 +++ gcc/config/mips/mips.md 2018/04/24 18:29:52 1.1.1.4 @@ -1,7 +1,9 @@ ;; Mips.md Machine Description for MIPS based processors ;; Contributed by A. Lichnewsky, lich@inria.inria.fr ;; Changes by Michael Meissner, meissner@osf.org -;; Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. +;; 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and +;; Brendan Eich, brendan@microunity.com. +;; Copyright (C) 1989, 90, 91, 92, 93, 94, 95 Free Software Foundation, Inc. ;; This file is part of GNU CC. @@ -17,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. @@ -43,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 @@ -53,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 @@ -79,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" +;; ??? 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 @@ -137,43 +151,64 @@ ;; 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")) + (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")) + (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) -(define_function_unit "addr" 1 0 (eq_attr "type" "fcmp") 2 0) - (define_function_unit "memory" 1 0 (eq_attr "type" "xfer") 2 0) -(define_function_unit "memory" 1 0 (eq_attr "type" "hilo") 3 0) -(define_function_unit "imuldiv" 1 1 - (and (eq_attr "type" "imul") (eq_attr "cpu" "!r3000,r4000")) - 17 0) +(define_function_unit "imuldiv" 1 0 + (eq_attr "type" "hilo") + 1 3) + +(define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "imul") (eq_attr "cpu" "!r3000,r4000,r4600,r4650")) + 17 17) -(define_function_unit "imuldiv" 1 1 +(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul") (eq_attr "cpu" "r3000")) - 12 0) + 12 12) + +(define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "imul") (eq_attr "cpu" "r4000,r4600")) + 10 10) -(define_function_unit "imuldiv" 1 1 - (and (eq_attr "type" "imul") (eq_attr "cpu" "r4000")) - 10 0) - -(define_function_unit "imuldiv" 1 1 - (and (eq_attr "type" "idiv") (eq_attr "cpu" "!r3000,r4000")) - 38 0) +(define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "imul") (eq_attr "cpu" "r4650")) + 4 4) -(define_function_unit "imuldiv" 1 1 +(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 (and (eq_attr "type" "idiv") (eq_attr "cpu" "r3000")) - 35 0) + 35 35) + +(define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "idiv") (eq_attr "cpu" "r4600")) + 42 42) + +(define_function_unit "imuldiv" 1 0 + (and (eq_attr "type" "idiv") (eq_attr "cpu" "r4650")) + 36 36) -(define_function_unit "imuldiv" 1 1 +(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "r4000")) - 69 0) + 69 69) + +(define_function_unit "adder" 1 1 + (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r6000")) + 3 0) + +(define_function_unit "adder" 1 1 + (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r3000,r6000")) + 2 0) (define_function_unit "adder" 1 1 (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r6000")) @@ -188,15 +223,15 @@ 3 0) (define_function_unit "adder" 1 1 - (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "!r3000")) + (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")) + (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"))) + (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 @@ -208,6 +243,10 @@ 5 0) (define_function_unit "mult" 1 1 + (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650"))) + 8 0) + +(define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000"))) 8 0) @@ -220,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"))) + (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 @@ -232,7 +271,11 @@ 15 0) (define_function_unit "divide" 1 1 - (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000"))) + (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,r4650"))) 36 0) (define_function_unit "divide" 1 1 @@ -243,8 +286,25 @@ (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000"))) 16 0) -(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 0) -(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 0) +(define_function_unit "divide" 1 1 + (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,r4650"))) + 54 0) +(define_function_unit "divide" 1 1 + (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,r4650"))) + 112 0) +(define_function_unit "divide" 1 1 + (and (eq_attr "type" "fsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650"))) + 60 0) ;; The following functional units do not use the cpu type, and use @@ -286,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") @@ -318,12 +378,7 @@ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") (match_operand:SI 2 "arith_operand" "dI")))] "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768" - "* -{ - return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) - ? \"subu\\t%0,%z1,%n2\" - : \"addu\\t%0,%z1,%2\"; -}" + "addu\\t%0,%z1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) @@ -333,12 +388,19 @@ (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "arith_operand" ""))) (clobber (match_dup 3))])] - "!TARGET_DEBUG_G_MODE" + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" " { if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768) operands[2] = force_reg (DImode, operands[2]); + if (TARGET_64BIT) + { + emit_insn (gen_adddi3_internal_3 (operands[0], operands[1], + operands[2])); + DONE; + } + operands[3] = gen_reg_rtx (SImode); }") @@ -347,7 +409,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "0,d") (match_operand:DI 2 "register_operand" "d,d"))) (clobber (match_operand:SI 3 "register_operand" "=d,d"))] - "!TARGET_DEBUG_G_MODE" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE" "* { return (REGNO (operands[0]) == REGNO (operands[1]) @@ -364,7 +426,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2])) @@ -393,7 +455,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2])) @@ -422,7 +484,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "%d,%d,%d") (match_operand:DI 2 "small_int" "P,J,N"))) (clobber (match_operand:SI 3 "register_operand" "=d,d,d"))] - "!TARGET_DEBUG_G_MODE && INTVAL (operands[2]) != -32768" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && INTVAL (operands[2]) != -32768" "@ addu\\t%L0,%L1,%2\;sltu\\t%3,%L0,%2\;addu\\t%M0,%M1,%3 move\\t%L0,%L1\;move\\t%M0,%M1 @@ -436,7 +498,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && INTVAL (operands[2]) > 0" @@ -459,7 +521,7 @@ (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && INTVAL (operands[2]) > 0" @@ -476,6 +538,38 @@ (plus:SI (subreg:SI (match_dup 1) 0) (match_dup 3)))] "") + +(define_insn "adddi3_internal_3" + [(set (match_operand:DI 0 "register_operand" "=d") + (plus:DI (match_operand:DI 1 "reg_or_0_operand" "dJ") + (match_operand:DI 2 "arith_operand" "dI")))] + "TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"dsubu\\t%0,%z1,%n2\" + : \"daddu\\t%0,%z1,%2\"; +}" + [(set_attr "type" "darith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + + +(define_insn "addsi3_internal_2" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") + (match_operand:SI 2 "arith_operand" "dI"))))] + "TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"subu\\t%0,%z1,%n2\" + : \"addu\\t%0,%z1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + ;; ;; .................... @@ -489,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") @@ -521,12 +615,7 @@ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") (match_operand:SI 2 "arith_operand" "dI")))] "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768" - "* -{ - return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) - ? \"addu\\t%0,%z1,%n2\" - : \"subu\\t%0,%z1,%2\"; -}" + "subu\\t%0,%z1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) @@ -536,15 +625,25 @@ (minus:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d"))) (clobber (match_dup 3))])] - "!TARGET_DEBUG_G_MODE" - "operands[3] = gen_reg_rtx (SImode);") + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + " +{ + if (TARGET_64BIT) + { + emit_insn (gen_subdi3_internal_3 (operands[0], operands[1], + operands[2])); + DONE; + } + + operands[3] = gen_reg_rtx (SImode); +}") (define_insn "subdi3_internal" [(set (match_operand:DI 0 "register_operand" "=d") (minus:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE" "sltu\\t%3,%L1,%L2\;subu\\t%L0,%L1,%L2\;subu\\t%M0,%M1,%M2\;subu\\t%M0,%M0,%3" [(set_attr "type" "darith") (set_attr "mode" "DI") @@ -555,7 +654,7 @@ (minus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" @@ -582,7 +681,7 @@ (minus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" @@ -609,7 +708,7 @@ (minus:DI (match_operand:DI 1 "register_operand" "d,d,d") (match_operand:DI 2 "small_int" "P,J,N"))) (clobber (match_operand:SI 3 "register_operand" "=d,d,d"))] - "!TARGET_DEBUG_G_MODE && INTVAL (operands[2]) != -32768" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && INTVAL (operands[2]) != -32768" "@ sltu\\t%3,%L1,%2\;subu\\t%L0,%L1,%2\;subu\\t%M0,%M1,%3 move\\t%L0,%L1\;move\\t%M0,%M1 @@ -623,7 +722,7 @@ (minus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && INTVAL (operands[2]) > 0" @@ -646,7 +745,7 @@ (minus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && INTVAL (operands[2]) > 0" @@ -664,6 +763,37 @@ (match_dup 3)))] "") +(define_insn "subdi3_internal_3" + [(set (match_operand:DI 0 "register_operand" "=d") + (minus:DI (match_operand:DI 1 "reg_or_0_operand" "dJ") + (match_operand:DI 2 "arith_operand" "dI")))] + "TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"daddu\\t%0,%z1,%n2\" + : \"dsubu\\t%0,%z1,%2\"; +}" + [(set_attr "type" "darith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + + +(define_insn "subsi3_internal_2" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") + (match_operand:SI 2 "arith_operand" "dI"))))] + "TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"addu\\t%0,%z1,%n2\" + : \"subu\\t%0,%z1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + ;; ;; .................... @@ -677,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") @@ -693,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]; @@ -708,81 +873,373 @@ xoperands[1] = gen_rtx (REG, SImode, LO_REGNUM); output_asm_insn (\"mult\\t%1,%2\", operands); - output_asm_insn (mips_move_1word (xoperands, insn), xoperands); + output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands); return \"\"; }" [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "3")]) ;; mult + mflo + delay -(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" - [(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_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 "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_insn "mulsidi3" +(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 "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" "DI") + (set_attr "length" "1")]) + +(define_insn "muldi3_r4000" [(set (match_operand:DI 0 "register_operand" "=d") - (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) - (sign_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (reg:DI 64))] - "" + (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 "=l")) + (clobber (match_scratch:DI 5 "=a"))] + "TARGET_64BIT && mips_cpu == PROCESSOR_R4000" "* { rtx xoperands[10]; xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, DImode, MD_REG_FIRST); + xoperands[1] = gen_rtx (REG, DImode, LO_REGNUM); - output_asm_insn (\"mult\\t%1,%2\", operands); - output_asm_insn (mips_move_2words (xoperands, insn), xoperands); + output_asm_insn (\"dmult\\t%1,%2\", operands); + output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands); return \"\"; }" [(set_attr "type" "imul") + (set_attr "mode" "DI") + (set_attr "length" "3")]) ;; mult + mflo + delay + +;; ??? We could define a mulditi3 pattern when TARGET_64BIT. + +(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 "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" "SI") - (set_attr "length" "4")]) ;; mult + mflo + mfhi + delay + (set_attr "length" "1")]) -(define_insn "umulsidi3" - [(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 (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" "1")]) + +(define_insn "smulsi3_highpart" + [(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 (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] + "" + "mult\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) + +(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")))) - (clobber (reg:DI 64))] + (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))] "" - "* + " { - rtx xoperands[10]; + 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; +}") - xoperands[0] = operands[0]; - xoperands[1] = gen_rtx (REG, DImode, MD_REG_FIRST); +(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 (match_scratch:SI 3 "=a"))] + "!TARGET_64BIT" + "multu\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "1")]) - output_asm_insn (\"multu\\t%1,%2\", operands); - output_asm_insn (mips_move_2words (xoperands, insn), 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" "1")]) + +(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 (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=a"))] + "" + "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" "=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 (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=a"))] + "TARGET_64BIT" + "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" "=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 (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=a"))] + "TARGET_64BIT" + "dmultu\\t%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + +;; The R4650 supports a 32 bit multiply/ 64 bit accumulate +;; instruction. The HI/LO registers are used as a 64 bit accumulator. + +(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" "SI") + (set_attr "length" "1")]) + +(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" "4")]) ;; mult + mflo + mfhi + delay + (set_attr "length" "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" "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")]) ;; ;; .................... @@ -796,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") @@ -821,6 +1278,10 @@ ;; 64 is the multiply/divide hi register ;; 65 is the multiply/divide lo register +;; ??? We can't accept constants here, because the MIPS assembler will replace +;; a divide by power of 2 with a shift, and then the remainder is no longer +;; available. + (define_insn "divmodsi4" [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "register_operand" "d") @@ -828,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" "* { @@ -843,7 +1305,32 @@ }" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "13")]) ;; various tests for dividing by 0 and such + (set_attr "length" "14")]) ;; various tests for dividing by 0 and such + +(define_insn "divmoddi4" + [(set (match_operand:DI 0 "register_operand" "=d") + (div:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d"))) + (set (match_operand:DI 3 "register_operand" "=d") + (mod:DI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:DI 4 "=l")) + (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\"; + + return \"ddiv\\t%0,%1,%2\;mfhi\\t%3\"; +}" + [(set_attr "type" "idiv") + (set_attr "mode" "DI") + (set_attr "length" "15")]) ;; various tests for dividing by 0 and such (define_insn "udivmodsi4" [(set (match_operand:SI 0 "register_operand" "=d") @@ -852,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" "* { @@ -867,55 +1355,136 @@ }" [(set_attr "type" "idiv") (set_attr "mode" "SI") - (set_attr "length" "13")]) ;; various tests for dividing by 0 and such + (set_attr "length" "8")]) ;; various tests for dividing by 0 and such + +(define_insn "udivmoddi4" + [(set (match_operand:DI 0 "register_operand" "=d") + (udiv:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d"))) + (set (match_operand:DI 3 "register_operand" "=d") + (umod:DI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:DI 4 "=l")) + (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 \"ddivu\\t%0,%1,%2\"; + + if (find_reg_note (insn, REG_UNUSED, operands[0])) + return \"dremu\\t%3,%1,%2\"; + + return \"ddivu\\t%0,%1,%2\;mfhi\\t%3\"; +}" + [(set_attr "type" "idiv") + (set_attr "mode" "DI") + (set_attr "length" "8")]) ;; various tests for dividing by 0 and such (define_insn "divsi3" [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (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"))] "!optimize" "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 +(define_insn "divdi3" + [(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 (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") + (set_attr "mode" "DI") + (set_attr "length" "14")]) ;; various tests for dividing by 0 and such + (define_insn "modsi3" [(set (match_operand:SI 0 "register_operand" "=d") (mod:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (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"))] "!optimize" "rem\\t%0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI") + (set_attr "length" "13")]) ;; various tests for dividing by 0 and such + +(define_insn "moddi3" + [(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 (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") + (set_attr "mode" "DI") (set_attr "length" "14")]) ;; various tests for dividing by 0 and such (define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (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"))] "!optimize" "divu\\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" "7")]) ;; various tests for dividing by 0 and such + +(define_insn "udivdi3" + [(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 (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") + (set_attr "mode" "DI") + (set_attr "length" "7")]) ;; various tests for dividing by 0 and such (define_insn "umodsi3" [(set (match_operand:SI 0 "register_operand" "=d") (umod:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d"))) - (clobber (reg:SI 64)) - (clobber (reg:SI 65))] + (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"))] "!optimize" "remu\\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" "7")]) ;; various tests for dividing by 0 and such + +(define_insn "umoddi3" + [(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 (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") + (set_attr "mode" "DI") + (set_attr "length" "7")]) ;; various tests for dividing by 0 and such ;; @@ -928,9 +1497,9 @@ (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" "fabs") + [(set_attr "type" "fsqrt") (set_attr "mode" "DF") (set_attr "length" "1")]) @@ -939,7 +1508,7 @@ (sqrt:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && HAVE_SQRT_P()" "sqrt.s\\t%0,%1" - [(set_attr "type" "fabs") + [(set_attr "type" "fsqrt") (set_attr "mode" "SF") (set_attr "length" "1")]) @@ -964,18 +1533,43 @@ dslots_jump_filled++; operands[2] = const0_rtx; - return (REGNO (operands[0]) == REGNO (operands[1])) - ? \"bgez\\t%1,1f%#\\n\\tsubu\\t%0,%z2,%0\\n1:\" - : \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tsubu\\t%0,%z2,%0\\n1:%)\"; + if (REGNO (operands[0]) == REGNO (operands[1])) + { + if (mips_isa >= 2) + return \"%(bltzl\\t%1,1f\\n\\tsubu\\t%0,%z2,%0\\n1:%)\"; + else + return \"bgez\\t%1,1f%#\\n\\tsubu\\t%0,%z2,%0\\n1:\"; + } + else + return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tsubu\\t%0,%z2,%0\\n1:%)\"; }" [(set_attr "type" "multi") (set_attr "mode" "SI") (set_attr "length" "3")]) +(define_insn "absdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (abs:DI (match_operand:DI 1 "register_operand" "d")))] + "TARGET_64BIT" + "* +{ + dslots_jump_total++; + dslots_jump_filled++; + operands[2] = const0_rtx; + + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"%(bltzl\\t%1,1f\\n\\tdsubu\\t%0,%z2,%0\\n1:%)\"; + else + return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tdsubu\\t%0,%z2,%0\\n1:%)\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "3")]) + (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") @@ -1035,6 +1629,42 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "SI") (set_attr "length" "6")]) +(define_insn "ffsdi2" + [(set (match_operand:DI 0 "register_operand" "=&d") + (ffs:DI (match_operand:DI 1 "register_operand" "d"))) + (clobber (match_scratch:DI 2 "=&d")) + (clobber (match_scratch:DI 3 "=&d"))] + "TARGET_64BIT" + "* +{ + dslots_jump_total += 2; + dslots_jump_filled += 2; + operands[4] = const0_rtx; + + if (optimize && find_reg_note (insn, REG_DEAD, operands[1])) + return \"%(\\ +move\\t%0,%z4\\n\\ +\\tbeq\\t%1,%z4,2f\\n\\ +1:\\tand\\t%2,%1,0x0001\\n\\ +\\tdaddu\\t%0,%0,1\\n\\ +\\tbeq\\t%2,%z4,1b\\n\\ +\\tdsrl\\t%1,%1,1\\n\\ +2:%)\"; + + return \"%(\\ +move\\t%0,%z4\\n\\ +\\tmove\\t%3,%1\\n\\ +\\tbeq\\t%3,%z4,2f\\n\\ +1:\\tand\\t%2,%3,0x0001\\n\\ +\\tdaddu\\t%0,%0,1\\n\\ +\\tbeq\\t%2,%z4,1b\\n\\ +\\tdsrl\\t%3,%3,1\\n\\ +2:%)\"; +}" + [(set_attr "type" "multi") + (set_attr "mode" "DI") + (set_attr "length" "6")]) + ;; ;; .................... @@ -1060,14 +1690,23 @@ move\\t%0,%z4\\n\\ [(parallel [(set (match_operand:DI 0 "register_operand" "=d") (neg:DI (match_operand:DI 1 "register_operand" "d"))) (clobber (match_dup 2))])] - "!TARGET_DEBUG_G_MODE" - "operands[2] = gen_reg_rtx (SImode);") + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + " +{ + if (TARGET_64BIT) + { + emit_insn (gen_negdi2_internal_2 (operands[0], operands[1])); + DONE; + } + + operands[2] = gen_reg_rtx (SImode); +}") (define_insn "negdi2_internal" [(set (match_operand:DI 0 "register_operand" "=d") (neg:DI (match_operand:DI 1 "register_operand" "d"))) (clobber (match_operand:SI 2 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE" + "! TARGET_64BIT && !TARGET_DEBUG_G_MODE" "* { operands[3] = const0_rtx; @@ -1077,10 +1716,23 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "DI") (set_attr "length" "4")]) +(define_insn "negdi2_internal_2" + [(set (match_operand:DI 0 "register_operand" "=d") + (neg:DI (match_operand:DI 1 "register_operand" "d")))] + "TARGET_64BIT" + "* +{ + operands[2] = const0_rtx; + return \"dsubu\\t%0,%z2,%1\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (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") @@ -1110,21 +1762,26 @@ move\\t%0,%z4\\n\\ (define_insn "one_cmpldi2" [(set (match_operand:DI 0 "register_operand" "=d") - (not:SI (match_operand:DI 1 "register_operand" "d")))] + (not:DI (match_operand:DI 1 "register_operand" "d")))] "" "* { operands[2] = const0_rtx; + if (TARGET_64BIT) + return \"nor\\t%0,%z2,%1\"; return \"nor\\t%M0,%z2,%M1\;nor\\t%L0,%z2,%L1\"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") - (set_attr "length" "2")]) + (set (attr "length") + (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) + (const_int 1) + (const_int 2)))]) (define_split [(set (match_operand:DI 0 "register_operand" "") (not:DI (match_operand:DI 1 "register_operand" "")))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))" @@ -1151,16 +1808,24 @@ move\\t%0,%z4\\n\\ (not:DI (ior:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d"))))] "" - "nor\\t%M0,%M1,%M2\;nor\\t%L0,%L1,%L2" + "* +{ + if (TARGET_64BIT) + return \"nor\\t%0,%z1,%z2\"; + return \"nor\\t%M0,%M1,%M2\;nor\\t%L0,%L1,%L2\"; +}" [(set_attr "type" "darith") (set_attr "mode" "DI") - (set_attr "length" "2")]) + (set (attr "length") + (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) + (const_int 1) + (const_int 2)))]) (define_split [(set (match_operand:DI 0 "register_operand" "") (not:DI (ior:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" ""))))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" @@ -1194,17 +1859,25 @@ move\\t%0,%z4\\n\\ [(set (match_operand:DI 0 "register_operand" "=d") (and:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d")))] - "!TARGET_DEBUG_G_MODE" - "and\\t%M0,%M1,%M2\;and\\t%L0,%L1,%L2" + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + "* +{ + if (TARGET_64BIT) + return \"and\\t%0,%1,%2\"; + return \"and\\t%M0,%M1,%M2\;and\\t%L0,%L1,%L2\"; +}" [(set_attr "type" "darith") (set_attr "mode" "DI") - (set_attr "length" "2")]) + (set (attr "length") + (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) + (const_int 1) + (const_int 2)))]) (define_split [(set (match_operand:DI 0 "register_operand" "") (and:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" "")))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" @@ -1213,6 +1886,18 @@ move\\t%0,%z4\\n\\ (set (subreg:SI (match_dup 0) 1) (and:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))] "") +(define_insn "anddi3_internal1" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (and:DI (match_operand:DI 1 "register_operand" "%d,d") + (match_operand:DI 2 "uns_arith_operand" "d,K")))] + "TARGET_64BIT" + "@ + and\\t%0,%1,%2 + andi\\t%0,%1,%x2" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (ior:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") @@ -1225,21 +1910,32 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "SI") (set_attr "length" "1")]) +;;; ??? There is no iordi3 pattern which accepts 'K' constants when +;;; TARGET_64BIT + (define_insn "iordi3" [(set (match_operand:DI 0 "register_operand" "=d") (ior:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d")))] - "!TARGET_DEBUG_G_MODE" - "or\\t%M0,%M1,%M2\;or\\t%L0,%L1,%L2" + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + "* +{ + if (TARGET_64BIT) + return \"or\\t%0,%1,%2\"; + return \"or\\t%M0,%M1,%M2\;or\\t%L0,%L1,%L2\"; +}" [(set_attr "type" "darith") (set_attr "mode" "DI") - (set_attr "length" "2")]) + (set (attr "length") + (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) + (const_int 1) + (const_int 2)))]) (define_split [(set (match_operand:DI 0 "register_operand" "") (ior:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" "")))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" @@ -1260,21 +1956,31 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "SI") (set_attr "length" "1")]) +;; ??? If delete the 32-bit long long patterns, then could merge this with +;; the following xordi3_internal pattern. (define_insn "xordi3" [(set (match_operand:DI 0 "register_operand" "=d") (xor:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d")))] - "!TARGET_DEBUG_G_MODE" - "xor\\t%M0,%M1,%M2\;xor\\t%L0,%L1,%L2" + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + "* +{ + if (TARGET_64BIT) + return \"xor\\t%0,%1,%2\"; + return \"xor\\t%M0,%M1,%M2\;xor\\t%L0,%L1,%L2\"; +}" [(set_attr "type" "darith") (set_attr "mode" "DI") - (set_attr "length" "2")]) + (set (attr "length") + (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) + (const_int 1) + (const_int 2)))]) (define_split [(set (match_operand:DI 0 "register_operand" "") (xor:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "register_operand" "")))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" @@ -1283,6 +1989,16 @@ move\\t%0,%z4\\n\\ (set (subreg:SI (match_dup 0) 1) (xor:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))] "") +(define_insn "xordi3_immed" + [(set (match_operand:DI 0 "register_operand" "d") + (xor:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "uns_arith_operand" "K")))] + "TARGET_64BIT" + "xori\\t%0,%1,%x2" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + ;; ;; .................... @@ -1294,12 +2010,142 @@ 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")]) +(define_insn "truncdisi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (match_operand:DI 1 "register_operand" "d")))] + "TARGET_64BIT" + "dsll\\t%0,%1,32\;dsra\\t%0,%0,32" + [(set_attr "type" "darith") + (set_attr "mode" "SI") + (set_attr "length" "2")]) + +(define_insn "truncdihi2" + [(set (match_operand:HI 0 "register_operand" "=d") + (truncate:HI (match_operand:DI 1 "register_operand" "d")))] + "TARGET_64BIT" + "andi\\t%0,%1,0xffff" + [(set_attr "type" "darith") + (set_attr "mode" "HI") + (set_attr "length" "1")]) + +(define_insn "truncdiqi2" + [(set (match_operand:QI 0 "register_operand" "=d") + (truncate:QI (match_operand:DI 1 "register_operand" "d")))] + "TARGET_64BIT" + "andi\\t%0,%1,0x00ff" + [(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")]) ;; ;; .................... @@ -1309,8 +2155,37 @@ move\\t%0,%z4\\n\\ ;; .................... ;; Extension insns. -;; Those for integer source operand -;; are ordered widest source type first. +;; Those for integer source operand are ordered widest source type first. + +(define_expand "zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_64BIT" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op1 = gen_lowpart (DImode, operands[1]); + rtx temp = gen_reg_rtx (DImode); + rtx shift = gen_rtx (CONST_INT, VOIDmode, 32); + + emit_insn (gen_ashldi3 (temp, op1, shift)); + emit_insn (gen_lshrdi3 (operands[0], temp, shift)); + DONE; + } +}") + +(define_insn "zero_extendsidi2_internal" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (zero_extend:DI (match_operand:SI 1 "memory_operand" "R,m")))] + "TARGET_64BIT" + "* return mips_move_1word (operands, insn, TRUE);" + [(set_attr "type" "load") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) (define_insn "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "=d,d,d") @@ -1327,6 +2202,21 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "SI") (set_attr "length" "1,1,2")]) +(define_insn "zero_extendhidi2" + [(set (match_operand:DI 0 "register_operand" "=d,d,d") + (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))] + "TARGET_64BIT" + "* +{ + if (which_alternative == 0) + return \"andi\\t%0,%1,0xffff\"; + else + return mips_move_1word (operands, insn, TRUE); +}" + [(set_attr "type" "arith,load,load") + (set_attr "mode" "DI") + (set_attr "length" "1,1,2")]) + (define_insn "zero_extendqihi2" [(set (match_operand:HI 0 "register_operand" "=d,d,d") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] @@ -1357,6 +2247,21 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "SI") (set_attr "length" "1,1,2")]) +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "register_operand" "=d,d,d") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] + "TARGET_64BIT" + "* +{ + if (which_alternative == 0) + return \"andi\\t%0,%1,0x00ff\"; + else + return mips_move_1word (operands, insn, TRUE); +}" + [(set_attr "type" "arith,load,load") + (set_attr "mode" "DI") + (set_attr "length" "1,1,2")]) + ;; ;; .................... @@ -1366,13 +2271,72 @@ move\\t%0,%z4\\n\\ ;; .................... ;; Extension insns. -;; Those for integer source operand -;; are ordered widest source type first. +;; Those for integer source operand are ordered widest source type first. + +(define_expand "extendsidi2" + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_64BIT" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op1 = gen_lowpart (DImode, operands[1]); + rtx temp = gen_reg_rtx (DImode); + rtx shift = gen_rtx (CONST_INT, VOIDmode, 32); + + emit_insn (gen_ashldi3 (temp, op1, shift)); + emit_insn (gen_ashrdi3 (operands[0], temp, shift)); + DONE; + } +}") + +(define_insn "extendsidi2_internal" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (sign_extend:DI (match_operand:SI 1 "memory_operand" "R,m")))] + "TARGET_64BIT" + "* return mips_move_1word (operands, insn, FALSE);" + [(set_attr "type" "load") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) ;; These patterns originally accepted general_operands, however, slightly ;; better code is generated by only accepting register_operands, and then ;; letting combine generate the lh and lb insns. +(define_expand "extendhidi2" + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "")))] + "TARGET_64BIT" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op1 = gen_lowpart (DImode, operands[1]); + rtx temp = gen_reg_rtx (DImode); + rtx shift = gen_rtx (CONST_INT, VOIDmode, 48); + + emit_insn (gen_ashldi3 (temp, op1, shift)); + emit_insn (gen_ashrdi3 (operands[0], temp, shift)); + DONE; + } +}") + +(define_insn "extendhidi2_internal" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (sign_extend:DI (match_operand:HI 1 "memory_operand" "R,m")))] + "TARGET_64BIT" + "* return mips_move_1word (operands, insn, FALSE);" + [(set_attr "type" "load") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) + (define_expand "extendhisi2" [(set (match_operand:SI 0 "register_operand" "") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] @@ -1465,11 +2429,41 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "SI") (set_attr "length" "1,2")]) +(define_expand "extendqidi2" + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:QI 1 "nonimmediate_operand" "")))] + "TARGET_64BIT" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op1 = gen_lowpart (DImode, operands[1]); + rtx temp = gen_reg_rtx (DImode); + rtx shift = gen_rtx (CONST_INT, VOIDmode, 56); + + emit_insn (gen_ashldi3 (temp, op1, shift)); + emit_insn (gen_ashrdi3 (operands[0], temp, shift)); + DONE; + } +}") + +(define_insn "extendqidi2_insn" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (sign_extend:DI (match_operand:QI 1 "memory_operand" "R,m")))] + "TARGET_64BIT" + "* return mips_move_1word (operands, insn, FALSE);" + [(set_attr "type" "load") + (set_attr "mode" "DI") + (set_attr "length" "1,2")]) + (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") @@ -1493,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]; @@ -1538,10 +2532,70 @@ move\\t%0,%z4\\n\\ (set_attr "length" "11,9,10,11")]) +;;; ??? trunc.l.d is mentioned in the appendix of the 1993 r4000/r4600 manuals +;;; but not in the chapter that describes the FPU. It is not mentioned at all +;;; in the 1991 manuals. The r4000 at Cygnus does not have this instruction. + +;;; Deleting this means that we now need two libgcc2.a libraries. One for +;;; the 32 bit calling convention and one for the 64 bit calling convention. + +;;; If this is disabled, then fixuns_truncdfdi2 must be disabled also. + +(define_insn "fix_truncdfdi2" + [(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_DOUBLE_FLOAT" + "* +{ + rtx xoperands[10]; + + if (which_alternative == 1) + return \"trunc.l.d %0,%1\"; + + output_asm_insn (\"trunc.l.d %2,%1\", operands); + + xoperands[0] = operands[0]; + xoperands[1] = operands[2]; + output_asm_insn (mips_move_2words (xoperands, insn, FALSE), xoperands); + return \"\"; +}" + [(set_attr "type" "fcvt") + (set_attr "mode" "DF") + (set_attr "length" "2,1,2,3")]) + + +;;; ??? trunc.l.s is mentioned in the appendix of the 1993 r4000/r4600 manuals +;;; but not in the chapter that describes the FPU. It is not mentioned at all +;;; in the 1991 manuals. The r4000 at Cygnus does not have this instruction. +(define_insn "fix_truncsfdi2" + [(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_DOUBLE_FLOAT" + "* +{ + rtx xoperands[10]; + + if (which_alternative == 1) + return \"trunc.l.s %0,%1\"; + + output_asm_insn (\"trunc.l.s %2,%1\", operands); + + xoperands[0] = operands[0]; + xoperands[1] = operands[2]; + output_asm_insn (mips_move_2words (xoperands, insn, FALSE), xoperands); + return \"\"; +}" + [(set_attr "type" "fcvt") + (set_attr "mode" "SF") + (set_attr "length" "2,1,2,3")]) + + (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++; @@ -1555,6 +2609,23 @@ move\\t%0,%z4\\n\\ (set_attr "length" "3,4,3")]) +(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_DOUBLE_FLOAT" + "* +{ + dslots_load_total++; + if (GET_CODE (operands[1]) == MEM) + return \"l.d\\t%0,%1%#\;cvt.d.l\\t%0,%0\"; + + return \"dmtc1\\t%1,%0%#\;cvt.d.l\\t%0,%0\"; +}" + [(set_attr "type" "fcvt") + (set_attr "mode" "DF") + (set_attr "length" "3,4,3")]) + + (define_insn "floatsisf2" [(set (match_operand:SF 0 "register_operand" "=f,f,f") (float:SF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))] @@ -1572,10 +2643,27 @@ move\\t%0,%z4\\n\\ (set_attr "length" "3,4,3")]) +(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_DOUBLE_FLOAT" + "* +{ + dslots_load_total++; + if (GET_CODE (operands[1]) == MEM) + return \"l.d\\t%0,%1%#\;cvt.s.l\\t%0,%0\"; + + return \"dmtc1\\t%1,%0%#\;cvt.s.l\\t%0,%0\"; +}" + [(set_attr "type" "fcvt") + (set_attr "mode" "SF") + (set_attr "length" "3,4,3")]) + + (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); @@ -1615,6 +2703,50 @@ 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_DOUBLE_FLOAT" + " +{ + rtx reg1 = gen_reg_rtx (DFmode); + rtx reg2 = gen_reg_rtx (DFmode); + rtx reg3 = gen_reg_rtx (DImode); + rtx label1 = gen_label_rtx (); + rtx label2 = gen_label_rtx (); + REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 63); + + if (reg1) /* turn off complaints about unreached code */ + { + emit_move_insn (reg1, immed_real_const_1 (offset, DFmode)); + do_pending_stack_adjust (); + + emit_insn (gen_cmpdf (operands[1], reg1)); + emit_jump_insn (gen_bge (label1)); + + emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1])); + emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (LABEL_REF, VOIDmode, label2))); + emit_barrier (); + + emit_label (label1); + emit_move_insn (reg2, gen_rtx (MINUS, DFmode, operands[1], reg1)); + emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000)); + emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32))); + + emit_insn (gen_fix_truncdfdi2 (operands[0], reg2)); + emit_insn (gen_iordi3 (operands[0], operands[0], reg3)); + + emit_label (label2); + + /* allow REG_NOTES to be set on last insn (labels don't have enough + fields, and can't be used for REG_NOTES anyway). */ + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + DONE; + } +}") + + (define_expand "fixuns_truncsfsi2" [(set (match_operand:SI 0 "register_operand" "") (unsigned_fix:SI (match_operand:SF 1 "register_operand" "")))] @@ -1657,6 +2789,50 @@ 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_DOUBLE_FLOAT" + " +{ + rtx reg1 = gen_reg_rtx (SFmode); + rtx reg2 = gen_reg_rtx (SFmode); + rtx reg3 = gen_reg_rtx (DImode); + rtx label1 = gen_label_rtx (); + rtx label2 = gen_label_rtx (); + REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 63); + + if (reg1) /* turn off complaints about unreached code */ + { + emit_move_insn (reg1, immed_real_const_1 (offset, SFmode)); + do_pending_stack_adjust (); + + emit_insn (gen_cmpsf (operands[1], reg1)); + emit_jump_insn (gen_bge (label1)); + + emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1])); + emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (LABEL_REF, VOIDmode, label2))); + emit_barrier (); + + emit_label (label1); + emit_move_insn (reg2, gen_rtx (MINUS, SFmode, operands[1], reg1)); + emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000)); + emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32))); + + emit_insn (gen_fix_truncsfdi2 (operands[0], reg2)); + emit_insn (gen_iordi3 (operands[0], operands[0], reg3)); + + emit_label (label2); + + /* allow REG_NOTES to be set on last insn (labels don't have enough + fields, and can't be used for REG_NOTES anyway). */ + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + DONE; + } +}") + ;; ;; .................... @@ -1665,54 +2841,99 @@ move\\t%0,%z4\\n\\ ;; ;; .................... -;; unaligned word moves generated by the block moves. +;; Bit field extract patterns which use lwl/lwr. + +;; ??? There should be DImode variants for 64 bit code, but the current +;; bitfield scheme can't handle that. We would need to add new optabs +;; in order to make that work. + +;; ??? There could be HImode variants for the ulh/ulhu/ush macros. +;; It isn't clear whether this will give better code. -(define_expand "movsi_unaligned" - [(set (match_operand:SI 0 "general_operand" "") - (unspec [(match_operand:SI 1 "general_operand" "")] 0))] +(define_expand "extv" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extract:SI (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] "" " { - /* Handle stores. */ - if (GET_CODE (operands[0]) == MEM) - { - rtx reg = gen_reg_rtx (SImode); - rtx insn = emit_insn (gen_movsi_ulw (reg, operands[1])); - rtx addr = XEXP (operands[0], 0); - if (CONSTANT_P (addr)) - REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV, addr, REG_NOTES (insn)); + /* If this isn't a 32 bit field, and it doesn't start on a byte boundary + then fail. */ + if (INTVAL (operands[2]) != 32 || (INTVAL (operands[3]) % 8) != 0) + FAIL; - if (reg_or_0_operand (operands[1], SImode)) - DONE; + /* This can happen for a 64 bit target, when extracting a value from + a 64 bit union member. extract_bit_field doesn't verify that our + source matches the predicate, so we force it to be a MEM here. */ + if (GET_CODE (operands[1]) != MEM) + FAIL; - operands[1] = reg; - } + /* Otherwise, emit a lwl/lwr pair to load the value. */ + emit_insn (gen_movsi_ulw (operands[0], operands[1])); + DONE; +}") - /* Generate appropriate load, store. If not a load or store, - do a normal movsi. */ - if (GET_CODE (operands[0]) != MEM && GET_CODE (operands[1]) != MEM) - { - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } +(define_expand "extzv" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] + "" + " +{ + /* If this isn't a 32 bit field, and it doesn't start on a byte boundary + then fail. */ + if (INTVAL (operands[2]) != 32 || (INTVAL (operands[3]) % 8) != 0) + FAIL; + + /* This can happen for a 64 bit target, when extracting a value from + a 64 bit union member. extract_bit_field doesn't verify that our + source matches the predicate, so we force it to be a MEM here. */ + if (GET_CODE (operands[1]) != MEM) + FAIL; + + /* Otherwise, emit a lwl/lwr pair to load the value. */ + emit_insn (gen_movsi_ulw (operands[0], operands[1])); + DONE; +}") + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "immediate_operand" "")) + (match_operand:SI 3 "register_operand" ""))] + "" + " +{ + /* If this isn't a 32 bit field, and it doesn't start on a byte boundary + then fail. */ + if (INTVAL (operands[1]) != 32 || (INTVAL (operands[2]) % 8) != 0) + FAIL; + + /* This can happen for a 64 bit target, when storing into a 32 bit union + member. store_bit_field doesn't verify that our target matches the + predicate, so we force it to be a MEM here. */ + if (GET_CODE (operands[0]) != MEM) + FAIL; - /* Fall through and generate normal code. */ + /* Otherwise, emit a swl/swr pair to load the value. */ + emit_insn (gen_movsi_usw (operands[0], operands[3])); + DONE; }") +;; unaligned word moves generated by the bit field patterns + (define_insn "movsi_ulw" - [(set (match_operand:SI 0 "register_operand" "=&d,&d,d,d") - (unspec [(match_operand:SI 1 "general_operand" "R,o,dIKL,M")] 0))] + [(set (match_operand:SI 0 "register_operand" "=&d,&d") + (unspec [(match_operand:QI 1 "general_operand" "R,o")] 0))] "" "* { - enum rtx_code code; + rtx offset = const0_rtx; + rtx addr = XEXP (operands[1], 0); + rtx mem_addr = eliminate_constant_term (addr, &offset); char *ret; - rtx offset; - rtx addr; - rtx mem_addr; - - if (which_alternative != 0) - return mips_move_1word (operands, insn, FALSE); if (TARGET_STATS) mips_count_memory_refs (operands[1], 2); @@ -1720,38 +2941,21 @@ move\\t%0,%z4\\n\\ /* The stack/frame pointers are always aligned, so we can convert to the faster lw if we are referencing an aligned stack location. */ - offset = const0_rtx; - addr = XEXP (operands[1], 0); - mem_addr = eliminate_constant_term (addr, &offset); - - if ((INTVAL (offset) & (UNITS_PER_WORD-1)) == 0 + if ((INTVAL (offset) & 3) == 0 && (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx)) ret = \"lw\\t%0,%1\"; - else - { - ret = \"ulw\\t%0,%1\"; - if (TARGET_GAS) - { - enum rtx_code code = GET_CODE (addr); - - if (code == CONST || code == SYMBOL_REF || code == LABEL_REF) - { - operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 1); - ret = \"%[la\\t%2,%1\;ulw\\t%0,0(%2)%]\"; - } - } - } + ret = \"ulw\\t%0,%1\"; return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn); }" - [(set_attr "type" "load,load,move,arith") + [(set_attr "type" "load,load") (set_attr "mode" "SI") - (set_attr "length" "2,4,1,2")]) + (set_attr "length" "2,4")]) (define_insn "movsi_usw" - [(set (match_operand:SI 0 "memory_operand" "=R,o") - (unspec [(match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")] 0))] + [(set (match_operand:QI 0 "memory_operand" "=R,o") + (unspec [(match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")] 1))] "" "* { @@ -1765,29 +2969,16 @@ move\\t%0,%z4\\n\\ /* The stack/frame pointers are always aligned, so we can convert to the faster sw if we are referencing an aligned stack location. */ - if ((INTVAL (offset) & (UNITS_PER_WORD-1)) == 0 + if ((INTVAL (offset) & 3) == 0 && (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx)) return \"sw\\t%1,%0\"; - - if (TARGET_GAS) - { - enum rtx_code code = GET_CODE (XEXP (operands[0], 0)); - - if (code == CONST || code == SYMBOL_REF || code == LABEL_REF) - { - operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 1); - return \"%[la\\t%2,%0\;usw\\t%z1,0(%2)%]\"; - } - } - return \"usw\\t%z1,%0\"; }" [(set_attr "type" "store") (set_attr "mode" "SI") (set_attr "length" "2,4")]) - ;; 64-bit integer moves ;; Unlike most other insns, the move insns can't be split with @@ -1800,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) @@ -1815,19 +3037,20 @@ move\\t%0,%z4\\n\\ (define_insn "movdi_internal" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*d,*x") (match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,*x,*d"))] - "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)" + "!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,arith,load,load,store,store,hilo,hilo") (set_attr "mode" "DI") - (set_attr "length" "2,4,2,4,2,4,2,2")]) + (set_attr "length" "2,4,2,4,2,4,2,2")]) (define_split [(set (match_operand:DI 0 "register_operand" "") (match_operand:DI 1 "register_operand" ""))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))" @@ -1835,6 +3058,150 @@ move\\t%0,%z4\\n\\ (set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))] "") +(define_insn "movdi_internal2" + [(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,hilo") + (set_attr "mode" "DI") + (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 @@ -1863,6 +3230,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 (SImode, temp)); + emit_move_insn (operands[0], force_reg (SImode, temp)); + DONE; + } + + /* 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])) + { + rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0)); + rtx temp2 = XEXP (XEXP (operands[1], 0), 1); + + if (! SMALL_INT (temp2)) + temp2 = force_reg (SImode, temp2); + + emit_move_insn (operands[0], gen_rtx (PLUS, SImode, temp, temp2)); + DONE; + } + if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], SImode) && !register_operand (operands[1], SImode) @@ -1878,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, TRUE);" - [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo") + "* 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,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, TRUE);" - [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo") + "* return mips_move_1word (operands, insn, FALSE);" + [(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 @@ -2028,7 +3448,7 @@ move\\t%0,%z4\\n\\ (define_insn "movsf_internal1" [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,f,R,m,*f,*d,*d,*d,*d,*R,*m") - (match_operand:SF 1 "general_operand" "f,G,R,Em,fG,fG,*d,*f,*G*d,*R,*E*m,*d,*d"))] + (match_operand:SF 1 "general_operand" "f,G,R,Fm,fG,fG,*d,*f,*G*d,*R,*F*m,*d,*d"))] "TARGET_HARD_FLOAT && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode) @@ -2042,7 +3462,7 @@ move\\t%0,%z4\\n\\ (define_insn "movsf_internal2" [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,R,m") - (match_operand:SF 1 "general_operand" " Gd,R,Em,d,d"))] + (match_operand:SF 1 "general_operand" " Gd,R,Fm,d,d"))] "TARGET_SOFT_FLOAT && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode) @@ -2076,8 +3496,9 @@ move\\t%0,%z4\\n\\ (define_insn "movdf_internal1" [(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,E,*d,*f,*d*G,*R,*o*E,*d,*d"))] - "TARGET_HARD_FLOAT + (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) @@ -2087,10 +3508,26 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "DF") (set_attr "length" "1,2,4,2,4,4,2,2,2,2,4,2,4")]) +(define_insn "movdf_internal1a" + [(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 + && ((GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == 0) + || operands[1] == CONST0_RTX (DFmode)))" + "* return mips_move_2words (operands, insn); " + [(set_attr "type" "move,load,store,store,store,store,load,load,load,load,store,store") + (set_attr "mode" "DF") + (set_attr "length" "1,2,1,1,2,2,2,2,2,1,2,1")]) + (define_insn "movdf_internal2" [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,R,o") - (match_operand:DF 1 "general_operand" "dG,R,oE,d,d"))] - "TARGET_SOFT_FLOAT + (match_operand:DF 1 "general_operand" "dG,R,oF,d,d"))] + "(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) @@ -2103,14 +3540,26 @@ move\\t%0,%z4\\n\\ (define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "register_operand" ""))] - "reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))" - [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0)) (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 @@ -2219,7 +3668,7 @@ move\\t%0,%z4\\n\\ (clobber (match_scratch:SI 7 "=&d")) ;; temp 4 (use (match_operand:SI 2 "small_int" "I")) ;; # bytes to move (use (match_operand:SI 3 "small_int" "I")) ;; alignment - (use (const_int 2))] ;; just last store of block mvoe + (use (const_int 2))] ;; just last store of block move "" "* return output_block_move (insn, operands, 4, BLOCK_MOVE_LAST);" [(set_attr "type" "store") @@ -2242,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\"; }" @@ -2256,8 +3705,18 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "arith_operand" ""))) (clobber (match_dup 3))])] - "!TARGET_DEBUG_G_MODE" - "operands[3] = gen_reg_rtx (SImode);") + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + " +{ + if (TARGET_64BIT) + { + emit_insn (gen_ashldi3_internal4 (operands[0], operands[1], + operands[2])); + DONE; + } + + operands[3] = gen_reg_rtx (SImode); +}") (define_insn "ashldi3_internal" @@ -2265,7 +3724,7 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE" "* { operands[4] = const0_rtx; @@ -2299,10 +3758,10 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "IJK"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" + "!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\"; }" @@ -2316,7 +3775,7 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" @@ -2324,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 @@ -2332,7 +3791,7 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" @@ -2340,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" @@ -2348,7 +3807,7 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "IJK"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" "* @@ -2371,7 +3830,7 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 63) < 32 @@ -2405,7 +3864,7 @@ move\\t%0,%z4\\n\\ (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 63) < 32 @@ -2434,6 +3893,23 @@ move\\t%0,%z4\\n\\ }") +(define_insn "ashldi3_internal4" + [(set (match_operand:DI 0 "register_operand" "=d") + (ashift:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "TARGET_64BIT" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); + + return \"dsll\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + + (define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "d") @@ -2442,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\"; }" @@ -2456,8 +3932,18 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "arith_operand" ""))) (clobber (match_dup 3))])] - "!TARGET_DEBUG_G_MODE" - "operands[3] = gen_reg_rtx (SImode);") + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + " +{ + if (TARGET_64BIT) + { + emit_insn (gen_ashrdi3_internal4 (operands[0], operands[1], + operands[2])); + DONE; + } + + operands[3] = gen_reg_rtx (SImode); +}") (define_insn "ashrdi3_internal" @@ -2465,7 +3951,7 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE" "* { operands[4] = const0_rtx; @@ -2499,10 +3985,10 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "IJK"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" + "!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") @@ -2515,7 +4001,7 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" @@ -2523,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 @@ -2531,7 +4017,7 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" @@ -2539,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" @@ -2547,7 +4033,7 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "IJK"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" "* @@ -2569,7 +4055,7 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 63) < 32 @@ -2603,7 +4089,7 @@ move\\t%0,%z4\\n\\ (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 63) < 32 @@ -2632,6 +4118,23 @@ move\\t%0,%z4\\n\\ }") +(define_insn "ashrdi3_internal4" + [(set (match_operand:DI 0 "register_operand" "=d") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "TARGET_64BIT" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); + + return \"dsra\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + + (define_insn "lshrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "d") @@ -2640,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\"; }" @@ -2654,8 +4157,18 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "arith_operand" ""))) (clobber (match_dup 3))])] - "!TARGET_DEBUG_G_MODE" - "operands[3] = gen_reg_rtx (SImode);") + "TARGET_64BIT || !TARGET_DEBUG_G_MODE" + " +{ + if (TARGET_64BIT) + { + emit_insn (gen_lshrdi3_internal4 (operands[0], operands[1], + operands[2])); + DONE; + } + + operands[3] = gen_reg_rtx (SImode); +}") (define_insn "lshrdi3_internal" @@ -2663,7 +4176,7 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE" + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE" "* { operands[4] = const0_rtx; @@ -2697,10 +4210,10 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "IJK"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" + "!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\"; }" @@ -2714,7 +4227,7 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" @@ -2722,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 @@ -2730,7 +4243,7 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" @@ -2738,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" @@ -2746,7 +4259,7 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "IJK"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_DEBUG_G_MODE + "!TARGET_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" "* @@ -2768,7 +4281,7 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && !WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 63) < 32 @@ -2802,7 +4315,7 @@ move\\t%0,%z4\\n\\ (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "small_int" ""))) (clobber (match_operand:SI 3 "register_operand" ""))] - "reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE + "reload_completed && WORDS_BIG_ENDIAN && !TARGET_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 63) < 32 @@ -2830,6 +4343,23 @@ move\\t%0,%z4\\n\\ operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31)); }") + +(define_insn "lshrdi3_internal4" + [(set (match_operand:DI 0 "register_operand" "=d") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "TARGET_64BIT" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); + + return \"dsrl\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + ;; ;; .................... @@ -2840,7 +4370,7 @@ move\\t%0,%z4\\n\\ ;; Flow here is rather complex: ;; -;; 1) The cmp{si,sf,df} routine is called. It deposits the +;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ;; arguments into the branch_cmp array, and the type into ;; branch_type. No RTL is generated. ;; @@ -2885,11 +4415,42 @@ move\\t%0,%z4\\n\\ } }") +(define_expand "cmpdi" + [(set (cc0) + (compare:CC (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "arith_operand" "")))] + "TARGET_64BIT" + " +{ + if (operands[0]) /* avoid unused code message */ + { + branch_cmp[0] = operands[0]; + branch_cmp[1] = operands[1]; + branch_type = CMP_DI; + DONE; + } +}") + +(define_expand "tstdi" + [(set (cc0) + (match_operand:DI 0 "register_operand" ""))] + "TARGET_64BIT" + " +{ + if (operands[0]) /* avoid unused code message */ + { + branch_cmp[0] = operands[0]; + branch_cmp[1] = const0_rtx; + branch_type = CMP_DI; + DONE; + } +}") + (define_expand "cmpdf" [(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 */ @@ -2927,11 +4488,11 @@ 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" "")))] - "" + "TARGET_HARD_FLOAT" "* { mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn)); @@ -2943,11 +4504,11 @@ 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" "")))] - "" + "TARGET_HARD_FLOAT" "* { mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn)); @@ -2959,11 +4520,11 @@ 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" "")))] - "" + "TARGET_HARD_FLOAT" "* { mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn)); @@ -2975,11 +4536,11 @@ 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" "")))] - "" + "TARGET_HARD_FLOAT" "* { mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn)); @@ -3035,6 +4596,51 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) +(define_insn "branch_zero_di" + [(set (pc) + (if_then_else (match_operator:DI 0 "cmp_op" + [(match_operand:DI 1 "register_operand" "d") + (const_int 0)]) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "* +{ + mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn)); + if (operands[2] != pc_rtx) + { /* normal jump */ + switch (GET_CODE (operands[0])) + { + case EQ: return \"%*beq%?\\t%z1,%.,%2\"; + case NE: return \"%*bne%?\\t%z1,%.,%2\"; + case GTU: return \"%*bne%?\\t%z1,%.,%2\"; + case LEU: return \"%*beq%?\\t%z1,%.,%2\"; + case GEU: return \"%*j\\t%2\"; + case LTU: return \"%*bne%?\\t%.,%.,%2\"; + } + + return \"%*b%C0z%?\\t%z1,%2\"; + } + else + { /* inverted jump */ + switch (GET_CODE (operands[0])) + { + case EQ: return \"%*bne%?\\t%z1,%.,%3\"; + case NE: return \"%*beq%?\\t%z1,%.,%3\"; + case GTU: return \"%*beq%?\\t%z1,%.,%3\"; + case LEU: return \"%*bne%?\\t%z1,%.,%3\"; + case GEU: return \"%*beq%?\\t%.,%.,%3\"; + case LTU: return \"%*j\\t%3\"; + } + + return \"%*b%N0z%?\\t%z1,%3\"; + } +}" + [(set_attr "type" "branch") + (set_attr "mode" "none") + (set_attr "length" "1")]) + + (define_insn "branch_equality" [(set (pc) (if_then_else (match_operator:SI 0 "equality_op" @@ -3055,6 +4661,26 @@ move\\t%0,%z4\\n\\ (set_attr "length" "1")]) +(define_insn "branch_equality_di" + [(set (pc) + (if_then_else (match_operator:DI 0 "equality_op" + [(match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d")]) + (match_operand 3 "pc_or_label_operand" "") + (match_operand 4 "pc_or_label_operand" "")))] + "" + "* +{ + mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn)); + return (operands[3] != pc_rtx) + ? \"%*b%C0%?\\t%z1,%z2,%3\" + : \"%*b%N0%?\\t%z1,%z2,%4\"; +}" + [(set_attr "type" "branch") + (set_attr "mode" "none") + (set_attr "length" "1")]) + + (define_expand "beq" [(set (pc) (if_then_else (eq:CC_EQ (cc0) @@ -3231,14 +4857,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (EQ, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3257,10 +4883,20 @@ move\\t%0,%z4\\n\\ (const_int 0)))] "" "sltu\\t%0,%1,1" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "seq_di_zero" + [(set (match_operand:DI 0 "register_operand" "=d") + (eq:DI (match_operand:DI 1 "register_operand" "d") + (const_int 0)))] + "TARGET_64BIT" + "sltu\\t%0,%1,1" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_insn "seq_si" [(set (match_operand:SI 0 "register_operand" "=d,d") (eq:SI (match_operand:SI 1 "register_operand" "%d,d") @@ -3269,7 +4905,7 @@ move\\t%0,%z4\\n\\ "@ xor\\t%0,%1,%2\;sltu\\t%0,%0,1 xori\\t%0,%1,%2\;sltu\\t%0,%0,1" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "2")]) @@ -3287,6 +4923,32 @@ move\\t%0,%z4\\n\\ (const_int 1)))] "") +(define_insn "seq_di" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (eq:DI (match_operand:DI 1 "register_operand" "%d,d") + (match_operand:DI 2 "uns_arith_operand" "d,K")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE" + "@ + xor\\t%0,%1,%2\;sltu\\t%0,%0,1 + xori\\t%0,%1,%2\;sltu\\t%0,%0,1" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (eq:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "uns_arith_operand" "")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE + && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)" + [(set (match_dup 0) + (xor:DI (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (ltu:DI (match_dup 0) + (const_int 1)))] + "") + (define_expand "sne" [(set (match_operand:SI 0 "register_operand" "=d") (ne:SI (match_dup 1) @@ -3294,14 +4956,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (NE, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3319,10 +4981,20 @@ move\\t%0,%z4\\n\\ (const_int 0)))] "" "sltu\\t%0,%.,%1" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "sne_di_zero" + [(set (match_operand:DI 0 "register_operand" "=d") + (ne:DI (match_operand:DI 1 "register_operand" "d") + (const_int 0)))] + "TARGET_64BIT" + "sltu\\t%0,%.,%1" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_insn "sne_si" [(set (match_operand:SI 0 "register_operand" "=d,d") (ne:SI (match_operand:SI 1 "register_operand" "%d,d") @@ -3331,7 +5003,7 @@ move\\t%0,%z4\\n\\ "@ xor\\t%0,%1,%2\;sltu\\t%0,%.,%0 xori\\t%0,%1,%x2\;sltu\\t%0,%.,%0" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "2")]) @@ -3349,6 +5021,32 @@ move\\t%0,%z4\\n\\ (const_int 0)))] "") +(define_insn "sne_di" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (ne:DI (match_operand:DI 1 "register_operand" "%d,d") + (match_operand:DI 2 "uns_arith_operand" "d,K")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE" + "@ + xor\\t%0,%1,%2\;sltu\\t%0,%.,%0 + xori\\t%0,%1,%x2\;sltu\\t%0,%.,%0" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ne:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "uns_arith_operand" "")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE + && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)" + [(set (match_dup 0) + (xor:DI (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (gtu:DI (match_dup 0) + (const_int 0)))] + "") + (define_expand "sgt" [(set (match_operand:SI 0 "register_operand" "=d") (gt:SI (match_dup 1) @@ -3356,14 +5054,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (GT, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3381,10 +5079,20 @@ move\\t%0,%z4\\n\\ (match_operand:SI 2 "reg_or_0_operand" "dJ")))] "" "slt\\t%0,%z2,%1" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "sgt_di" + [(set (match_operand:DI 0 "register_operand" "=d") + (gt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "reg_or_0_operand" "dJ")))] + "TARGET_64BIT" + "slt\\t%0,%z2,%1" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_expand "sge" [(set (match_operand:SI 0 "register_operand" "=d") (ge:SI (match_dup 1) @@ -3392,14 +5100,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (GE, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3414,7 +5122,7 @@ move\\t%0,%z4\\n\\ (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_DEBUG_C_MODE" "slt\\t%0,%1,%2\;xori\\t%0,%0,0x0001" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "2")]) @@ -3431,6 +5139,29 @@ move\\t%0,%z4\\n\\ (const_int 1)))] "") +(define_insn "sge_di" + [(set (match_operand:DI 0 "register_operand" "=d") + (ge:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "arith_operand" "dI")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE" + "slt\\t%0,%1,%2\;xori\\t%0,%0,0x0001" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ge:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "arith_operand" "")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE" + [(set (match_dup 0) + (lt:DI (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (xor:DI (match_dup 0) + (const_int 1)))] + "") + (define_expand "slt" [(set (match_operand:SI 0 "register_operand" "=d") (lt:SI (match_dup 1) @@ -3438,14 +5169,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (LT, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3460,10 +5191,20 @@ move\\t%0,%z4\\n\\ (match_operand:SI 2 "arith_operand" "dI")))] "" "slt\\t%0,%1,%2" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "slt_di" + [(set (match_operand:DI 0 "register_operand" "=d") + (lt:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "arith_operand" "dI")))] + "TARGET_64BIT" + "slt\\t%0,%1,%2" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_expand "sle" [(set (match_operand:SI 0 "register_operand" "=d") (le:SI (match_dup 1) @@ -3471,14 +5212,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (LE, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3500,17 +5241,31 @@ move\\t%0,%z4\\n\\ operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2])+1); return \"slt\\t%0,%1,%2\"; }" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "sle_di_const" + [(set (match_operand:DI 0 "register_operand" "=d") + (le:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "small_int" "I")))] + "TARGET_64BIT && INTVAL (operands[2]) < 32767" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2])+1); + return \"slt\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_insn "sle_si_reg" [(set (match_operand:SI 0 "register_operand" "=d") (le:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")))] "TARGET_DEBUG_C_MODE" "slt\\t%0,%z2,%1\;xori\\t%0,%0,0x0001" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "2")]) @@ -3527,6 +5282,29 @@ move\\t%0,%z4\\n\\ (const_int 1)))] "") +(define_insn "sle_di_reg" + [(set (match_operand:DI 0 "register_operand" "=d") + (le:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE" + "slt\\t%0,%z2,%1\;xori\\t%0,%0,0x0001" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (le:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" "")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE" + [(set (match_dup 0) + (lt:DI (match_dup 2) + (match_dup 1))) + (set (match_dup 0) + (xor:DI (match_dup 0) + (const_int 1)))] + "") + (define_expand "sgtu" [(set (match_operand:SI 0 "register_operand" "=d") (gtu:SI (match_dup 1) @@ -3534,14 +5312,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (GTU, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3559,10 +5337,20 @@ move\\t%0,%z4\\n\\ (match_operand:SI 2 "reg_or_0_operand" "dJ")))] "" "sltu\\t%0,%z2,%1" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "sgtu_di" + [(set (match_operand:DI 0 "register_operand" "=d") + (gtu:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "reg_or_0_operand" "dJ")))] + "TARGET_64BIT" + "sltu\\t%0,%z2,%1" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_expand "sgeu" [(set (match_operand:SI 0 "register_operand" "=d") (geu:SI (match_dup 1) @@ -3570,14 +5358,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (GEU, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3592,7 +5380,7 @@ move\\t%0,%z4\\n\\ (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_DEBUG_C_MODE" "sltu\\t%0,%1,%2\;xori\\t%0,%0,0x0001" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "2")]) @@ -3609,6 +5397,29 @@ move\\t%0,%z4\\n\\ (const_int 1)))] "") +(define_insn "sgeu_di" + [(set (match_operand:DI 0 "register_operand" "=d") + (geu:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "arith_operand" "dI")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE" + "sltu\\t%0,%1,%2\;xori\\t%0,%0,0x0001" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (geu:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "arith_operand" "")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE" + [(set (match_dup 0) + (ltu:DI (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (xor:DI (match_dup 0) + (const_int 1)))] + "") + (define_expand "sltu" [(set (match_operand:SI 0 "register_operand" "=d") (ltu:SI (match_dup 1) @@ -3616,14 +5427,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (LTU, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3638,10 +5449,20 @@ move\\t%0,%z4\\n\\ (match_operand:SI 2 "arith_operand" "dI")))] "" "sltu\\t%0,%1,%2" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "sltu_di" + [(set (match_operand:DI 0 "register_operand" "=d") + (ltu:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "arith_operand" "dI")))] + "TARGET_64BIT" + "sltu\\t%0,%1,%2" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_expand "sleu" [(set (match_operand:SI 0 "register_operand" "=d") (leu:SI (match_dup 1) @@ -3649,14 +5470,14 @@ move\\t%0,%z4\\n\\ "" " { - if (branch_type != CMP_SI) + if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI)) FAIL; /* set up operands from compare. */ operands[1] = branch_cmp[0]; operands[2] = branch_cmp[1]; - if (!TARGET_DEBUG_C_MODE) + if (TARGET_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (LEU, operands[0], operands[1], operands[2], (int *)0); DONE; @@ -3678,17 +5499,31 @@ move\\t%0,%z4\\n\\ operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2])+1); return \"sltu\\t%0,%1,%2\"; }" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "1")]) +(define_insn "sleu_di_const" + [(set (match_operand:DI 0 "register_operand" "=d") + (leu:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "small_int" "I")))] + "TARGET_64BIT && INTVAL (operands[2]) < 32767" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2])+1); + return \"sltu\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "1")]) + (define_insn "sleu_si_reg" [(set (match_operand:SI 0 "register_operand" "=d") (leu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")))] "TARGET_DEBUG_C_MODE" "sltu\\t%0,%z2,%1\;xori\\t%0,%0,0x0001" - [(set_attr "type" "arith") + [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "2")]) @@ -3705,6 +5540,29 @@ move\\t%0,%z4\\n\\ (const_int 1)))] "") +(define_insn "sleu_di_reg" + [(set (match_operand:DI 0 "register_operand" "=d") + (leu:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE" + "sltu\\t%0,%z2,%1\;xori\\t%0,%0,0x0001" + [(set_attr "type" "arith") + (set_attr "mode" "DI") + (set_attr "length" "2")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (leu:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" "")))] + "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE" + [(set (match_dup 0) + (ltu:DI (match_dup 2) + (match_dup 1))) + (set (match_dup 0) + (xor:DI (match_dup 0) + (const_int 1)))] + "") + ;; ;; .................... @@ -3714,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_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -3732,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_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -3750,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_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -3768,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_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -3786,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_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -3804,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_DOUBLE_FLOAT" "* { rtx xoperands[10]; @@ -3822,10 +5680,10 @@ 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" "* { rtx xoperands[10]; @@ -3840,10 +5698,10 @@ 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" "* { rtx xoperands[10]; @@ -3858,10 +5716,10 @@ 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" "* { rtx xoperands[10]; @@ -3876,10 +5734,10 @@ 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" "* { rtx xoperands[10]; @@ -3894,10 +5752,10 @@ 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" "* { rtx xoperands[10]; @@ -3912,10 +5770,10 @@ 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" "* { rtx xoperands[10]; @@ -3947,30 +5805,117 @@ 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") (set_attr "mode" "none") (set_attr "length" "1")]) -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "register_operand" "d"))] +(define_expand "indirect_jump" + [(set (pc) (match_operand 0 "register_operand" "d"))] "" + " +{ + rtx dest; + + if (operands[0]) /* eliminate unused code warnings */ + { + dest = operands[0]; + if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode) + operands[0] = copy_to_mode_reg (Pmode, dest); + + if (!TARGET_LONG64) + emit_jump_insn (gen_indirect_jump_internal1 (operands[0])); + else + emit_jump_insn (gen_indirect_jump_internal2 (operands[0])); + + DONE; + } +}") + +(define_insn "indirect_jump_internal1" + [(set (pc) (match_operand:SI 0 "register_operand" "d"))] + "!TARGET_LONG64" + "%*j\\t%0" + [(set_attr "type" "jump") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +(define_insn "indirect_jump_internal2" + [(set (pc) (match_operand:DI 0 "register_operand" "d"))] + "TARGET_LONG64" "%*j\\t%0" [(set_attr "type" "jump") (set_attr "mode" "none") (set_attr "length" "1")]) -(define_insn "tablejump" +(define_expand "tablejump" [(set (pc) - (match_operand:SI 0 "register_operand" "d")) + (match_operand 0 "register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] "" - "%*j\\t%0" + " +{ + rtx dest; + + if (operands[0]) /* eliminate unused code warnings */ + { + if (GET_MODE (operands[0]) != Pmode) + abort (); + + if (!TARGET_LONG64) + emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejump_internal2 (operands[0], operands[1])); + + DONE; + } +}") + +(define_insn "tablejump_internal1" + [(set (pc) + (match_operand:SI 0 "register_operand" "d")) + (use (label_ref (match_operand 1 "" "")))] + "!TARGET_LONG64" + "* +{ + /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */ + if (TARGET_ABICALLS && (! ABI_64BIT || mips_isa < 3)) + output_asm_insn (\".cpadd\\t%0\", operands); + return \"%*j\\t%0\"; +}" [(set_attr "type" "jump") (set_attr "mode" "none") - (set_attr "length" "1")]) + (set (attr "length") + (if_then_else (eq_attr "abicalls" "yes") + (const_int 2) + (const_int 1)))]) + +(define_insn "tablejump_internal2" + [(set (pc) + (match_operand:DI 0 "register_operand" "d")) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_LONG64" + "* +{ + /* .cpdadd expands to dadd REG,REG,$gp when pic, and nothing when not pic. */ + /* ??? 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") + (set_attr "mode" "none") + (set (attr "length") + (if_then_else (eq_attr "abicalls" "yes") + (const_int 2) + (const_int 1)))]) ;; Function return, only allow after optimization, so that we can ;; eliminate jumps to jumps if no stack space is used. @@ -3995,6 +5940,83 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "none") (set_attr "length" "1")]) +;; Implement a switch statement when generating embedded PIC code. +;; Switches are implemented by `tablejump' when not using -membedded-pic. + +(define_expand "casesi" + [(set (match_dup 5) + (minus:SI (match_operand:SI 0 "register_operand" "d") + (match_operand:SI 1 "arith_operand" "dI"))) + (set (cc0) + (compare:CC (match_dup 5) + (match_operand:SI 2 "arith_operand" ""))) + (set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 4 "" "")) + (pc))) + (parallel + [(set (pc) + (mem:SI (plus:SI (mult:SI (match_dup 5) + (const_int 4)) + (label_ref (match_operand 3 "" ""))))) + (clobber (match_scratch:SI 6 "")) + (clobber (reg:SI 31))])] + "TARGET_EMBEDDED_PIC" + " +{ + /* We need slightly different code for eight byte table entries. */ + if (TARGET_LONG64) + abort (); + + if (operands[0]) + { + rtx reg = gen_reg_rtx (SImode); + + /* If the index is too large, go to the default label. */ + emit_insn (gen_subsi3 (reg, operands[0], operands[1])); + emit_insn (gen_cmpsi (reg, operands[2])); + emit_insn (gen_bgtu (operands[4])); + + /* Do the PIC jump. */ + emit_insn (gen_casesi_internal (reg, operands[3], gen_reg_rtx (SImode))); + + DONE; + } +}") + +;; An embedded PIC switch statement looks like this: +;; bal $LS1 +;; sll $reg,$index,2 +;; $LS1: +;; addu $reg,$reg,$31 +;; lw $reg,$L1-$LS1($reg) +;; addu $reg,$reg,$31 +;; j $reg +;; $L1: +;; .word case1-$LS1 +;; .word case2-$LS1 +;; ... + +(define_insn "casesi_internal" + [(set (pc) + (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "d") + (const_int 4)) + (label_ref (match_operand 1 "" ""))))) + (clobber (match_operand:SI 2 "register_operand" "d")) + (clobber (reg:SI 31))] + "TARGET_EMBEDDED_PIC" + "* +{ + output_asm_insn (\"%(bal\\t%S1\;sll\\t%0,2\\n%S1:\", operands); + output_asm_insn (\"addu\\t%0,%0,$31%)\", operands); + output_asm_insn (\"lw\\t%0,%1-%S1(%0)\;addu\\t%0,%0,$31\", operands); + return \"j\\t%0\"; +}" + [(set_attr "type" "jump") + (set_attr "mode" "none") + (set_attr "length" "6")]) + ;; ;; .................... @@ -4043,6 +6065,20 @@ move\\t%0,%z4\\n\\ ;; } ;; }") +;; When generating embedded PIC code we need to get the address of the +;; current function. This specialized instruction does just that. + +(define_insn "get_fnaddr" + [(set (match_operand 0 "register_operand" "=d") + (unspec [(match_operand 1 "" "")] 1)) + (clobber (reg:SI 31))] + "TARGET_EMBEDDED_PIC + && GET_CODE (operands[1]) == SYMBOL_REF" + "%($LF%= = . + 8\;bal\\t$LF%=\;la\\t%0,%1-$LF%=%)\;addu\\t%0,%0,$31" + [(set_attr "type" "call") + (set_attr "mode" "none") + (set_attr "length" "4")]) + ;; ;; .................... @@ -4089,7 +6125,7 @@ move\\t%0,%z4\\n\\ } emit_call_insn (gen_call_internal1 (operands[0], operands[1], - gen_rtx (REG, Pmode, GP_REG_FIRST + 31))); + gen_rtx (REG, SImode, GP_REG_FIRST + 31))); DONE; } }") @@ -4109,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 @@ -4153,21 +6189,31 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "none") (set_attr "length" "2")]) -(define_insn "call_internal3" +(define_insn "call_internal3a" [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=d"))] - "!TARGET_ABICALLS && TARGET_LONG_CALLS" + "!TARGET_LONG64 && !TARGET_ABICALLS && TARGET_LONG_CALLS" "%*jal\\t%2,%0" [(set_attr "type" "call") (set_attr "mode" "none") (set_attr "length" "1")]) -(define_insn "call_internal4" +(define_insn "call_internal3b" + [(call (mem:DI (match_operand:DI 0 "register_operand" "r")) + (match_operand 1 "" "i")) + (clobber (match_operand:SI 2 "register_operand" "=d"))] + "TARGET_LONG64 && !TARGET_ABICALLS && TARGET_LONG_CALLS" + "%*jal\\t%2,%0" + [(set_attr "type" "call") + (set_attr "mode" "none") + (set_attr "length" "1")]) + +(define_insn "call_internal4a" [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=d"))] - "TARGET_ABICALLS && TARGET_LONG_CALLS" + "!TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS" "* { if (REGNO (operands[0]) != PIC_FUNCTION_ADDR_REGNUM) @@ -4179,6 +6225,21 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "none") (set_attr "length" "2")]) +(define_insn "call_internal4b" + [(call (mem:DI (match_operand:DI 0 "register_operand" "r")) + (match_operand 1 "" "i")) + (clobber (match_operand:SI 2 "register_operand" "=d"))] + "TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS" + "* +{ + if (REGNO (operands[0]) != PIC_FUNCTION_ADDR_REGNUM) + return \"move\\t%^,%0\\n\\tjal\\t%2,%^\"; + else + return \"jal\\t%2,%0\"; +}" + [(set_attr "type" "call") + (set_attr "mode" "none") + (set_attr "length" "2")]) ;; calls.c now passes a fourth argument, make saber happy @@ -4218,7 +6279,7 @@ move\\t%0,%z4\\n\\ } emit_call_insn (gen_call_value_internal1 (operands[0], operands[1], operands[2], - gen_rtx (REG, Pmode, GP_REG_FIRST + 31))); + gen_rtx (REG, SImode, GP_REG_FIRST + 31))); DONE; } @@ -4241,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 @@ -4286,23 +6347,51 @@ move\\t%0,%z4\\n\\ (set_attr "mode" "none") (set_attr "length" "2")]) -(define_insn "call_value_internal3" +(define_insn "call_value_internal3a" [(set (match_operand 0 "register_operand" "=df") (call (mem:SI (match_operand:SI 1 "register_operand" "r")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "!TARGET_ABICALLS && TARGET_LONG_CALLS" + "!TARGET_LONG64 && !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_internal3b" + [(set (match_operand 0 "register_operand" "=df") + (call (mem:DI (match_operand:DI 1 "register_operand" "r")) + (match_operand 2 "" "i"))) + (clobber (match_operand:SI 3 "register_operand" "=d"))] + "TARGET_LONG64 && !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_internal4" +(define_insn "call_value_internal4a" [(set (match_operand 0 "register_operand" "=df") (call (mem:SI (match_operand:SI 1 "register_operand" "r")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] - "TARGET_ABICALLS && TARGET_LONG_CALLS" + "!TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS" + "* +{ + if (REGNO (operands[1]) != PIC_FUNCTION_ADDR_REGNUM) + return \"move\\t%^,%1\\n\\tjal\\t%3,%^\"; + else + return \"jal\\t%3,%1\"; +}" + [(set_attr "type" "call") + (set_attr "mode" "none") + (set_attr "length" "2")]) + +(define_insn "call_value_internal4b" + [(set (match_operand 0 "register_operand" "=df") + (call (mem:DI (match_operand:DI 1 "register_operand" "r")) + (match_operand 2 "" "i"))) + (clobber (match_operand:SI 3 "register_operand" "=d"))] + "TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS" "* { if (REGNO (operands[1]) != PIC_FUNCTION_ADDR_REGNUM) @@ -4369,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.