gcc/gcc/config/mips/mips.md

339 KiB
Raw Blame History

;; Mips.md Machine Description for MIPS based processors ;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, ;; 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. ;; Contributed by A. Lichnewsky, lich@inria.inria.fr ;; Changes by Michael Meissner, meissner@osf.org ;; 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and ;; Brendan Eich, brendan@microunity.com.

;; This file is part of GNU CC.

;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version.

;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details.

;; 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, 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA.

;; ??? Currently does not have define_function_unit support for the R8000. ;; Must include new entries for fmadd in addition to existing entries.

(define_constants [(UNSPEC_ULW 0) (UNSPEC_USW 1) (UNSPEC_ULD 2) (UNSPEC_USD 3) (UNSPEC_GET_FNADDR 4) (UNSPEC_HILO_DELAY 5) (UNSPEC_BLOCKAGE 6) (UNSPEC_LOADGP 7) (UNSPEC_SETJMP 8) (UNSPEC_LONGJMP 9) (UNSPEC_EH_RECEIVER 10) (UNSPEC_EH_RETURN 11) (UNSPEC_CONSTTABLE_QI 12) (UNSPEC_CONSTTABLE_HI 13) (UNSPEC_CONSTTABLE_SI 14) (UNSPEC_CONSTTABLE_DI 15) (UNSPEC_CONSTTABLE_SF 16) (UNSPEC_CONSTTABLE_DF 17) (UNSPEC_ALIGN_2 18) (UNSPEC_ALIGN_4 19) (UNSPEC_ALIGN_8 20)])

;; .................... ;; ;; Attributes ;; ;; ....................

;; Classification of each insn. ;; branch conditional branch ;; jump unconditional jump ;; call unconditional call ;; load load instruction(s) ;; store store instruction(s) ;; move data movement within same register set ;; xfer transfer to/from coprocessor ;; hilo transfer of hi/lo registers ;; arith integer arithmetic instruction ;; darith double precision integer arithmetic instructions ;; imul integer multiply ;; imadd integer multiply-add ;; idiv integer divide ;; 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 ;; fcmp floating point compare ;; fcvt floating point convert ;; fsqrt floating point square root ;; frsqrt floating point reciprocal square root ;; multi multiword sequence (or user asm statements) ;; nop no operation

(define_attr "type" "unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,imadd,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,multi,nop" (const_string "unknown"))

;; Main data type used by the insn (define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF,FPSW" (const_string "unknown"))

;; Length (in # of bytes). A conditional branch is allowed only to a ;; location within a signed 18-bit offset of the delay slot. If that ;; provides too smal a range, we use the `j' instruction. This ;; instruction takes a 28-bit value, but that value is not an offset. ;; Instead, it's bitwise-ored with the high-order four bits of the ;; instruction in the delay slot, which means it cannot be used to ;; cross a 256MB boundary. We could fall back back on the jr, ;; instruction which allows full access to the entire address space, ;; but we do not do so at present.

(define_attr "length" "" (cond [(eq_attr "type" "branch") (cond [(lt (abs (minus (match_dup 1) (plus (pc) (const_int 4)))) (const_int 131072)) (const_int 4) (ne (symbol_ref "flag_pic && ! TARGET_EMBEDDED_PIC") (const_int 0)) (const_int 24) ] (const_int 12)) ] (const_int 4)))

;; Attribute describing the processor. This attribute must match exactly ;; with the processor_type enumeration in mips.h.

;; Attribute describing the processor ;; (define_attr "cpu" "default,r3000,r6000,r4000" ;; (const ;; (cond [(eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R3000")) (const_string "r3000") ;; (eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R4000")) (const_string "r4000") ;; (eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R6000")) (const_string "r6000")] ;; (const_string "default"))))

;; ??? Fix everything that tests this attribute. (define_attr "cpu" "default,4kc,5kc,20kc,m4k,r3000,r3900,r6000,r4000,r4100,r4111,r4120,r4300,r4600,r4650,r5000,r5400,r5500,r8000,sb1,sr71000" (const (symbol_ref "mips_cpu_attr")))

;; Does the instruction have a mandatory delay slot? ;; The 3900, is (mostly) mips1, but does not have a mandatory load delay ;; slot. (define_attr "dslot" "no,yes" (if_then_else (ior (eq_attr "type" "branch,jump,call,xfer,hilo,fcmp") (and (eq_attr "type" "load") (and (eq (symbol_ref "mips_isa") (const_int 1)) (and (eq (symbol_ref "mips16") (const_int 0)) (eq_attr "cpu" "!r3900"))))) (const_string "yes") (const_string "no")))

;; Can the instruction be put into a delay slot? (define_attr "can_delay" "no,yes" (if_then_else (and (eq_attr "dslot" "no") ; ADJUST_INSN_LENGTH divides length by 2 on mips16, ; so cope with it here. (ior (and (eq (symbol_ref "mips16") (const_int 0)) (eq_attr "length" "4")) (and (ne (symbol_ref "mips16") (const_int 0)) (eq_attr "length" "2")))) (const_string "yes") (const_string "no")))

;; Attribute defining whether or not we can use the branch-likely instructions

(define_attr "branch_likely" "no,yes" (const (if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0)) (const_string "yes") (const_string "no"))))

;; Describe a user's asm statement. (define_asm_attributes [(set_attr "type" "multi")])

;; whether or not generating calls to position independent functions (define_attr "abicalls" "no,yes" (const (symbol_ref "mips_abicalls_attr")))

;; ......................... ;; ;; Delay slots, can't describe load/fcmp/xfer delay slots here ;; ;; .........................

(define_delay (and (eq_attr "type" "branch") (eq (symbol_ref "mips16") (const_int 0))) [(eq_attr "can_delay" "yes") (nil) (and (eq_attr "branch_likely" "yes") (and (eq_attr "dslot" "no") (eq_attr "length" "4")))])

(define_delay (eq_attr "type" "jump") [(eq_attr "can_delay" "yes") (nil) (nil)])

(define_delay (and (eq_attr "type" "call") (eq_attr "abicalls" "no")) [(eq_attr "can_delay" "yes") (nil) (nil)])

;; ......................... ;; ;; Functional units ;; ;; .........................

; (define_function_unit NAME MULTIPLICITY SIMULTANEITY ; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])

;; 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,r3900,r4600,r4650,r4100,r4120,r4300,r5000")) 3 0)

(define_function_unit "memory" 1 0 (and (eq_attr "type" "load") (eq_attr "cpu" "r3000,r3900,r4600,r4650,r4100,r4120,r4300,r5000")) 2 0)

(define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0)

(define_function_unit "memory" 1 0 (eq_attr "type" "xfer") 2 0)

(define_function_unit "imuldiv" 1 0 (eq_attr "type" "hilo") 1 3)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4120,r4300,r5000")) 17 17)

;; On them mips16, we want to stronly discourage a mult from appearing ;; after an mflo, since that requires explicit nop instructions. We ;; do this by pretending that mflo ties up the function unit for long ;; enough that the scheduler will ignore load stalls and the like when ;; selecting instructions to between the two instructions.

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "hilo") (ne (symbol_ref "mips16") (const_int 0))) 1 5)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (eq_attr "cpu" "r3000,r3900")) 12 12)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (eq_attr "cpu" "r4000,r4600")) 10 10)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (eq_attr "cpu" "r4650")) 4 4)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100,r4120"))) 1 1)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100,r4120"))) 4 4)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300,r5000"))) 5 5)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300"))) 8 8)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul,imadd") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000"))) 9 9)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "!r3000,r3900,r4000,r4600,r4650,r4100,r4120,r4300,r5000")) 38 38)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "r3000,r3900")) 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 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "r4000")) 69 69)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100,r4120"))) 35 35)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100,r4120"))) 67 67)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300"))) 37 37)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300"))) 69 69)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (and (eq_attr "mode" "SI") (eq_attr "cpu" "r5000"))) 36 36)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000"))) 68 68)

;; The R4300 does NOT have a separate Floating Point Unit, instead ;; the FP hardware is part of the normal ALU circuitry. This means FP ;; instructions affect the pipe-line, and no functional unit ;; parallelism can occur on R4300 processors. To force GCC into coding ;; for only a single functional unit, we force the R4300 FP ;; instructions to be processed in the "imuldiv" unit.

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r3900,r6000,r4300,r5000")) 3 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r3000,r3900,r6000")) 2 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fcmp") (eq_attr "cpu" "r5000")) 1 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r3900,r6000,r4300")) 4 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fadd") (eq_attr "cpu" "r3000,r3900")) 2 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fadd") (eq_attr "cpu" "r6000")) 3 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "!r3000,r3900,r4600,r4650,r4300,r5000")) 2 0)

(define_function_unit "adder" 1 1 (and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000,r3900,r4600,r4650,r5000")) 1 0)

(define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000"))) 7 0)

(define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000,r3900,r5000"))) 4 0)

(define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000"))) 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,r3900,r6000,r4300,r5000"))) 8 0)

(define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000,r3900,r5000"))) 5 0)

(define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000"))) 6 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300,r5000"))) 23 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000,r3900"))) 12 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000"))) 15 0)

(define_function_unit "divide" 1 1 (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" "SF") (eq_attr "cpu" "r5000"))) 21 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r3900,r6000,r4600,r4650,r4300"))) 36 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000,r3900"))) 19 0)

(define_function_unit "divide" 1 1 (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" "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,frsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000"))) 54 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650"))) 31 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000"))) 21 0)

;;; ??? Is this number right? (define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000"))) 112 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650"))) 60 0)

(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt,frsqrt") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r5000"))) 36 0)

;; R4300 FP instruction classes treated as part of the "imuldiv" ;; functional unit:

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "fadd") (eq_attr "cpu" "r4300")) 3 3)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "fcmp,fabs,fneg") (eq_attr "cpu" "r4300")) 1 1)

(define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4300"))) 5 5) (define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4300"))) 8 8)

(define_function_unit "imuldiv" 1 0 (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt,frsqrt")) (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4300"))) 29 29) (define_function_unit "imuldiv" 1 0 (and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt,frsqrt")) (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4300"))) 58 58) ;; The following functional units do not use the cpu type, and use ;; much less memory in genattrtab.c.

;; (define_function_unit "memory" 1 0 (eq_attr "type" "load") 3 0) ;; (define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0) ;; ;; (define_function_unit "fp_comp" 1 0 (eq_attr "type" "fcmp") 2 0) ;; ;; (define_function_unit "transfer" 1 0 (eq_attr "type" "xfer") 2 0) ;; (define_function_unit "transfer" 1 0 (eq_attr "type" "hilo") 3 0) ;; ;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "imul") 17 0) ;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "idiv") 38 0) ;; ;; (define_function_unit "adder" 1 1 (eq_attr "type" "fadd") 4 0) ;; (define_function_unit "adder" 1 1 (eq_attr "type" "fabs,fneg") 2 0) ;; ;; (define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (eq_attr "mode" "SF")) 7 0) ;; (define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (eq_attr "mode" "DF")) 8 0) ;; ;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "SF")) 23 0) ;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "DF")) 36 0) ;; ;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 0) ;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 0) ;; Include scheduling descriptions.

(include "5400.md") (include "5500.md") (include "sr71k.md")

;; ;; .................... ;; ;; CONDITIONAL TRAPS ;; ;; .................... ;;

(define_insn "trap" [(trap_if (const_int 1) (const_int 0))] "" "* { if (ISA_HAS_COND_TRAP) return "teq\t$0,$0"; else if (TARGET_MIPS16) return "break 0"; else return "break"; }")

(define_expand "conditional_trap" [(trap_if (match_operator 0 "cmp_op" [(match_dup 2) (match_dup 3)]) (match_operand 1 "const_int_operand" ""))] "ISA_HAS_COND_TRAP" " { mips_gen_conditional_trap (operands); DONE; }")

;; Match a TRAP_IF with 2nd arg of 0. The div_trap_* insns match a ;; 2nd arg of any CONST_INT, so this insn must appear first. ;; gen_div_trap always generates TRAP_IF with 2nd arg of 6 or 7.

(define_insn "" [(trap_if (match_operator 0 "trap_cmp_op" [(match_operand:SI 1 "reg_or_0_operand" "d") (match_operand:SI 2 "nonmemory_operand" "dI")]) (const_int 0))] "ISA_HAS_COND_TRAP" "t%C0\t%z1,%z2") ;; ;; .................... ;; ;; ADDITION ;; ;; .................... ;;

(define_insn "adddf3" [(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_DOUBLE_FLOAT" "add.d\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "DF")])

(define_insn "addsf3" [(set (match_operand:SF 0 "register_operand" "=f") (plus:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "add.s\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "SF")])

(define_expand "addsi3" [(set (match_operand:SI 0 "register_operand" "=d") (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") (match_operand:SI 2 "arith_operand" "dI")))] "" " { /* The mips16 assembler handles -32768 correctly, and so does gas, but some other MIPS assemblers think that -32768 needs to be loaded into a register before it can be added in. */ if (! TARGET_MIPS16 && ! TARGET_GAS && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768) operands[2] = force_reg (SImode, operands[2]);

/* If a large stack adjustment was forced into a register, we may be asked to generate rtx such as:

(set (reg:SI sp) (plus:SI (reg:SI sp) (reg:SI pseudo)))

 but no such instruction is available in mips16.  Handle it by
 using a temporary.  */

if (TARGET_MIPS16 && REGNO (operands[0]) == STACK_POINTER_REGNUM && ((GET_CODE (operands[1]) == REG && REGNO (operands[1]) != STACK_POINTER_REGNUM) || GET_CODE (operands[2]) != CONST_INT)) { rtx tmp = gen_reg_rtx (SImode);

  emit_move_insn (tmp, operands[1]);
  emit_insn (gen_addsi3 (tmp, tmp, operands[2]));
  emit_move_insn (operands[0], tmp);
  DONE;
}

}")

(define_insn "addsi3_internal" [(set (match_operand:SI 0 "register_operand" "=d") (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") (match_operand:SI 2 "arith_operand" "dI")))] "! TARGET_MIPS16 && (TARGET_GAS || GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" "addu\t%0,%z1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

;; For the mips16, we need to recognize stack pointer additions ;; explicitly, since we don't have a constraint for $sp. These insns ;; will be generated by the save_restore_insns functions.

(define_insn "" [(set (reg:SI 29) (plus:SI (reg:SI 29) (match_operand:SI 0 "small_int" "I")))] "TARGET_MIPS16" "addu\t%,%,%0" [(set_attr "type" "arith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (match_operand:VOID 0 "m16_simm8_8" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (plus:SI (reg:SI 29) (match_operand:SI 1 "small_int" "I")))] "TARGET_MIPS16" "addu\t%0,%$,%1" [(set_attr "type" "arith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (match_operand:VOID 1 "m16_uimm8_4" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (plus:SI (match_operand:SI 1 "register_operand" "0,d,d") (match_operand:SI 2 "arith_operand" "IQ,O,d")))] "TARGET_MIPS16 && (GET_CODE (operands[1]) != REG || REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER || M16_REG_P (REGNO (operands[1])) || REGNO (operands[1]) == ARG_POINTER_REGNUM || REGNO (operands[1]) == FRAME_POINTER_REGNUM || REGNO (operands[1]) == STACK_POINTER_REGNUM) && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) >= FIRST_PSEUDO_REGISTER || M16_REG_P (REGNO (operands[2])) || REGNO (operands[2]) == ARG_POINTER_REGNUM || REGNO (operands[2]) == FRAME_POINTER_REGNUM || REGNO (operands[2]) == STACK_POINTER_REGNUM)" "* { if (REGNO (operands[0]) == REGNO (operands[1])) return "addu\t%0,%2"; return "addu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_simm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 2 "m16_simm4_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; On the mips16, we can sometimes split an add of a constant which is ;; a 4 byte instruction into two adds which are both 2 byte ;; instructions. There are two cases: one where we are adding a ;; constant plus a register to another register, and one where we are ;; simply adding a constant to a register.

(define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) > 0x7f && INTVAL (operands[1]) <= 0x7f + 0x7f) || (INTVAL (operands[1]) < - 0x80 && INTVAL (operands[1]) >= - 0x80 - 0x80))" [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val >= 0) { operands[1] = GEN_INT (0x7f); operands[2] = GEN_INT (val - 0x7f); } else { operands[1] = GEN_INT (- 0x80); operands[2] = GEN_INT (val + 0x80); } }")

(define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && M16_REG_P (REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]) && GET_CODE (operands[2]) == CONST_INT && ((INTVAL (operands[2]) > 0x7 && INTVAL (operands[2]) <= 0x7 + 0x7f) || (INTVAL (operands[2]) < - 0x8 && INTVAL (operands[2]) >= - 0x8 - 0x80))" [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] " { HOST_WIDE_INT val = INTVAL (operands[2]);

if (val >= 0) { operands[2] = GEN_INT (0x7); operands[3] = GEN_INT (val - 0x7); } else { operands[2] = GEN_INT (- 0x8); operands[3] = GEN_INT (val + 0x8); } }")

(define_expand "adddi3" [(parallel [(set (match_operand:DI 0 "register_operand" "") (plus:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_arith_operand" ""))) (clobber (match_dup 3))])] "TARGET_64BIT || (!TARGET_DEBUG_G_MODE && !TARGET_MIPS16)" " { /* The mips16 assembler handles -32768 correctly, and so does gas, but some other MIPS assemblers think that -32768 needs to be loaded into a register before it can be added in. */ if (! TARGET_MIPS16 && ! TARGET_GAS && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768) operands[2] = force_reg (DImode, operands[2]);

/* If a large stack adjustment was forced into a register, we may be asked to generate rtx such as:

(set (reg:DI sp) (plus:DI (reg:DI sp) (reg:DI pseudo)))

 but no such instruction is available in mips16.  Handle it by
 using a temporary.  */

if (TARGET_MIPS16 && REGNO (operands[0]) == STACK_POINTER_REGNUM && ((GET_CODE (operands[1]) == REG && REGNO (operands[1]) != STACK_POINTER_REGNUM) || GET_CODE (operands[2]) != CONST_INT)) { rtx tmp = gen_reg_rtx (DImode);

  emit_move_insn (tmp, operands[1]);
  emit_insn (gen_addsi3 (tmp, tmp, operands[2]));
  emit_move_insn (operands[0], tmp);
  DONE;
}

if (TARGET_64BIT) { emit_insn (gen_adddi3_internal_3 (operands[0], operands[1], operands[2])); DONE; }

operands[3] = gen_reg_rtx (SImode); }")

(define_insn "adddi3_internal_1" [(set (match_operand:DI 0 "register_operand" "=d,&d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16" "* { return (REGNO (operands[0]) == REGNO (operands[1]) && REGNO (operands[0]) == REGNO (operands[2])) ? "srl\t%3,%L0,31;sll\t%M0,%M0,1;sll\t%L0,%L1,1;addu\t%M0,%M0,%3" : "addu\t%L0,%L1,%L2;sltu\t%3,%L0,%L2;addu\t%M0,%M1,%M2;addu\t%M0,%M0,%3"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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])) && (REGNO (operands[0]) != REGNO (operands[1]) || REGNO (operands[0]) != REGNO (operands[2]))"

[(set (subreg:SI (match_dup 0) 0) (plus:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))

(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 2) 0)))

(set (subreg:SI (match_dup 0) 4) (plus:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))

(set (subreg:SI (match_dup 0) 4) (plus:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))] "")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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])) && (REGNO (operands[0]) != REGNO (operands[1]) || REGNO (operands[0]) != REGNO (operands[2]))"

[(set (subreg:SI (match_dup 0) 4) (plus:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))

(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 2) 4)))

(set (subreg:SI (match_dup 0) 0) (plus:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))

(set (subreg:SI (match_dup 0) 0) (plus:SI (subreg:SI (match_dup 0) 0) (match_dup 3)))] "")

(define_insn "adddi3_internal_2" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && (TARGET_GAS || GET_CODE (operands[2]) != CONST_INT || 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 subu\t%L0,%L1,%n2;sltu\t%3,%L0,%2;subu\t%M0,%M1,1;addu\t%M0,%M0,%3" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "12,8,16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (plus: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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (subreg:SI (match_dup 0) 0) (plus:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))

(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 0) 0) (match_dup 2)))

(set (subreg:SI (match_dup 0) 4) (plus:SI (subreg:SI (match_dup 1) 4) (match_dup 3)))] "")

(define_split [(set (match_operand:DI 0 "register_operand" "") (plus: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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (subreg:SI (match_dup 0) 4) (plus:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))

(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 0) 4) (match_dup 2)))

(set (subreg:SI (match_dup 0) 0) (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 "se_reg_or_0_operand" "dJ") (match_operand:DI 2 "se_arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16 && (TARGET_GAS || 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")])

;; For the mips16, we need to recognize stack pointer additions ;; explicitly, since we don't have a constraint for $sp. These insns ;; will be generated by the save_restore_insns functions.

(define_insn "" [(set (reg:DI 29) (plus:DI (reg:DI 29) (match_operand:DI 0 "small_int" "I")))] "TARGET_MIPS16 && TARGET_64BIT" "daddu\t%,%,%0" [(set_attr "type" "arith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (match_operand:VOID 0 "m16_simm8_8" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (plus:DI (reg:DI 29) (match_operand:DI 1 "small_int" "I")))] "TARGET_MIPS16 && TARGET_64BIT" "daddu\t%0,%$,%1" [(set_attr "type" "arith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (match_operand:VOID 0 "m16_uimm5_4" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (plus:DI (match_operand:DI 1 "register_operand" "0,d,d") (match_operand:DI 2 "arith_operand" "IQ,O,d")))] "TARGET_MIPS16 && TARGET_64BIT && (GET_CODE (operands[1]) != REG || REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER || M16_REG_P (REGNO (operands[1])) || REGNO (operands[1]) == ARG_POINTER_REGNUM || REGNO (operands[1]) == FRAME_POINTER_REGNUM || REGNO (operands[1]) == STACK_POINTER_REGNUM) && (GET_CODE (operands[2]) != REG || REGNO (operands[2]) >= FIRST_PSEUDO_REGISTER || M16_REG_P (REGNO (operands[2])) || REGNO (operands[2]) == ARG_POINTER_REGNUM || REGNO (operands[2]) == FRAME_POINTER_REGNUM || REGNO (operands[2]) == STACK_POINTER_REGNUM)" "* { if (REGNO (operands[0]) == REGNO (operands[1])) return "daddu\t%0,%2"; return "daddu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_simm5_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 2 "m16_simm4_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; On the mips16, we can sometimes split an add of a constant which is ;; a 4 byte instruction into two adds which are both 2 byte ;; instructions. There are two cases: one where we are adding a ;; constant plus a register to another register, and one where we are ;; simply adding a constant to a register.

(define_split [(set (match_operand:DI 0 "register_operand" "") (plus:DI (match_dup 0) (match_operand:DI 1 "const_int_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) > 0xf && INTVAL (operands[1]) <= 0xf + 0xf) || (INTVAL (operands[1]) < - 0x10 && INTVAL (operands[1]) >= - 0x10 - 0x10))" [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val >= 0) { operands[1] = GEN_INT (0xf); operands[2] = GEN_INT (val - 0xf); } else { operands[1] = GEN_INT (- 0x10); operands[2] = GEN_INT (val + 0x10); } }")

(define_split [(set (match_operand:DI 0 "register_operand" "") (plus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "const_int_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && M16_REG_P (REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]) && GET_CODE (operands[2]) == CONST_INT && ((INTVAL (operands[2]) > 0x7 && INTVAL (operands[2]) <= 0x7 + 0xf) || (INTVAL (operands[2]) < - 0x8 && INTVAL (operands[2]) >= - 0x8 - 0x10))" [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2))) (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] " { HOST_WIDE_INT val = INTVAL (operands[2]);

if (val >= 0) { operands[2] = GEN_INT (0x7); operands[3] = GEN_INT (val - 0x7); } else { operands[2] = GEN_INT (- 0x8); operands[3] = GEN_INT (val + 0x8); } }")

(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 && !TARGET_MIPS16 && (TARGET_GAS || 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")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (sign_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "0,d,d") (match_operand:SI 2 "arith_operand" "I,O,d"))))] "TARGET_MIPS16 && TARGET_64BIT" "* { if (REGNO (operands[0]) == REGNO (operands[1])) return "addu\t%0,%2"; return "addu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_simm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 2 "m16_simm4_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; ;; .................... ;; ;; SUBTRACTION ;; ;; .................... ;;

(define_insn "subdf3" [(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_DOUBLE_FLOAT" "sub.d\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "DF")])

(define_insn "subsf3" [(set (match_operand:SF 0 "register_operand" "=f") (minus:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "sub.s\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "SF")])

(define_expand "subsi3" [(set (match_operand:SI 0 "register_operand" "=d") (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") (match_operand:SI 2 "arith_operand" "dI")))] "" " { if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) == -32768 || (TARGET_MIPS16 && INTVAL (operands[2]) == -0x4000))) operands[2] = force_reg (SImode, operands[2]); }")

(define_insn "subsi3_internal" [(set (match_operand:SI 0 "register_operand" "=d") (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") (match_operand:SI 2 "arith_operand" "dI")))] "!TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" "subu\t%0,%z1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

;; For the mips16, we need to recognize stack pointer subtractions ;; explicitly, since we don't have a constraint for $sp. These insns ;; will be generated by the save_restore_insns functions.

(define_insn "" [(set (reg:SI 29) (minus:SI (reg:SI 29) (match_operand:SI 0 "small_int" "I")))] "TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" "addu\t%,%,%n0" [(set_attr "type" "arith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (match_operand:VOID 0 "m16_nsimm8_8" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (minus:SI (reg:SI 29) (match_operand:SI 1 "small_int" "I")))] "TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" "addu\t%0,%$,%n1" [(set_attr "type" "arith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (match_operand:VOID 1 "m16_nuimm8_4" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (minus:SI (match_operand:SI 1 "register_operand" "0,d,d") (match_operand:SI 2 "arith_operand" "I,O,d")))] "TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || (INTVAL (operands[2]) != -32768 && INTVAL (operands[2]) != -0x4000))" "* { if (REGNO (operands[0]) == REGNO (operands[1])) return "subu\t%0,%2"; return "subu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_nsimm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 2 "m16_nsimm4_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; On the mips16, we can sometimes split a subtract of a constant ;; which is a 4 byte instruction into two adds which are both 2 byte ;; instructions. There are two cases: one where we are setting a ;; register to a register minus a constant, and one where we are ;; simply subtracting a constant from a register.

(define_split [(set (match_operand:SI 0 "register_operand" "") (minus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) > 0x80 && INTVAL (operands[1]) <= 0x80 + 0x80) || (INTVAL (operands[1]) < - 0x7f && INTVAL (operands[1]) >= - 0x7f - 0x7f))" [(set (match_dup 0) (minus:SI (match_dup 0) (match_dup 1))) (set (match_dup 0) (minus:SI (match_dup 0) (match_dup 2)))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val >= 0) { operands[1] = GEN_INT (0x80); operands[2] = GEN_INT (val - 0x80); } else { operands[1] = GEN_INT (- 0x7f); operands[2] = GEN_INT (val + 0x7f); } }")

(define_split [(set (match_operand:SI 0 "register_operand" "") (minus:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && M16_REG_P (REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]) && GET_CODE (operands[2]) == CONST_INT && ((INTVAL (operands[2]) > 0x8 && INTVAL (operands[2]) <= 0x8 + 0x80) || (INTVAL (operands[2]) < - 0x7 && INTVAL (operands[2]) >= - 0x7 - 0x7f))" [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (minus:SI (match_dup 0) (match_dup 3)))] " { HOST_WIDE_INT val = INTVAL (operands[2]);

if (val >= 0) { operands[2] = GEN_INT (0x8); operands[3] = GEN_INT (val - 0x8); } else { operands[2] = GEN_INT (- 0x7); operands[3] = GEN_INT (val + 0x7); } }")

(define_expand "subdi3" [(parallel [(set (match_operand:DI 0 "register_operand" "=d") (minus:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (clobber (match_dup 3))])] "TARGET_64BIT || (!TARGET_DEBUG_G_MODE && !TARGET_MIPS16)" " { 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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16" "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") (set_attr "length" "16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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]))"

[(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))

(set (subreg:SI (match_dup 0) 0) (minus:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))

(set (subreg:SI (match_dup 0) 4) (minus:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))

(set (subreg:SI (match_dup 0) 4) (minus:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))] "")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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]))"

[(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))

(set (subreg:SI (match_dup 0) 4) (minus:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))

(set (subreg:SI (match_dup 0) 0) (minus:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))

(set (subreg:SI (match_dup 0) 0) (minus:SI (subreg:SI (match_dup 0) 0) (match_dup 3)))] "")

(define_insn "subdi3_internal_2" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 sltu\t%3,%L1,%2;subu\t%L0,%L1,%2;subu\t%M0,%M1,1;subu\t%M0,%M0,%3" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "12,8,16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))

(set (subreg:SI (match_dup 0) 0) (minus:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))

(set (subreg:SI (match_dup 0) 4) (minus:SI (subreg:SI (match_dup 1) 4) (match_dup 3)))] "")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (match_dup 3) (ltu:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))

(set (subreg:SI (match_dup 0) 4) (minus:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))

(set (subreg:SI (match_dup 0) 0) (minus:SI (subreg:SI (match_dup 1) 0) (match_dup 3)))] "")

(define_insn "subdi3_internal_3" [(set (match_operand:DI 0 "register_operand" "=d") (minus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ") (match_operand:DI 2 "se_arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16 && (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")])

;; For the mips16, we need to recognize stack pointer subtractions ;; explicitly, since we don't have a constraint for $sp. These insns ;; will be generated by the save_restore_insns functions.

(define_insn "" [(set (reg:DI 29) (minus:DI (reg:DI 29) (match_operand:DI 0 "small_int" "I")))] "TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" "daddu\t%,%,%n0" [(set_attr "type" "arith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (match_operand:VOID 0 "m16_nsimm8_8" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (minus:DI (reg:DI 29) (match_operand:DI 1 "small_int" "I")))] "TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)" "daddu\t%0,%$,%n1" [(set_attr "type" "arith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (match_operand:VOID 0 "m16_nuimm5_4" "") (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (minus:DI (match_operand:DI 1 "register_operand" "0,d,d") (match_operand:DI 2 "arith_operand" "I,O,d")))] "TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || (INTVAL (operands[2]) != -32768 && INTVAL (operands[2]) != -0x4000))" "* { if (REGNO (operands[0]) == REGNO (operands[1])) return "dsubu\t%0,%2"; return "dsubu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_nsimm5_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 2 "m16_nsimm4_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; On the mips16, we can sometimes split an add of a constant which is ;; a 4 byte instruction into two adds which are both 2 byte ;; instructions. There are two cases: one where we are adding a ;; constant plus a register to another register, and one where we are ;; simply adding a constant to a register.

(define_split [(set (match_operand:DI 0 "register_operand" "") (minus:DI (match_dup 0) (match_operand:DI 1 "const_int_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) > 0x10 && INTVAL (operands[1]) <= 0x10 + 0x10) || (INTVAL (operands[1]) < - 0xf && INTVAL (operands[1]) >= - 0xf - 0xf))" [(set (match_dup 0) (minus:DI (match_dup 0) (match_dup 1))) (set (match_dup 0) (minus:DI (match_dup 0) (match_dup 2)))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val >= 0) { operands[1] = GEN_INT (0xf); operands[2] = GEN_INT (val - 0xf); } else { operands[1] = GEN_INT (- 0x10); operands[2] = GEN_INT (val + 0x10); } }")

(define_split [(set (match_operand:DI 0 "register_operand" "") (minus:DI (match_operand:DI 1 "register_operand" "") (match_operand:DI 2 "const_int_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && M16_REG_P (REGNO (operands[1])) && REGNO (operands[0]) != REGNO (operands[1]) && GET_CODE (operands[2]) == CONST_INT && ((INTVAL (operands[2]) > 0x8 && INTVAL (operands[2]) <= 0x8 + 0x10) || (INTVAL (operands[2]) < - 0x7 && INTVAL (operands[2]) >= - 0x7 - 0xf))" [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2))) (set (match_dup 0) (minus:DI (match_dup 0) (match_dup 3)))] " { HOST_WIDE_INT val = INTVAL (operands[2]);

if (val >= 0) { operands[2] = GEN_INT (0x8); operands[3] = GEN_INT (val - 0x8); } else { operands[2] = GEN_INT (- 0x7); operands[3] = GEN_INT (val + 0x7); } }")

(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 && !TARGET_MIPS16 && (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")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (sign_extend:DI (minus:SI (match_operand:SI 1 "register_operand" "0,d,d") (match_operand:SI 2 "arith_operand" "I,O,d"))))] "TARGET_64BIT && TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || (INTVAL (operands[2]) != -32768 && INTVAL (operands[2]) != -0x4000))" "* { if (REGNO (operands[0]) == REGNO (operands[1])) return "subu\t%0,%2"; return "subu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_nsimm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 2 "m16_nsimm4_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; ;; .................... ;; ;; MULTIPLICATION ;; ;; .................... ;;

;; Early Vr4300 silicon has a CPU bug where multiplies with certain ;; operands may corrupt immediately following multiplies. This is a ;; simple fix to insert NOPs.

(define_expand "muldf3" [(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_DOUBLE_FLOAT" " { if (!TARGET_MIPS4300) emit_insn (gen_muldf3_internal (operands[0], operands[1], operands[2])); else emit_insn (gen_muldf3_r4300 (operands[0], operands[1], operands[2])); DONE; }")

(define_insn "muldf3_internal" [(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_DOUBLE_FLOAT && !TARGET_MIPS4300" "mul.d\t%0,%1,%2" [(set_attr "type" "fmul") (set_attr "mode" "DF")])

(define_insn "muldf3_r4300" [(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_DOUBLE_FLOAT && TARGET_MIPS4300" "* { output_asm_insn ("mul.d\t%0,%1,%2", operands); if (TARGET_4300_MUL_FIX) output_asm_insn ("nop", operands); return ""; }" [(set_attr "type" "fmul") (set_attr "mode" "DF") (set_attr "length" "8")]) ;; mul.d + nop

(define_expand "mulsf3" [(set (match_operand:SF 0 "register_operand" "=f") (mult:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" " { if (!TARGET_MIPS4300) emit_insn( gen_mulsf3_internal (operands[0], operands[1], operands[2])); else emit_insn( gen_mulsf3_r4300 (operands[0], operands[1], operands[2])); DONE; }")

(define_insn "mulsf3_internal" [(set (match_operand:SF 0 "register_operand" "=f") (mult:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && !TARGET_MIPS4300" "mul.s\t%0,%1,%2" [(set_attr "type" "fmul") (set_attr "mode" "SF")])

(define_insn "mulsf3_r4300" [(set (match_operand:SF 0 "register_operand" "=f") (mult:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_MIPS4300" "* { output_asm_insn ("mul.s\t%0,%1,%2", operands); if (TARGET_4300_MUL_FIX) output_asm_insn ("nop", operands); return ""; }" [(set_attr "type" "fmul") (set_attr "mode" "SF") (set_attr "length" "8")]) ;; mul.s + nop

;; ??? 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 (match_scratch:SI 3 "=h")) (clobber (match_scratch:SI 4 "=a"))] "" " { if (GENERATE_MULT3_SI || TARGET_MAD) emit_insn (gen_mulsi3_mult3 (operands[0], operands[1], operands[2])); else if (!TARGET_MIPS4000 || TARGET_MIPS16) 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_mult3" [(set (match_operand:SI 0 "register_operand" "=d,l") (mult:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "register_operand" "d,d"))) (clobber (match_scratch:SI 3 "=h,h")) (clobber (match_scratch:SI 4 "=l,X")) (clobber (match_scratch:SI 5 "=a,a"))] "GENERATE_MULT3_SI || TARGET_MAD" "* { if (which_alternative == 1) return "mult\t%1,%2"; if (TARGET_MAD || TARGET_MIPS5400 || TARGET_MIPS5500 || ISA_MIPS32 || ISA_MIPS32R2 || ISA_MIPS64) return "mul\t%0,%1,%2"; return "mult\t%0,%1,%2"; }" [(set_attr "type" "imul") (set_attr "mode" "SI")])

(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"))] "!TARGET_MIPS4000 || TARGET_MIPS16" "mult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI")])

(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"))] "TARGET_MIPS4000 && !TARGET_MIPS16" "* { rtx xoperands[10];

xoperands[0] = operands[0]; xoperands[1] = gen_rtx_REG (SImode, LO_REGNUM);

output_asm_insn ("mult\t%1,%2", operands); output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands); return ""; }" [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "12")]) ;; mult + mflo + delay

;; Multiply-accumulate patterns

;; For processors that can copy the output to a general register: ;; ;; The all-d alternative is needed because the combiner will find this ;; pattern and then register alloc/reload will move registers around to ;; make them fit, and we don't want to trigger unnecessary loads to LO. ;; ;; The last alternative should be made slightly less desirable, but adding ;; "?" to the constraint is too strong, and causes values to be loaded into ;; LO even when that's more costly. For now, using "*d" mostly does the ;; trick. (define_insn "*mul_acc_si" [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d") (match_operand:SI 2 "register_operand" "d,d,d")) (match_operand:SI 3 "register_operand" "0,l,d"))) (clobber (match_scratch:SI 4 "=h,h,h")) (clobber (match_scratch:SI 5 "=X,3,l")) (clobber (match_scratch:SI 6 "=a,a,a")) (clobber (match_scratch:SI 7 "=X,X,d"))] "(TARGET_MIPS3900 || TARGET_MIPS5400 || TARGET_MIPS5500 || ISA_HAS_MADD_MSUB) && !TARGET_MIPS16" " { static const char *const madd[] = { "madd\t%1,%2", "madd\t%0,%1,%2" }; static const char *const macc[] = { "macc\t$0,%1,%2", "macc\t%0,%1,%2" }; if (which_alternative == 2) return "#"; if (ISA_HAS_MADD_MSUB && which_alternative != 0) return "#";

if (TARGET_MIPS5400) return macc[which_alternative];

if (TARGET_MIPS5500) { if (which_alternative == 0) return madd[0]; else return macc[which_alternative]; }

return madd[which_alternative]; }" [(set_attr "type" "imadd,imadd,multi") (set_attr "mode" "SI") (set_attr "length" "4,4,8")])

;; Split the above insn if we failed to get LO allocated. (define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand" "")) (match_operand:SI 3 "register_operand" ""))) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "")) (clobber (match_scratch:SI 6 "")) (clobber (match_scratch:SI 7 ""))] "reload_completed && !TARGET_DEBUG_D_MODE && GP_REG_P (true_regnum (operands[0])) && GP_REG_P (true_regnum (operands[3]))" [(parallel [(set (match_dup 7) (mult:SI (match_dup 1) (match_dup 2))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6))]) (set (match_dup 0) (plus:SI (match_dup 7) (match_dup 3)))] "")

;; Splitter to copy result of MADD to a general register (define_split [(set (match_operand:SI 0 "register_operand" "") (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand" "")) (match_operand:SI 3 "register_operand" ""))) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "")) (clobber (match_scratch:SI 6 "")) (clobber (match_scratch:SI 7 ""))] "reload_completed && !TARGET_DEBUG_D_MODE && GP_REG_P (true_regnum (operands[0])) && true_regnum (operands[3]) == LO_REGNUM" [(parallel [(set (match_dup 3) (plus:SI (mult:SI (match_dup 1) (match_dup 2)) (match_dup 3))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6)) (clobber (match_dup 7))]) (set (match_dup 0) (match_dup 3))] "")

(define_insn "*mul_sub_si" [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") (minus:SI (match_operand:SI 1 "register_operand" "0,l,d") (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") (match_operand:SI 3 "register_operand" "d,d,d")))) (clobber (match_scratch:SI 4 "=h,h,h")) (clobber (match_scratch:SI 5 "=X,3,l")) (clobber (match_scratch:SI 6 "=a,a,a")) (clobber (match_scratch:SI 7 "=X,X,d"))] "ISA_HAS_MADD_MSUB" " { if (which_alternative != 0) return "#"; return "msub\t%2,%3"; }" [(set_attr "type" "imadd,multi,multi") (set_attr "mode" "SI") (set_attr "length" "4,8,8")])

;; Split the above insn if we failed to get LO allocated. (define_split [(set (match_operand:SI 0 "register_operand" "") (minus:SI (match_operand:SI 1 "register_operand" "") (mult:SI (match_operand:SI 2 "register_operand" "") (match_operand:SI 3 "register_operand" "")))) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "")) (clobber (match_scratch:SI 6 "")) (clobber (match_scratch:SI 7 ""))] "reload_completed && !TARGET_DEBUG_D_MODE && GP_REG_P (true_regnum (operands[0])) && GP_REG_P (true_regnum (operands[1]))" [(parallel [(set (match_dup 7) (mult:SI (match_dup 2) (match_dup 3))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6))]) (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 7)))] "")

;; Splitter to copy result of MSUB to a general register (define_split [(set (match_operand:SI 0 "register_operand" "") (minus:SI (match_operand:SI 1 "register_operand" "") (mult:SI (match_operand:SI 2 "register_operand" "") (match_operand:SI 3 "register_operand" "")))) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "")) (clobber (match_scratch:SI 6 "")) (clobber (match_scratch:SI 7 ""))] "reload_completed && !TARGET_DEBUG_D_MODE && GP_REG_P (true_regnum (operands[0])) && true_regnum (operands[1]) == LO_REGNUM" [(parallel [(set (match_dup 1) (minus:SI (match_dup 1) (mult:SI (match_dup 2) (match_dup 3)))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6)) (clobber (match_dup 7))]) (set (match_dup 0) (match_dup 1))] "")

(define_insn "*muls" [(set (match_operand:SI 0 "register_operand" "=l,d") (neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "register_operand" "d,d")))) (clobber (match_scratch:SI 3 "=h,h")) (clobber (match_scratch:SI 4 "=a,a")) (clobber (match_scratch:SI 5 "=X,l"))] "ISA_HAS_MULS && TARGET_64BIT" "@ muls\t$0,%1,%2 muls\t%0,%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI")])

;; See comments above for mul_acc_si. (define_insn "*msac" [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") (minus:SI (match_operand:SI 1 "register_operand" "0,l,*d") (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") (match_operand:SI 3 "register_operand" "d,d,d")))) (clobber (match_scratch:SI 4 "=h,h,h")) (clobber (match_scratch:SI 5 "=X,1,l")) (clobber (match_scratch:SI 6 "=a,a,a")) (clobber (match_scratch:SI 7 "=X,X,d"))] "ISA_HAS_MSAC && TARGET_64BIT" "@ msac\t$0,%2,%3 msac\t%0,%2,%3 #" [(set_attr "type" "imadd,imadd,multi") (set_attr "mode" "SI") (set_attr "length" "4,4,8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (minus:SI (match_operand:SI 1 "register_operand" "") (mult:SI (match_operand:SI 2 "register_operand" "") (match_operand:SI 3 "register_operand" "")))) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "")) (clobber (match_scratch:SI 6 "")) (clobber (match_scratch:SI 7 ""))] "reload_completed && !TARGET_DEBUG_D_MODE && GP_REG_P (true_regnum (operands[0])) && GP_REG_P (true_regnum (operands[1]))" [(parallel [(set (match_dup 7) (mult:SI (match_dup 2) (match_dup 3))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6))]) (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 7)))] "")

(define_expand "muldi3" [(set (match_operand:DI 0 "register_operand" "=l") (mult:DI (match_operand:DI 1 "se_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 (GENERATE_MULT3_DI || TARGET_MIPS4000 || TARGET_MIPS16) emit_insn (gen_muldi3_internal2 (operands[0], operands[1], operands[2])); else emit_insn (gen_muldi3_internal (operands[0], operands[1], operands[2])); DONE; }")

;; Don't accept both operands using se_register_operand, because if ;; both operands are sign extended we would prefer to use mult in the ;; mulsidi3 pattern. Commutativity should permit either operand to be ;; sign extended.

(define_insn "muldi3_internal" [(set (match_operand:DI 0 "register_operand" "=l") (mult:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "register_operand" "d"))) (clobber (match_scratch:DI 3 "=h")) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !TARGET_MIPS4000 && !TARGET_MIPS16" "dmult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "DI")])

(define_insn "muldi3_internal2" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (match_operand:DI 1 "se_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 && (GENERATE_MULT3_DI || TARGET_MIPS4000 || TARGET_MIPS16)" "* { if (GENERATE_MULT3_DI) output_asm_insn ("dmult\t%0,%1,%2", operands); else { rtx xoperands[10];

  xoperands[0] = operands[0];
  xoperands[1] = gen_rtx_REG (DImode, LO_REGNUM);

  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") (if_then_else (ne (symbol_ref "GENERATE_MULT3_DI") (const_int 0)) (const_int 4) (const_int 12)))]) ;; 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"))))] "" " { rtx dummy = gen_rtx (SIGN_EXTEND, DImode, const0_rtx); if (TARGET_64BIT) emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2], dummy, dummy)); else emit_insn (gen_mulsidi3_internal (operands[0], operands[1], operands[2], dummy, dummy)); DONE; }")

(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"))))] "" " { rtx dummy = gen_rtx (ZERO_EXTEND, DImode, const0_rtx); if (TARGET_64BIT) emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2], dummy, dummy)); else emit_insn (gen_mulsidi3_internal (operands[0], operands[1], operands[2], dummy, dummy)); DONE; }")

(define_insn "mulsidi3_internal" [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d")]))) (clobber (match_scratch:SI 5 "=a"))] "!TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" "* { if (GET_CODE (operands[3]) == SIGN_EXTEND) return "mult\t%1,%2"; return "multu\t%1,%2"; }" [(set_attr "type" "imul") (set_attr "mode" "SI")])

(define_insn "mulsidi3_64bit" [(set (match_operand:DI 0 "register_operand" "=a") (mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d")]))) (clobber (match_scratch:DI 5 "=l")) (clobber (match_scratch:DI 6 "=h"))] "TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" "* { if (GET_CODE (operands[3]) == SIGN_EXTEND) return "mult\t%1,%2"; return "multu\t%1,%2"; }" [(set_attr "type" "imul") (set_attr "mode" "SI")])

;; widening multiply with accumulator and/or negation ;; These don't match yet for zero-extending; too complex for combine? ;; Possible additions we should have: ;; "=x" variants for when !TARGET_64BIT ? ;; all-d alternatives with splits like pure SImode versions (define_insn "muls_di" [(set (match_operand:DI 0 "register_operand" "=a") (neg:DI (mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d")])))) (clobber (match_scratch:SI 5 "=h")) (clobber (match_scratch:SI 6 "=l"))] "TARGET_64BIT && ISA_HAS_MULS && GET_CODE (operands[3]) == GET_CODE (operands[4])" " { if (GET_CODE (operands[3]) == SIGN_EXTEND) return "muls\t$0,%1,%2"; else return "mulsu\t$0,%1,%2"; }" [(set_attr "type" "imul") (set_attr "length" "4") (set_attr "mode" "SI")])

(define_insn "msac_di" [(set (match_operand:DI 0 "register_operand" "=a") (minus:DI (match_operand:DI 3 "register_operand" "0") (mult:DI (match_operator:DI 4 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 5 "extend_operator" [(match_operand:SI 2 "register_operand" "d")])))) (clobber (match_scratch:SI 6 "=h")) (clobber (match_scratch:SI 7 "=l"))] "TARGET_64BIT && ISA_HAS_MSAC && GET_CODE (operands[4]) == GET_CODE (operands[5])" " { if (GET_CODE (operands[4]) == SIGN_EXTEND) { if (TARGET_MIPS5500) return "msub\t%1,%2"; else return "msac\t$0,%1,%2"; } else { if (TARGET_MIPS5500) return "msubu\t%1,%2"; else return "msacu\t$0,%1,%2"; } }" [(set_attr "type" "imadd") (set_attr "length" "4") (set_attr "mode" "SI")])

;; _highpart patterns (define_expand "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))))] "" " { rtx dummy = gen_rtx (SIGN_EXTEND, DImode, const0_rtx); rtx dummy2 = gen_rtx_LSHIFTRT (DImode, const0_rtx, const0_rtx); #ifndef NO_MD_PROTOTYPES rtx (*genfn) PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx)); #else rtx (*genfn) (); #endif if (ISA_HAS_MULHI && TARGET_64BIT) genfn = gen_xmulsi3_highpart_mulhi; else genfn = gen_xmulsi3_highpart_internal; emit_insn ((*genfn) (operands[0], operands[1], operands[2], dummy, dummy, dummy2)); DONE; }")

(define_expand "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))))] "" " { rtx dummy = gen_rtx (ZERO_EXTEND, DImode, const0_rtx); rtx dummy2 = gen_rtx_LSHIFTRT (DImode, const0_rtx, const0_rtx); #ifndef NO_MD_PROTOTYPES rtx (*genfn) PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx)); #else rtx (*genfn) (); #endif if (ISA_HAS_MULHI && TARGET_64BIT) genfn = gen_xmulsi3_highpart_mulhi; else genfn = gen_xmulsi3_highpart_internal; emit_insn ((*genfn) (operands[0], operands[1], operands[2], dummy, dummy, dummy2)); DONE; }")

(define_insn "xmulsi3_highpart_internal" [(set (match_operand:SI 0 "register_operand" "=h") (truncate:SI (match_operator:DI 5 "highpart_shift_operator" [(mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d")])) (const_int 32)]))) (clobber (match_scratch:SI 6 "=l")) (clobber (match_scratch:SI 7 "=a"))] "GET_CODE (operands[3]) == GET_CODE (operands[4])" "* { if (GET_CODE (operands[3]) == SIGN_EXTEND) return "mult\t%1,%2"; else return "multu\t%1,%2"; }" [(set_attr "type" "imul") (set_attr "mode" "SI")])

(define_insn "xmulsi3_highpart_mulhi" [(set (match_operand:SI 0 "register_operand" "=h,d") (truncate:SI (match_operator:DI 5 "highpart_shift_operator" [(mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d,d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d,d")])) (const_int 32)]))) (clobber (match_scratch:SI 6 "=l,l")) (clobber (match_scratch:SI 7 "=a,a")) (clobber (match_scratch:SI 8 "=X,h"))] "ISA_HAS_MULHI && TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" "* { static char const *const sign[] = { "mult\t%1,%2", "mulhi\t%0,%1,%2" }; static char const *const zero[] = { "multu\t%1,%2", "mulhiu\t%0,%1,%2" }; if (GET_CODE (operands[3]) == SIGN_EXTEND) return sign[which_alternative]; else return zero[which_alternative]; }" [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "4")])

(define_insn "xmulsi3_neg_highpart_mulhi" [(set (match_operand:SI 0 "register_operand" "=h,d") (truncate:SI (match_operator:DI 5 "highpart_shift_operator" [(neg:DI (mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d,d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d,d")]))) (const_int 32)]))) (clobber (match_scratch:SI 6 "=l,l")) (clobber (match_scratch:SI 7 "=a,a")) (clobber (match_scratch:SI 8 "=X,h"))] "ISA_HAS_MULHI && TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" " { static char const *const sign[] = { "mulshi\t$0,%1,%2", "mulshi\t%0,%1,%2" }; static char const *const zero[] = { "mulshiu\t$0,%1,%2", "mulshiu\t%0,%1,%2" }; if (GET_CODE (operands[3]) == SIGN_EXTEND) return sign[which_alternative]; else return zero[which_alternative]; }" [(set_attr "type" "imul") (set_attr "mode" "SI") (set_attr "length" "4")])

(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 "se_register_operand" "d")) (sign_extend:TI (match_operand:DI 2 "se_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")])

(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 "se_register_operand" "d")) (zero_extend:TI (match_operand:DI 2 "se_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")])

;; 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" "imadd") (set_attr "mode" "SI")])

(define_insn "mul_acc_di" [(set (match_operand:DI 0 "register_operand" "+x") (plus:DI (mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d")])) (match_dup 0))) (clobber (match_scratch:SI 5 "=a"))] "TARGET_MAD && ! TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" " { if (GET_CODE (operands[3]) == SIGN_EXTEND) return "mad\t%1,%2"; else return "madu\t%1,%2"; }" [(set_attr "type" "imadd") (set_attr "mode" "SI")])

(define_insn "mul_acc_64bit_di" [(set (match_operand:DI 0 "register_operand" "+a") (plus:DI (mult:DI (match_operator:DI 3 "extend_operator" [(match_operand:SI 1 "register_operand" "d")]) (match_operator:DI 4 "extend_operator" [(match_operand:SI 2 "register_operand" "d")])) (match_dup 0))) (clobber (match_scratch:SI 5 "=h")) (clobber (match_scratch:SI 6 "=l"))] "TARGET_MAD && TARGET_64BIT && GET_CODE (operands[3]) == GET_CODE (operands[4])" " { if (TARGET_MAD) { if (GET_CODE (operands[3]) == SIGN_EXTEND) return "mad\t%1,%2"; else return "madu\t%1,%2"; } else if (ISA_HAS_MACC) { if (GET_CODE (operands[3]) == SIGN_EXTEND) { if (TARGET_MIPS5500) return "madd\t%1,%2"; else return "macc\t$0,%1,%2"; } else { if (TARGET_MIPS5500) return "maddu\t%1,%2"; else return "maccu\t$0,%1,%2"; } } else abort ();

}" [(set_attr "type" "imadd") (set_attr "mode" "SI")])

;; 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")))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FUSED_MADD" "madd.d\t%0,%3,%1,%2" [(set_attr "type" "fmadd") (set_attr "mode" "DF")])

(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")))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_FUSED_MADD" "madd.s\t%0,%3,%1,%2" [(set_attr "type" "fmadd") (set_attr "mode" "SF")])

(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")))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FUSED_MADD" "msub.d\t%0,%3,%1,%2" [(set_attr "type" "fmadd") (set_attr "mode" "DF")])

(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")))]

"ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_FUSED_MADD" "msub.s\t%0,%3,%1,%2" [(set_attr "type" "fmadd") (set_attr "mode" "SF")])

(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"))))] "ISA_HAS_NMADD_NMSUB && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FUSED_MADD" "nmadd.d\t%0,%3,%1,%2" [(set_attr "type" "fmadd") (set_attr "mode" "DF")])

(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"))))] "ISA_HAS_NMADD_NMSUB && TARGET_HARD_FLOAT && TARGET_FUSED_MADD" "nmadd.s\t%0,%3,%1,%2" [(set_attr "type" "fmadd") (set_attr "mode" "SF")])

(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"))))] "ISA_HAS_NMADD_NMSUB && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FUSED_MADD" "nmsub.d\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "DF")])

(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"))))] "ISA_HAS_NMADD_NMSUB && TARGET_HARD_FLOAT && TARGET_FUSED_MADD" "nmsub.s\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "SF")]) ;; ;; .................... ;; ;; DIVISION and REMAINDER ;; ;; .................... ;;

(define_insn "divdf3" [(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_DOUBLE_FLOAT" "div.d\t%0,%1,%2" [(set_attr "type" "fdiv") (set_attr "mode" "DF")])

(define_insn "divsf3" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "div.s\t%0,%1,%2" [(set_attr "type" "fdiv") (set_attr "mode" "SF")])

(define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "const_float_1_operand" "") (match_operand:DF 2 "register_operand" "f")))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_unsafe_math_optimizations" "recip.d\t%0,%2" [(set_attr "type" "fdiv") (set_attr "mode" "DF")])

(define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "const_float_1_operand" "") (match_operand:SF 2 "register_operand" "f")))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && flag_unsafe_math_optimizations" "recip.s\t%0,%2" [(set_attr "type" "fdiv") (set_attr "mode" "SF")])

;; If optimizing, prefer the divmod functions over separate div and ;; mod functions, since this will allow using one instruction for both ;; the quotient and remainder. At present, the divmod is not moved out ;; of loops if it is constant within the loop, so allow -mdebugc to ;; use the old method of doing things.

;; 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_expand "divmodsi4" [(set (match_operand:SI 0 "register_operand" "=d") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (set (match_operand:SI 3 "register_operand" "=d") (mod:SI (match_dup 1) (match_dup 2))) (clobber (match_scratch:SI 4 "=l")) (clobber (match_scratch:SI 5 "=h")) (clobber (match_scratch:SI 6 "=a"))] "optimize" " { emit_insn (gen_divmodsi4_internal (operands[0], operands[1], operands[2], operands[3])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); } if (TARGET_CHECK_RANGE_DIV) { emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (SImode, GEN_INT (-1)), GEN_INT (0x6))); emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (SImode, GEN_INT (trunc_int_for_mode (BITMASK_HIGH, SImode))), GEN_INT (0x6))); }

DONE; }")

(define_insn "divmodsi4_internal" [(set (match_operand:SI 0 "register_operand" "=l") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (set (match_operand:SI 3 "register_operand" "=h") (mod:SI (match_dup 1) (match_dup 2))) (clobber (match_scratch:SI 4 "=a"))] "optimize" "div\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "divmoddi4" [(set (match_operand:DI 0 "register_operand" "=d") (div:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (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" " { emit_insn (gen_divmoddi4_internal (operands[0], operands[1], operands[2], operands[3])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); } if (TARGET_CHECK_RANGE_DIV) { emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (DImode, GEN_INT (-1)), GEN_INT (0x6))); emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (DImode, GEN_INT (BITMASK_HIGH)), GEN_INT (0x6))); }

DONE; }")

(define_insn "divmoddi4_internal" [(set (match_operand:DI 0 "register_operand" "=l") (div:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (set (match_operand:DI 3 "register_operand" "=h") (mod:DI (match_dup 1) (match_dup 2))) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && optimize" "ddiv\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "udivmodsi4" [(set (match_operand:SI 0 "register_operand" "=d") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (set (match_operand:SI 3 "register_operand" "=d") (umod:SI (match_dup 1) (match_dup 2))) (clobber (match_scratch:SI 4 "=l")) (clobber (match_scratch:SI 5 "=h")) (clobber (match_scratch:SI 6 "=a"))] "optimize" " { emit_insn (gen_udivmodsi4_internal (operands[0], operands[1], operands[2], operands[3])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); }

DONE; }")

(define_insn "udivmodsi4_internal" [(set (match_operand:SI 0 "register_operand" "=l") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (set (match_operand:SI 3 "register_operand" "=h") (umod:SI (match_dup 1) (match_dup 2))) (clobber (match_scratch:SI 4 "=a"))] "optimize" "divu\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "udivmoddi4" [(set (match_operand:DI 0 "register_operand" "=d") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (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" " { emit_insn (gen_udivmoddi4_internal (operands[0], operands[1], operands[2], operands[3])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); }

DONE; }")

(define_insn "udivmoddi4_internal" [(set (match_operand:DI 0 "register_operand" "=l") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (set (match_operand:DI 3 "register_operand" "=h") (umod:DI (match_dup 1) (match_dup 2))) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && optimize" "ddivu\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

;; Division trap

(define_expand "div_trap" [(trap_if (eq (match_operand 0 "register_operand" "d") (match_operand 1 "true_reg_or_0_operand" "dJ")) (match_operand 2 "immediate_operand" ""))] "" " { if (TARGET_MIPS16) emit_insn (gen_div_trap_mips16 (operands[0],operands[1],operands[2])); else emit_insn (gen_div_trap_normal (operands[0],operands[1],operands[2])); DONE; }")

(define_insn "div_trap_normal" [(trap_if (eq (match_operand 0 "register_operand" "d,d") (match_operand 1 "true_reg_or_0_operand" "d,J")) (match_operand 2 "immediate_operand" ""))] "!TARGET_MIPS16" "* { rtx link; int have_dep_anti = 0;

/* For divmod if one division is not needed then we don't need an extra divide by zero trap, which is anti dependent on previous trap */ for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))

if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link)
    && GET_CODE (XEXP (link, 0)) == INSN
    && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF
&& which_alternative == 1)
  have_dep_anti = 1;

if (! have_dep_anti) { if (GENERATE_BRANCHLIKELY) { if (which_alternative == 1) return "%(beql\t%0,$0,1f\n\tbreak\t%2\n%~1:%)"; else return "%(beql\t%0,%1,1f\n\tbreak\t%2\n%~1:%)"; } else { if (which_alternative == 1) return "%(bne\t%0,$0,1f\n\tnop\n\tbreak\t%2\n%~1:%)"; else return "%(bne\t%0,%1,1f\n\tnop\n\tbreak\t%2\n%~1:%)"; } } return ""; }" [(set_attr "type" "unknown") (set_attr "length" "12")])

;; The mips16 bne insns is a macro which uses reg 24 as an intermediate.

(define_insn "div_trap_mips16" [(trap_if (eq (match_operand 0 "register_operand" "d,d") (match_operand 1 "true_reg_or_0_operand" "d,J")) (match_operand 2 "immediate_operand" "")) (clobber (reg:SI 24))] "TARGET_MIPS16" "* { rtx link; int have_dep_anti = 0;

/* For divmod if one division is not needed then we don't need an extra divide by zero trap, which is anti dependent on previous trap */ for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))

if ((int) REG_DEP_ANTI == (int) REG_NOTE_KIND (link)
    && GET_CODE (XEXP (link, 0)) == INSN
    && GET_CODE (PATTERN (XEXP (link, 0))) == TRAP_IF
&& which_alternative == 1)
  have_dep_anti = 1;

if (! have_dep_anti) { /* No branch delay slots on mips16. */ if (which_alternative == 1) return "%(bnez\t%0,1f\n\tbreak\t%2\n%~1:%)"; else return "%(bne\t%0,%1,1f\n\tbreak\t%2\n%~1:%)"; } return ""; }" [(set_attr "type" "unknown") (set_attr "length" "12")])

(define_expand "divsi3" [(set (match_operand:SI 0 "register_operand" "=l") (div: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"))] "!optimize" " { emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); } if (TARGET_CHECK_RANGE_DIV) { emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (SImode, GEN_INT (-1)), GEN_INT (0x6))); emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (SImode, GEN_INT (trunc_int_for_mode (BITMASK_HIGH, SImode))), GEN_INT (0x6))); }

DONE; }")

(define_insn "divsi3_internal" [(set (match_operand:SI 0 "register_operand" "=l") (div:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=h")) (clobber (match_scratch:SI 4 "=a"))] "!optimize" "div\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "divdi3" [(set (match_operand:DI 0 "register_operand" "=l") (div:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (clobber (match_scratch:DI 3 "=h")) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { emit_insn (gen_divdi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); } if (TARGET_CHECK_RANGE_DIV) { emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (DImode, GEN_INT (-1)), GEN_INT (0x6))); emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (DImode, GEN_INT (BITMASK_HIGH)), GEN_INT (0x6))); }

DONE; }")

(define_insn "divdi3_internal" [(set (match_operand:DI 0 "register_operand" "=l") (div:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=h")) (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" "ddiv\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI")])

(define_expand "modsi3" [(set (match_operand:SI 0 "register_operand" "=h") (mod:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SI 3 "=l")) (clobber (match_scratch:SI 4 "=a"))] "!optimize" " { emit_insn (gen_modsi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); } if (TARGET_CHECK_RANGE_DIV) { emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (SImode, GEN_INT (-1)), GEN_INT (0x6))); emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (SImode, GEN_INT (trunc_int_for_mode (BITMASK_HIGH, SImode))), GEN_INT (0x6))); }

DONE; }")

(define_insn "modsi3_internal" [(set (match_operand:SI 0 "register_operand" "=h") (mod:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=l")) (clobber (match_scratch:SI 4 "=a"))] "!optimize" "div\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "moddi3" [(set (match_operand:DI 0 "register_operand" "=h") (mod:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (clobber (match_scratch:DI 3 "=l")) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { emit_insn (gen_moddi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); } if (TARGET_CHECK_RANGE_DIV) { emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (DImode, GEN_INT (-1)), GEN_INT (0x6))); emit_insn (gen_div_trap (operands[2], copy_to_mode_reg (DImode, GEN_INT (BITMASK_HIGH)), GEN_INT (0x6))); }

DONE; }")

(define_insn "moddi3_internal" [(set (match_operand:DI 0 "register_operand" "=h") (mod:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=l")) (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" "ddiv\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI")])

(define_expand "udivsi3" [(set (match_operand:SI 0 "register_operand" "=l") (udiv: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"))] "!optimize" " { emit_insn (gen_udivsi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); }

DONE; }")

(define_insn "udivsi3_internal" [(set (match_operand:SI 0 "register_operand" "=l") (udiv:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=h")) (clobber (match_scratch:SI 4 "=a"))] "!optimize" "divu\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "udivdi3" [(set (match_operand:DI 0 "register_operand" "=l") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "di"))) (clobber (match_scratch:DI 3 "=h")) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { emit_insn (gen_udivdi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); }

DONE; }")

(define_insn "udivdi3_internal" [(set (match_operand:DI 0 "register_operand" "=l") (udiv:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=h")) (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" "ddivu\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI")])

(define_expand "umodsi3" [(set (match_operand:SI 0 "register_operand" "=h") (umod:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SI 3 "=l")) (clobber (match_scratch:SI 4 "=a"))] "!optimize" " { emit_insn (gen_umodsi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); }

DONE; }")

(define_insn "umodsi3_internal" [(set (match_operand:SI 0 "register_operand" "=h") (umod:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=l")) (clobber (match_scratch:SI 4 "=a"))] "!optimize" "divu\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "SI")])

(define_expand "umoddi3" [(set (match_operand:DI 0 "register_operand" "=h") (umod:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "di"))) (clobber (match_scratch:DI 3 "=l")) (clobber (match_scratch:DI 4 "=a"))] "TARGET_64BIT && !optimize" " { emit_insn (gen_umoddi3_internal (operands[0], operands[1], operands[2])); if (!TARGET_NO_CHECK_ZERO_DIV) { emit_insn (gen_div_trap (operands[2], GEN_INT (0), GEN_INT (0x7))); }

DONE; }")

(define_insn "umoddi3_internal" [(set (match_operand:DI 0 "register_operand" "=h") (umod:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_nonmemory_operand" "di"))) (clobber (match_scratch:SI 3 "=l")) (clobber (match_scratch:SI 4 "=a"))] "TARGET_64BIT && !optimize" "ddivu\t$0,%1,%2" [(set_attr "type" "idiv") (set_attr "mode" "DI")]) ;; ;; .................... ;; ;; SQUARE ROOT ;; ;; ....................

(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_DOUBLE_FLOAT" "sqrt.d\t%0,%1" [(set_attr "type" "fsqrt") (set_attr "mode" "DF")])

(define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f") (sqrt:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && HAVE_SQRT_P()" "sqrt.s\t%0,%1" [(set_attr "type" "fsqrt") (set_attr "mode" "SF")])

(define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "const_float_1_operand" "") (sqrt:DF (match_operand:DF 2 "register_operand" "f"))))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_unsafe_math_optimizations" "rsqrt.d\t%0,%2" [(set_attr "type" "frsqrt") (set_attr "mode" "DF")])

(define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "const_float_1_operand" "") (sqrt:SF (match_operand:SF 2 "register_operand" "f"))))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && flag_unsafe_math_optimizations" "rsqrt.s\t%0,%2" [(set_attr "type" "frsqrt") (set_attr "mode" "SF")])

;; ;; .................... ;; ;; ABSOLUTE VALUE ;; ;; ....................

;; Do not use the integer abs macro instruction, since that signals an ;; exception on -2147483648 (sigh).

(define_insn "abssi2" [(set (match_operand:SI 0 "register_operand" "=d") (abs:SI (match_operand:SI 1 "register_operand" "d")))] "!TARGET_MIPS16" "* { dslots_jump_total++; dslots_jump_filled++; operands[2] = const0_rtx;

if (REGNO (operands[0]) == REGNO (operands[1])) { if (GENERATE_BRANCHLIKELY) return "%(bltzl\t%1,1f\n\tsubu\t%0,%z2,%0\n%~1:%)"; else return "bgez\t%1,1f%#\n\tsubu\t%0,%z2,%0\n%~1:"; } else return "%(bgez\t%1,1f\n\tmove\t%0,%1\n\tsubu\t%0,%z2,%0\n%~1:%)"; }" [(set_attr "type" "multi") (set_attr "mode" "SI") (set_attr "length" "12")])

(define_insn "absdi2" [(set (match_operand:DI 0 "register_operand" "=d") (abs:DI (match_operand:DI 1 "se_register_operand" "d")))] "TARGET_64BIT && !TARGET_MIPS16" "* { unsigned int regno1; dslots_jump_total++; dslots_jump_filled++; operands[2] = const0_rtx;

if (GET_CODE (operands[1]) == REG) regno1 = REGNO (operands[1]); else regno1 = REGNO (XEXP (operands[1], 0));

if (REGNO (operands[0]) == regno1) return "%(bltzl\t%1,1f\n\tdsubu\t%0,%z2,%0\n%~1:%)"; else return "%(bgez\t%1,1f\n\tmove\t%0,%1\n\tdsubu\t%0,%z2,%0\n%~1:%)"; }" [(set_attr "type" "multi") (set_attr "mode" "DI") (set_attr "length" "12")])

(define_insn "absdf2" [(set (match_operand:DF 0 "register_operand" "=f") (abs:DF (match_operand:DF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "abs.d\t%0,%1" [(set_attr "type" "fabs") (set_attr "mode" "DF")])

(define_insn "abssf2" [(set (match_operand:SF 0 "register_operand" "=f") (abs:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" "abs.s\t%0,%1" [(set_attr "type" "fabs") (set_attr "mode" "SF")])

;; ;; .................... ;; ;; FIND FIRST BIT INSTRUCTION ;; ;; .................... ;;

(define_insn "ffssi2" [(set (match_operand:SI 0 "register_operand" "=&d") (ffs:SI (match_operand:SI 1 "register_operand" "d"))) (clobber (match_scratch:SI 2 "=&d")) (clobber (match_scratch:SI 3 "=&d"))] "!TARGET_MIPS16" "* { 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\ \taddu\t%0,%0,1\n\ \tbeq\t%2,%z4,1b\n\ \tsrl\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\ \taddu\t%0,%0,1\n\ \tbeq\t%2,%z4,1b\n\ \tsrl\t%3,%3,1\n\ %~2:%)"; }" [(set_attr "type" "multi") (set_attr "mode" "SI") (set_attr "length" "12")])

(define_insn "ffsdi2" [(set (match_operand:DI 0 "register_operand" "=&d") (ffs:DI (match_operand:DI 1 "se_register_operand" "d"))) (clobber (match_scratch:DI 2 "=&d")) (clobber (match_scratch:DI 3 "=&d"))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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" "24")])

;; ;; .................... ;; ;; NEGATION and ONE'S COMPLEMENT ;; ;; ....................

(define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=d") (neg:SI (match_operand:SI 1 "register_operand" "d")))] "" "* { if (TARGET_MIPS16) return "neg\t%0,%1"; operands[2] = const0_rtx; return "subu\t%0,%z2,%1"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_expand "negdi2" [(parallel [(set (match_operand:DI 0 "register_operand" "=d") (neg:DI (match_operand:DI 1 "se_register_operand" "d"))) (clobber (match_dup 2))])] "(TARGET_64BIT || !TARGET_DEBUG_G_MODE) && !TARGET_MIPS16" " { 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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16" "* { operands[3] = const0_rtx; return "subu\t%L0,%z3,%L1;subu\t%M0,%z3,%M1;sltu\t%2,%z3,%L0;subu\t%M0,%M0,%2"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "16")])

(define_insn "negdi2_internal_2" [(set (match_operand:DI 0 "register_operand" "=d") (neg:DI (match_operand:DI 1 "se_register_operand" "d")))] "TARGET_64BIT && !TARGET_MIPS16" "* { operands[2] = const0_rtx; return "dsubu\t%0,%z2,%1"; }" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=f") (neg:DF (match_operand:DF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "neg.d\t%0,%1" [(set_attr "type" "fneg") (set_attr "mode" "DF")])

(define_insn "negsf2" [(set (match_operand:SF 0 "register_operand" "=f") (neg:SF (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" "neg.s\t%0,%1" [(set_attr "type" "fneg") (set_attr "mode" "SF")])

(define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=d") (not:SI (match_operand:SI 1 "register_operand" "d")))] "" "* { if (TARGET_MIPS16) return "not\t%0,%1"; operands[2] = const0_rtx; return "nor\t%0,%z2,%1"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "one_cmpldi2" [(set (match_operand:DI 0 "register_operand" "=d") (not:DI (match_operand:DI 1 "se_register_operand" "d")))] "" "* { if (TARGET_MIPS16) { if (TARGET_64BIT) return "not\t%0,%1"; return "not\t%M0,%M1;not\t%L0,%L1"; } 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") (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) (const_int 4) (const_int 8)))])

(define_split [(set (match_operand:DI 0 "register_operand" "") (not:DI (match_operand:DI 1 "register_operand" "")))] "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) (not:SI (subreg:SI (match_dup 1) 0))) (set (subreg:SI (match_dup 0) 4) (not:SI (subreg:SI (match_dup 1) 4)))] "")

;; ;; .................... ;; ;; LOGICAL ;; ;; .................... ;;

;; Many of these instructions uses trivial define_expands, because we ;; want to use a different set of constraints when TARGET_MIPS16.

(define_expand "andsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (and:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "" " { if (TARGET_MIPS16) { operands[1] = force_reg (SImode, operands[1]); operands[2] = force_reg (SImode, operands[2]); } }")

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d") (and:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "!TARGET_MIPS16" "@ and\t%0,%1,%2 andi\t%0,%1,%x2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (and:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "d")))] "TARGET_MIPS16" "and\t%0,%2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_expand "anddi3" [(set (match_operand:DI 0 "register_operand" "=d") (and:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT || !TARGET_DEBUG_G_MODE" " { if (TARGET_MIPS16) { operands[1] = force_reg (DImode, operands[1]); operands[2] = force_reg (DImode, operands[2]); } }")

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (and:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "(TARGET_64BIT || !TARGET_DEBUG_G_MODE) && !TARGET_MIPS16" "* { 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") (if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0)) (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (and:DI (match_operand:DI 1 "se_register_operand" "0") (match_operand:DI 2 "se_register_operand" "d")))] "(TARGET_64BIT || !TARGET_DEBUG_G_MODE) && TARGET_MIPS16" "* { if (TARGET_64BIT) return "and\t%0,%2"; return "and\t%M0,%M2;and\t%L0,%L2"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) (const_int 4) (const_int 8)))])

(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_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]))"

[(set (subreg:SI (match_dup 0) 0) (and:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) (set (subreg:SI (match_dup 0) 4) (and:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))] "")

(define_insn "anddi3_internal1" [(set (match_operand:DI 0 "register_operand" "=d,d") (and:DI (match_operand:DI 1 "se_register_operand" "%d,d") (match_operand:DI 2 "se_uns_arith_operand" "d,K")))] "TARGET_64BIT && !TARGET_MIPS16" "@ and\t%0,%1,%2 andi\t%0,%1,%x2" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_expand "iorsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (ior:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "" " { if (TARGET_MIPS16) { operands[1] = force_reg (SImode, operands[1]); operands[2] = force_reg (SImode, operands[2]); } }")

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d") (ior:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "!TARGET_MIPS16" "@ or\t%0,%1,%2 ori\t%0,%1,%x2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (ior:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "d")))] "TARGET_MIPS16" "or\t%0,%2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

;;; ??? There is no iordi3 pattern which accepts 'K' constants when ;;; TARGET_64BIT

(define_expand "iordi3" [(set (match_operand:DI 0 "register_operand" "=d") (ior:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT || !TARGET_DEBUG_G_MODE" "")

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (ior:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "(TARGET_64BIT || !TARGET_DEBUG_G_MODE) && !TARGET_MIPS16" "* { 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") (if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0)) (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (ior:DI (match_operand:DI 1 "se_register_operand" "0") (match_operand:DI 2 "se_register_operand" "d")))] "(TARGET_64BIT || !TARGET_DEBUG_G_MODE) && TARGET_MIPS16" "* { if (TARGET_64BIT) return "or\t%0,%2"; return "or\t%M0,%M2;or\t%L0,%L2"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (ge (symbol_ref "mips_isa") (const_int 3)) (const_int 4) (const_int 8)))])

(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_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]))"

[(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) (set (subreg:SI (match_dup 0) 4) (ior:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))] "")

(define_expand "xorsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (xor:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "" "")

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d") (xor:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "!TARGET_MIPS16" "@ xor\t%0,%1,%2 xori\t%0,%1,%x2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,t,t") (xor:SI (match_operand:SI 1 "uns_arith_operand" "%0,d,d") (match_operand:SI 2 "uns_arith_operand" "d,K,d")))] "TARGET_MIPS16" "@ xor\t%0,%2 cmpi\t%1,%2 cmp\t%1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm8_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

;; ??? If delete the 32-bit long long patterns, then could merge this with ;; the following xordi3_internal pattern. (define_expand "xordi3" [(set (match_operand:DI 0 "register_operand" "=d") (xor:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT || !TARGET_DEBUG_G_MODE" "")

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (xor:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "(TARGET_64BIT || !TARGET_DEBUG_G_MODE) && !TARGET_MIPS16" "* { 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") (if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0)) (const_int 4) (const_int 8)))])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (xor:DI (match_operand:DI 1 "se_register_operand" "0") (match_operand:DI 2 "se_register_operand" "d")))] "!TARGET_64BIT && TARGET_MIPS16" "xor\t%M0,%M2;xor\t%L0,%L2" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,t,t") (xor:DI (match_operand:DI 1 "se_register_operand" "%0,d,d") (match_operand:DI 2 "se_uns_arith_operand" "d,K,d")))] "TARGET_64BIT && TARGET_MIPS16" "@ xor\t%0,%2 cmpi\t%1,%2 cmp\t%1,%2" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm8_1" "") (const_int 4) (const_int 8)) (const_int 4)])])

(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_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]))"

[(set (subreg:SI (match_dup 0) 0) (xor:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) (set (subreg:SI (match_dup 0) 4) (xor:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))] "")

(define_insn "xordi3_immed" [(set (match_operand:DI 0 "register_operand" "=d") (xor:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_uns_arith_operand" "K")))] "TARGET_64BIT && !TARGET_MIPS16" "xori\t%0,%1,%x2" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "*norsi3" [(set (match_operand:SI 0 "register_operand" "=d") (and:SI (not:SI (match_operand:SI 1 "register_operand" "d")) (not:SI (match_operand:SI 2 "register_operand" "d"))))] "!TARGET_MIPS16" "nor\t%0,%z1,%z2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "nordi3" [(set (match_operand:DI 0 "register_operand" "=d") (and:DI (not:DI (match_operand:DI 1 "se_register_operand" "d")) (not:DI (match_operand:DI 2 "se_register_operand" "d"))))] "!TARGET_MIPS16" " { 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") (if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0)) (const_int 4) (const_int 8)))])

(define_split [(set (match_operand:DI 0 "register_operand" "") (and:DI (not:DI (match_operand:DI 1 "register_operand" "")) (not:DI (match_operand:DI 2 "register_operand" ""))))] "reload_completed && !TARGET_MIPS16 && !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]))"

[(set (subreg:SI (match_dup 0) 0) (and:SI (not:SI (subreg:SI (match_dup 1) 0)) (not:SI (subreg:SI (match_dup 2) 0)))) (set (subreg:SI (match_dup 0) 4) (and:SI (not:SI (subreg:SI (match_dup 1) 4)) (not:SI (subreg:SI (match_dup 2) 4))))] "") ;; ;; .................... ;; ;; TRUNCATION ;; ;; ....................

(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_DOUBLE_FLOAT" "cvt.s.d\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF")])

(define_insn "truncdisi2" [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (match_operand:DI 1 "se_register_operand" "d")))] "TARGET_64BIT" "* { if (TARGET_MIPS16) return "dsll\t%0,%1,32;dsra\t%0,32"; return "dsll\t%0,%1,32;dsra\t%0,%0,32"; }" [(set_attr "type" "darith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (eq (symbol_ref "mips16") (const_int 0)) (const_int 8) (const_int 16)))])

(define_insn "truncdihi2" [(set (match_operand:HI 0 "register_operand" "=d") (truncate:HI (match_operand:DI 1 "se_register_operand" "d")))] "TARGET_64BIT" "* { if (TARGET_MIPS16) return "dsll\t%0,%1,48;dsra\t%0,48"; return "andi\t%0,%1,0xffff"; }" [(set_attr "type" "darith") (set_attr "mode" "HI") (set (attr "length") (if_then_else (eq (symbol_ref "mips16") (const_int 0)) (const_int 4) (const_int 16)))]) (define_insn "truncdiqi2" [(set (match_operand:QI 0 "register_operand" "=d") (truncate:QI (match_operand:DI 1 "se_register_operand" "d")))] "TARGET_64BIT" "* { if (TARGET_MIPS16) return "dsll\t%0,%1,56;dsra\t%0,56"; return "andi\t%0,%1,0x00ff"; }" [(set_attr "type" "darith") (set_attr "mode" "QI") (set (attr "length") (if_then_else (eq (symbol_ref "mips16") (const_int 0)) (const_int 4) (const_int 16)))])

;; 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 "se_register_operand" "d") (match_operand:DI 2 "small_int" "I"))))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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" "8")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (lshiftrt:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "small_int" "I"))))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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" "8")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (ashift:DI (match_operand:DI 1 "se_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); if (TARGET_MIPS16) return "dsll\t%0,%1,%2;dsra\t%0,32"; 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" "8")])

;; 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 "se_register_operand" "d"))))] "TARGET_64BIT && !TARGET_MIPS16" "andi\t%0,%1,0xffff" [(set_attr "type" "darith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (truncate:QI (match_operand:DI 1 "se_register_operand" "d"))))] "TARGET_64BIT && !TARGET_MIPS16" "andi\t%0,%1,0xff" [(set_attr "type" "darith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:HI 0 "register_operand" "=d") (zero_extend:HI (truncate:QI (match_operand:DI 1 "se_register_operand" "d"))))] "TARGET_64BIT && !TARGET_MIPS16" "andi\t%0,%1,0xff" [(set_attr "type" "darith") (set_attr "mode" "HI")]) ;; ;; .................... ;; ;; ZERO EXTENSION ;; ;; ....................

;; Extension insns. ;; 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 || TARGET_MIPS16) && 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_INT (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 && !TARGET_MIPS16" "* return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "load") (set_attr "mode" "DI") (set_attr "length" "4,8")])

(define_expand "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] "" " { if (TARGET_MIPS16 && GET_CODE (operands[1]) != MEM) { rtx op = gen_lowpart (SImode, operands[1]); rtx temp = force_reg (SImode, GEN_INT (0xffff));

  emit_insn (gen_andsi3 (operands[0], op, temp));
  DONE;
}

}")

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))] "!TARGET_MIPS16" "* { 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" "SI") (set_attr "length" "4,4,8")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d") (zero_extend:SI (match_operand:HI 1 "memory_operand" "R,m")))] "TARGET_MIPS16" "* return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "load,load") (set_attr "mode" "SI") (set_attr "length" "4,8")])

(define_expand "zero_extendhidi2" [(set (match_operand:DI 0 "register_operand" "") (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "")))] "TARGET_64BIT" " { if (TARGET_MIPS16 && GET_CODE (operands[1]) != MEM) { rtx op = gen_lowpart (DImode, operands[1]); rtx temp = force_reg (DImode, GEN_INT (0xffff));

  emit_insn (gen_anddi3 (operands[0], op, temp));
  DONE;
}

}")

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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" "4,4,8")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d") (zero_extend:DI (match_operand:HI 1 "memory_operand" "R,m")))] "TARGET_64BIT && TARGET_MIPS16" "* return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "load,load") (set_attr "mode" "DI") (set_attr "length" "4,8")])

(define_expand "zero_extendqihi2" [(set (match_operand:HI 0 "register_operand" "") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] "" " { if (TARGET_MIPS16 && GET_CODE (operands[1]) != MEM) { rtx op0 = gen_lowpart (SImode, operands[0]); rtx op1 = gen_lowpart (SImode, operands[1]); rtx temp = force_reg (SImode, GEN_INT (0xff));

  emit_insn (gen_andsi3 (op0, op1, temp));
  DONE;
}

}")

(define_insn "" [(set (match_operand:HI 0 "register_operand" "=d,d,d") (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] "!TARGET_MIPS16" "* { 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" "HI") (set_attr "length" "4,4,8")])

(define_insn "" [(set (match_operand:HI 0 "register_operand" "=d,d") (zero_extend:HI (match_operand:QI 1 "memory_operand" "R,m")))] "TARGET_MIPS16" "* return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "load,load") (set_attr "mode" "HI") (set_attr "length" "4,8")])

(define_expand "zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] "" " { if (TARGET_MIPS16 && GET_CODE (operands[1]) != MEM) { rtx op = gen_lowpart (SImode, operands[1]); rtx temp = force_reg (SImode, GEN_INT (0xff));

  emit_insn (gen_andsi3 (operands[0], op, temp));
  DONE;
}

}")

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] "!TARGET_MIPS16" "* { 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" "SI") (set_attr "length" "4,4,8")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d") (zero_extend:SI (match_operand:QI 1 "memory_operand" "R,m")))] "TARGET_MIPS16" "* return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "load,load") (set_attr "mode" "SI") (set_attr "length" "4,8")])

(define_expand "zero_extendqidi2" [(set (match_operand:DI 0 "register_operand" "") (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "")))] "TARGET_64BIT" " { if (TARGET_MIPS16 && GET_CODE (operands[1]) != MEM) { rtx op = gen_lowpart (DImode, operands[1]); rtx temp = force_reg (DImode, GEN_INT (0xff));

  emit_insn (gen_anddi3 (operands[0], op, temp));
  DONE;
}

}")

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d,d") (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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" "4,4,8")])

;; These can be created when a paradoxical subreg operand with an implicit ;; sign_extend operator is reloaded. Because of the subreg, this is really ;; a zero extend. ;; ??? It might be possible to eliminate the need for these patterns by adding ;; more support to reload for implicit sign_extend operators. (define_insn "paradoxical_extendhidi2" [(set (match_operand:DI 0 "register_operand" "=d,d") (sign_extend:DI (subreg:SI (match_operand:HI 1 "memory_operand" "R,m") 0)))] "TARGET_64BIT" " { return mips_move_1word (operands, insn, TRUE); }" [(set_attr "type" "load,load") (set_attr "mode" "DI") (set_attr "length" "4,8")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d") (zero_extend:DI (match_operand:QI 1 "memory_operand" "R,m")))] "TARGET_64BIT && TARGET_MIPS16" "* return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "load,load") (set_attr "mode" "DI") (set_attr "length" "4,8")]) ;; ;; .................... ;; ;; SIGN EXTENSION ;; ;; ....................

;; Extension insns. ;; Those for integer source operand are ordered widest source type first.

;; In 64 bit mode, 32 bit values in general registers are always ;; correctly sign extended. That means that if the target is a ;; general register, we can sign extend from SImode to DImode just by ;; doing a move. The matching define_insns are *movdi_internal2_extend ;; and *movdi_internal2_mips16.

(define_expand "extendsidi2" [(set (match_operand:DI 0 "register_operand" "") (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))] "TARGET_64BIT" "")

;; 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_INT (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" "4,8")])

(define_expand "extendhisi2" [(set (match_operand:SI 0 "register_operand" "") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] "" " { if (ISA_HAS_SEB_SEH) { emit_insn (gen_extendhisi2_hw (operands[0], force_reg (HImode, operands[1]))); DONE; }

if (optimize && GET_CODE (operands[1]) == MEM) operands[1] = force_not_mem (operands[1]);

if (GET_CODE (operands[1]) != MEM) { rtx op1 = gen_lowpart (SImode, operands[1]); rtx temp = gen_reg_rtx (SImode); rtx shift = GEN_INT (16);

  emit_insn (gen_ashlsi3 (temp, op1, shift));
  emit_insn (gen_ashrsi3 (operands[0], temp, shift));
  DONE;
}

}")

(define_insn "extendhisi2_hw" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] "ISA_HAS_SEB_SEH"
"seh\t%0,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "extendhisi2_internal" [(set (match_operand:SI 0 "register_operand" "=d,d") (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,m")))] "" "* return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "load") (set_attr "mode" "SI") (set_attr "length" "4,8")])

(define_expand "extendqihi2" [(set (match_operand:HI 0 "register_operand" "") (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] "" " { if (optimize && GET_CODE (operands[1]) == MEM) operands[1] = force_not_mem (operands[1]);

if (GET_CODE (operands[1]) != MEM) { rtx op0 = gen_lowpart (SImode, operands[0]); rtx op1 = gen_lowpart (SImode, operands[1]); rtx temp = gen_reg_rtx (SImode); rtx shift = GEN_INT (24);

  emit_insn (gen_ashlsi3 (temp, op1, shift));
  emit_insn (gen_ashrsi3 (op0, temp, shift));
  DONE;
}

}")

(define_insn "extendqihi2_internal" [(set (match_operand:HI 0 "register_operand" "=d,d") (sign_extend:HI (match_operand:QI 1 "memory_operand" "R,m")))] "" "* return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "load") (set_attr "mode" "SI") (set_attr "length" "4,8")])

(define_expand "extendqisi2" [(set (match_operand:SI 0 "register_operand" "") (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] "" " { if (ISA_HAS_SEB_SEH) { emit_insn (gen_extendqisi2_hw (operands[0], force_reg (QImode, operands[1]))); DONE; } if (optimize && GET_CODE (operands[1]) == MEM) operands[1] = force_not_mem (operands[1]);

if (GET_CODE (operands[1]) != MEM) { rtx op1 = gen_lowpart (SImode, operands[1]); rtx temp = gen_reg_rtx (SImode); rtx shift = GEN_INT (24);

  emit_insn (gen_ashlsi3 (temp, op1, shift));
  emit_insn (gen_ashrsi3 (operands[0], temp, shift));
  DONE;
}

}")

(define_insn "extendqisi2_hw" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))] "ISA_HAS_SEB_SEH"
"seb\t%0,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "extendqisi2_insn" [(set (match_operand:SI 0 "register_operand" "=d,d") (sign_extend:SI (match_operand:QI 1 "memory_operand" "R,m")))] "" "* return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "load") (set_attr "mode" "SI") (set_attr "length" "4,8")])

(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_INT (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" "4,8")])

(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_DOUBLE_FLOAT" "cvt.d.s\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF")])

;; ;; .................... ;; ;; CONVERSIONS ;; ;; ....................

(define_expand "fix_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (match_operand:DF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" { if (!ISA_HAS_TRUNC_W) { emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1])); DONE; } })

(define_insn "fix_truncdfsi2_insn" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (match_operand:DF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W" "trunc.w.d %0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "4")])

(define_insn "fix_truncdfsi2_macro" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (match_operand:DF 1 "register_operand" "f"))) (clobber (match_scratch:DF 2 "=d"))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W" "trunc.w.d %0,%1,%2" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "36")])

(define_expand "fix_truncsfsi2" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" { if (!ISA_HAS_TRUNC_W) { emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1])); DONE; } })

(define_insn "fix_truncsfsi2_insn" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W" "trunc.w.s %0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "4")])

(define_insn "fix_truncsfsi2_macro" [(set (match_operand:SI 0 "register_operand" "=f") (fix:SI (match_operand:SF 1 "register_operand" "f"))) (clobber (match_scratch:SF 2 "=d"))] "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W" "trunc.w.s %0,%1,%2" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "36")])

;;; ??? 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 "register_operand" "=f") (fix:DI (match_operand:DF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" "trunc.l.d %0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "4")])

;;; ??? 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 "register_operand" "=f") (fix:DI (match_operand:SF 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" "trunc.l.s %0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF") (set_attr "length" "4")])

(define_insn "floatsidf2" [(set (match_operand:DF 0 "register_operand" "=f") (float:DF (match_operand:SI 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "cvt.d.w\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "4")])

(define_insn "floatdidf2" [(set (match_operand:DF 0 "register_operand" "=f") (float:DF (match_operand:DI 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" "cvt.d.l\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF") (set_attr "length" "4")])

(define_insn "floatsisf2" [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:SI 1 "register_operand" "f")))] "TARGET_HARD_FLOAT" "cvt.s.w\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF") (set_attr "length" "4")])

(define_insn "floatdisf2" [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:DI 1 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" "cvt.s.l\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF") (set_attr "length" "4")])

(define_expand "fixuns_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "") (unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" " { rtx reg1 = gen_reg_rtx (DFmode); rtx reg2 = gen_reg_rtx (DFmode); rtx reg3 = gen_reg_rtx (SImode); rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); REAL_VALUE_TYPE offset;

real_2expN (&offset, 31);

if (reg1) /* turn off complaints about unreached code */ { emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode)); do_pending_stack_adjust ();

  emit_insn (gen_cmpdf (operands[1], reg1));
  emit_jump_insn (gen_bge (label1));

  emit_insn (gen_fix_truncdfsi2 (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_INT (trunc_int_for_mode
			     (BITMASK_HIGH, SImode)));

  emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
  emit_insn (gen_iorsi3 (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_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_2expN (&offset, 63);

if (reg1) /* turn off complaints about unreached code */ { emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (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_INT (BITMASK_HIGH));
  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" "")))] "TARGET_HARD_FLOAT" " { rtx reg1 = gen_reg_rtx (SFmode); rtx reg2 = gen_reg_rtx (SFmode); rtx reg3 = gen_reg_rtx (SImode); rtx label1 = gen_label_rtx (); rtx label2 = gen_label_rtx (); REAL_VALUE_TYPE offset;

real_2expN (&offset, 31);

if (reg1) /* turn off complaints about unreached code */ { emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode)); do_pending_stack_adjust ();

  emit_insn (gen_cmpsf (operands[1], reg1));
  emit_jump_insn (gen_bge (label1));

  emit_insn (gen_fix_truncsfsi2 (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_INT (trunc_int_for_mode
			     (BITMASK_HIGH, SImode)));

  emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
  emit_insn (gen_iorsi3 (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_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_2expN (&offset, 63);

if (reg1) /* turn off complaints about unreached code */ { emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (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_INT (BITMASK_HIGH));
  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;
}

}")

;; ;; .................... ;; ;; DATA MOVEMENT ;; ;; ....................

;; Bit field extract patterns which use lwl/lwr.

;; ??? There could be HImode variants for the ulh/ulhu/ush macros. ;; It isn't clear whether this will give better code.

;; Only specify the mode operand 1, the rest are assumed to be word_mode. (define_expand "extv" [(set (match_operand 0 "register_operand" "") (sign_extract (match_operand:QI 1 "memory_operand" "") (match_operand 2 "immediate_operand" "") (match_operand 3 "immediate_operand" "")))] "!TARGET_MIPS16" " { /* If the field does not start on a byte boundary, then fail. */ if (INTVAL (operands[3]) % 8 != 0) FAIL;

/* MIPS I and MIPS II can only handle a 32bit field. */ if (!TARGET_64BIT && INTVAL (operands[2]) != 32) FAIL;

/* MIPS III and MIPS IV can handle both 32bit and 64bit fields. */ if (TARGET_64BIT && INTVAL (operands[2]) != 64 && INTVAL (operands[2]) != 32) 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;

/* Change the mode to BLKmode for aliasing purposes. */ operands[1] = adjust_address (operands[1], BLKmode, 0); set_mem_size (operands[1], GEN_INT (INTVAL (operands[2]) / BITS_PER_UNIT));

/* Otherwise, emit a l[wd]l/l[wd]r pair to load the value. */ if (INTVAL (operands[2]) == 64) emit_insn (gen_movdi_uld (operands[0], operands[1])); else { if (TARGET_64BIT) { operands[0] = gen_lowpart (SImode, operands[0]); if (operands[0] == NULL_RTX) FAIL; } emit_insn (gen_movsi_ulw (operands[0], operands[1])); } DONE; }")

;; Only specify the mode operand 1, the rest are assumed to be word_mode. (define_expand "extzv" [(set (match_operand 0 "register_operand" "") (zero_extract (match_operand:QI 1 "memory_operand" "") (match_operand 2 "immediate_operand" "") (match_operand 3 "immediate_operand" "")))] "!TARGET_MIPS16" " { /* If the field does not start on a byte boundary, then fail. */ if (INTVAL (operands[3]) % 8 != 0) FAIL;

/* MIPS I and MIPS II can only handle a 32bit field. */ if (!TARGET_64BIT && INTVAL (operands[2]) != 32) FAIL;

/* MIPS III and MIPS IV can handle both 32bit and 64bit fields. */ if (TARGET_64BIT && INTVAL (operands[2]) != 64 && INTVAL (operands[2]) != 32) 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;

/* Change the mode to BLKmode for aliasing purposes. */ operands[1] = adjust_address (operands[1], BLKmode, 0); set_mem_size (operands[1], GEN_INT (INTVAL (operands[2]) / BITS_PER_UNIT));

/* Otherwise, emit a lwl/lwr pair to load the value. */ if (INTVAL (operands[2]) == 64) emit_insn (gen_movdi_uld (operands[0], operands[1])); else { if (TARGET_64BIT) { operands[0] = gen_lowpart (SImode, operands[0]); if (operands[0] == NULL_RTX) FAIL; } emit_insn (gen_movsi_ulw (operands[0], operands[1])); } DONE; }")

;; Only specify the mode operands 0, the rest are assumed to be word_mode. (define_expand "insv" [(set (zero_extract (match_operand:QI 0 "memory_operand" "") (match_operand 1 "immediate_operand" "") (match_operand 2 "immediate_operand" "")) (match_operand 3 "register_operand" ""))] "!TARGET_MIPS16" " { /* If the field does not start on a byte boundary, then fail. */ if (INTVAL (operands[2]) % 8 != 0) FAIL;

/* MIPS I and MIPS II can only handle a 32bit field. */ if (!TARGET_64BIT && INTVAL (operands[1]) != 32) FAIL;

/* MIPS III and MIPS IV can handle both 32bit and 64bit fields. */ if (TARGET_64BIT && INTVAL (operands[1]) != 64 && INTVAL (operands[1]) != 32) 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;

/* Change the mode to BLKmode for aliasing purposes. */ operands[0] = adjust_address (operands[0], BLKmode, 0); set_mem_size (operands[0], GEN_INT (INTVAL (operands[1]) / BITS_PER_UNIT));

/* Otherwise, emit a s[wd]l/s[wd]r pair to load the value. */ if (INTVAL (operands[1]) == 64) emit_insn (gen_movdi_usd (operands[0], operands[3])); else { if (TARGET_64BIT) { operands[3] = gen_lowpart (SImode, operands[3]); if (operands[3] == NULL_RTX) FAIL; } 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") (unspec:SI [(match_operand:BLK 1 "general_operand" "R,o")] UNSPEC_ULW))] "!TARGET_MIPS16" "* { rtx offset = const0_rtx; rtx addr = XEXP (operands[1], 0); rtx mem_addr = eliminate_constant_term (addr, &offset); const char *ret;

if (TARGET_STATS) mips_count_memory_refs (operands[1], 2);

/* The stack/frame pointers are always aligned, so we can convert to the faster lw if we are referencing an aligned stack location. */

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";

return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn); }" [(set_attr "type" "load,load") (set_attr "mode" "SI") (set_attr "length" "8,16")])

(define_insn "movsi_usw" [(set (match_operand:BLK 0 "memory_operand" "=R,o") (unspec:BLK [(match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")] UNSPEC_USW))] "!TARGET_MIPS16" "* { rtx offset = const0_rtx; rtx addr = XEXP (operands[0], 0); rtx mem_addr = eliminate_constant_term (addr, &offset);

if (TARGET_STATS) mips_count_memory_refs (operands[0], 2);

/* 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) & 3) == 0 && (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx)) return "sw\t%z1,%0";

return "usw\t%z1,%0"; }" [(set_attr "type" "store") (set_attr "mode" "SI") (set_attr "length" "8,16")])

;; Bit field extract patterns which use ldl/ldr.

;; unaligned double word moves generated by the bit field patterns

(define_insn "movdi_uld" [(set (match_operand:DI 0 "register_operand" "=&d,&d") (unspec:DI [(match_operand:BLK 1 "general_operand" "R,o")] UNSPEC_ULD))] "" "* { rtx offset = const0_rtx; rtx addr = XEXP (operands[1], 0); rtx mem_addr = eliminate_constant_term (addr, &offset); const char *ret;

if (TARGET_STATS) mips_count_memory_refs (operands[1], 2);

/* The stack/frame pointers are always aligned, so we can convert to the faster lw if we are referencing an aligned stack location. */

if ((INTVAL (offset) & 7) == 0 && (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx)) ret = "ld\t%0,%1"; else ret = "uld\t%0,%1";

return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn); }" [(set_attr "type" "load,load") (set_attr "mode" "SI") (set_attr "length" "8,16")])

(define_insn "movdi_usd" [(set (match_operand:BLK 0 "memory_operand" "=R,o") (unspec:BLK [(match_operand:DI 1 "reg_or_0_operand" "dJ,dJ")] UNSPEC_USD))] "" "* { rtx offset = const0_rtx; rtx addr = XEXP (operands[0], 0); rtx mem_addr = eliminate_constant_term (addr, &offset);

if (TARGET_STATS) mips_count_memory_refs (operands[0], 2);

/* 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) & 7) == 0 && (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx)) return "sd\t%z1,%0";

return "usd\t%z1,%0"; }" [(set_attr "type" "store") (set_attr "mode" "SI") (set_attr "length" "8,16")])

;; These two patterns support loading addresses with two instructions instead ;; of using the macro instruction la.

;; ??? mips_move_1word has support for HIGH, so this pattern may be ;; unnecessary.

(define_insn "high" [(set (match_operand:SI 0 "register_operand" "=r") (high:SI (match_operand:SI 1 "immediate_operand" "")))] "mips_split_addresses && !TARGET_MIPS16" "lui\t%0,%%hi(%1) # high" [(set_attr "type" "move")])

(define_insn "low" [(set (match_operand:SI 0 "register_operand" "=r") (lo_sum:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "immediate_operand" "")))] "mips_split_addresses && !TARGET_MIPS16" "addiu\t%0,%1,%%lo(%2) # low" [(set_attr "type" "arith") (set_attr "mode" "SI")])

;; 64-bit integer moves

;; Unlike most other insns, the move insns can't be split with ;; different predicates, because register spilling and other parts of ;; the compiler, have memoized the insn number already.

(define_expand "movdi" [(set (match_operand:DI 0 "nonimmediate_operand" "") (match_operand:DI 1 "general_operand" ""))] "" " { if (mips_split_addresses && mips_check_split (operands[1], DImode)) { enum machine_mode mode = GET_MODE (operands[0]); rtx tem = ((reload_in_progress | reload_completed) ? operands[0] : gen_reg_rtx (mode));

  emit_insn (gen_rtx_SET (VOIDmode, tem,
		      gen_rtx_HIGH (mode, operands[1])));

  operands[1] = gen_rtx_LO_SUM (mode, tem, operands[1]);
}

/* 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_reg (),
		   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;
}

/* On the mips16, we can handle a GP relative reference by adding in $gp. We need to check the name to see whether this is a string constant. */ if (TARGET_MIPS16 && register_operand (operands[0], DImode) && GET_CODE (operands[1]) == SYMBOL_REF && SYMBOL_REF_FLAG (operands[1])) { const char *name = XSTR (operands[1], 0);

  if (name[0] != '*'
  || strncmp (name + 1, LOCAL_LABEL_PREFIX,
	      sizeof LOCAL_LABEL_PREFIX - 1) != 0)
{
  rtx base_reg;

  if (reload_in_progress || reload_completed)
    {
      /* In movsi we use the constant table here.  However, in
             this case, we're better off copying $28 into a
             register and adding, because the constant table entry
             would be 8 bytes.  */
      base_reg = operands[0];
      emit_move_insn (base_reg,
		      gen_rtx (CONST, DImode,
			       gen_rtx (REG, DImode,
					GP_REG_FIRST + 28)));
    }
  else
    {
      base_reg = gen_reg_rtx (Pmode);
      emit_move_insn (base_reg, mips16_gp_pseudo_reg ());
    }

  emit_move_insn (operands[0],
		  gen_rtx (PLUS, Pmode, base_reg,
			   mips16_gp_offset (operands[1])));
  DONE;
}
}

if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], DImode) && !register_operand (operands[1], DImode) && (TARGET_MIPS16 || ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0) && operands[1] != CONST0_RTX (DImode)))) { rtx temp = force_reg (DImode, operands[1]); emit_move_insn (operands[0], temp); DONE; } }")

;; For mips16, we need a special case to handle storing $31 into ;; memory, since we don't have a constraint to match $31. This ;; instruction can be generated by save_restore_insns.

(define_insn "" [(set (match_operand:DI 0 "memory_operand" "=R,m") (reg:DI 31))] "TARGET_MIPS16 && TARGET_64BIT" "* { operands[1] = gen_rtx (REG, DImode, 31); return mips_move_2words (operands, insn); }" [(set_attr "type" "store") (set_attr "mode" "DI") (set_attr "length" "4,8")])

(define_insn "movdi_internal" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,x,d,x,BCD,BCD,BCD,*d,*m,*R") (match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,d,d,m,R,BCD,BCD,BCD"))] "!TARGET_64BIT && !TARGET_MIPS16 && (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,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "DI") (set_attr "length" "8,16,8,16,8,16,8,8,8,8,8,8,8,8,8")])

(define_insn "" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,To,*d") (match_operand:DI 1 "general_operand" "d,d,y,K,N,R,To,d,d,x"))] "!TARGET_64BIT && TARGET_MIPS16 && (register_operand (operands[0], DImode) || register_operand (operands[1], DImode))" " return mips_move_2words (operands, insn);" [(set_attr "type" "move,move,move,arith,arith,load,load,store,store,hilo") (set_attr "mode" "DI") (set_attr "length" "8,8,8,8,12,8,16,8,16,8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (match_operand:DI 1 "register_operand" ""))] "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) 4) (subreg:SI (match_dup 1) 4))] "")

(define_insn "movdi_internal2" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,*f,*d,*R,*m,*x,d,x,a,BCD,BCD,BCD,*d,*m,*R") (match_operand:DI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,dJ,*R,*m,*f,*f,*f,*J,*x,*d,J,d,m,R,BCD,BCD,BCD"))] "TARGET_64BIT && !TARGET_MIPS16 && (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,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "DI") (set_attr "length" "4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,8,8,8,8,8,8,8")])

;; Sign-extended operands are reloaded using this instruction, so the ;; constraints must handle every SImode source operand X and destination ;; register R for which: ;; ;; mips_secondary_reload_class (CLASS_OF (R), DImode, true, ;; gen_rtx_SIGN_EXTEND (DImode, X)) ;; ;; returns NO_REGS. Also handle memory destinations, where allowed. ;; ;; This pattern is essentially a trimmed-down version of movdi_internal2. ;; The main difference is that dJ -> f and f -> d are the only constraints ;; involving float registers. See mips_secondary_reload_class for details. (define_insn "*movdi_internal2_extend" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*d,*f,*x,d,x,a,BCD,BCD,BCD,*d,*m,*R") (sign_extend:DI (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,dJ,*J,*x,*d,J,d,m,R,BCD,BCD,BCD")))] "TARGET_64BIT && !TARGET_MIPS16 && (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_sign_extend (insn, operands[0], operands[1]);" [(set_attr "type" "move,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "DI") (set_attr "length" "4,4,8,4,8,4,8,4,4,4,4,4,8,8,8,8,8,8,8")])

(define_insn "*movdi_internal2_mips16" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d") (match_operand:DI 1 "movdi_operand" "d,d,y,K,N,s,R,m,d,d,x"))] "TARGET_64BIT && TARGET_MIPS16 && (register_operand (operands[0], DImode) || se_register_operand (operands[1], DImode))" " return mips_move_2words (operands, insn);" [(set_attr "type" "move,move,move,arith,arith,arith,load,load,store,store,hilo") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) (const_int 4) (const_int 4) (if_then_else (match_operand:VOID 1 "m16_uimm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "") (const_int 8) (const_int 12)) (if_then_else (match_operand:VOID 1 "m16_usym5_4" "") (const_int 4) (const_int 8)) (const_int 4) (const_int 8) (const_int 4) (const_int 8) (const_int 4)])])

;; On the mips16, we can split ld $r,N($r) into an add and a load, ;; when the original load is a 4 byte instruction but the add and the ;; load are 2 2 byte instructions.

(define_split [(set (match_operand:DI 0 "register_operand" "") (mem:DI (plus:DI (match_dup 0) (match_operand:DI 1 "const_int_operand" ""))))] "TARGET_64BIT && TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x10) || (INTVAL (operands[1]) >= 32 * 8 && INTVAL (operands[1]) <= 31 * 8 + 0x8) || (INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) < 32 * 8 && (INTVAL (operands[1]) & 7) != 0))" [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) (set (match_dup 0) (mem:DI (plus:DI (match_dup 0) (match_dup 2))))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val < 0) operands[2] = GEN_INT (0); else if (val >= 32 * 8) { int off = val & 7;

  operands[1] = GEN_INT (0x8 + off);
  operands[2] = GEN_INT (val - off - 0x8);
}

else { int off = val & 7;

  operands[1] = GEN_INT (off);
  operands[2] = GEN_INT (val - off);
}

}")

;; 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 "" "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, hi_word, lo_word; rtx addr = find_replacement (&XEXP (operands[1], 0)); rtx op1 = replace_equiv_address (operands[1], addr);

  scratch = gen_rtx_REG (SImode, REGNO (scratch));
  memword = adjust_address (op1, SImode, 0);
  offword = adjust_address (op1, SImode, 4);

  if (BYTES_BIG_ENDIAN)
    {
      hi_word = memword;
      lo_word = offword;
    }
  else
    {
      hi_word = offword;
      lo_word = memword;
    }
  emit_move_insn (scratch, hi_word);
  emit_move_insn (gen_rtx_REG (SImode, 64), scratch);
  emit_move_insn (scratch, lo_word);
  emit_move_insn (gen_rtx (REG, SImode, 65), scratch);
  emit_insn (gen_hilo_delay (operands[0]));
}
  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));
      emit_insn (gen_hilo_delay (operands[0]));
}
  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)); emit_insn (gen_hilo_delay (operands[1])); 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.

;; Reloading HILO_REG in MIPS16 mode requires two scratch registers, so we ;; use a TImode scratch reg.

(define_expand "reload_outdi" [(set (match_operand:DI 0 "general_operand" "=b") (match_operand:DI 1 "se_register_operand" "b")) (clobber (match_operand:TI 2 "register_operand" "=&d"))] "TARGET_64BIT" " { rtx scratch = gen_rtx_REG (DImode, REGNO (operands[2]));

if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM) { 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)); emit_insn (gen_hilo_delay (operands[0])); DONE; } if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM) { if (GET_CODE (operands[0]) == MEM) { rtx scratch, memword, offword, hi_word, lo_word; rtx addr = find_replacement (&XEXP (operands[0], 0)); rtx op0 = replace_equiv_address (operands[0], addr);

  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
  memword = adjust_address (op0, SImode, 0);
  offword = adjust_address (op0, SImode, 4);

  if (BYTES_BIG_ENDIAN)
    {
      hi_word = memword;
      lo_word = offword;
    }
  else
    {
      hi_word = offword;
      lo_word = memword;
    }
  emit_move_insn (scratch, gen_rtx_REG (SImode, 64));
  emit_move_insn (hi_word, scratch);
  emit_move_insn (scratch, gen_rtx_REG (SImode, 65));
  emit_move_insn (lo_word, scratch);
  emit_insn (gen_hilo_delay (operands[1]));
}
  else if (TARGET_MIPS16 && ! M16_REG_P (REGNO (operands[0])))
{
  /* Handle the case where operand[0] is not a 'd' register,
     and hence we can not directly move from the HILO register
     into it.  */
  rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1);
  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 (scratch2, gen_rtx (REG, DImode, 64)));
  emit_insn (gen_ashldi3 (scratch2, scratch2, GEN_INT (32)));
  emit_insn (gen_iordi3 (scratch, scratch, scratch2));
  emit_insn (gen_movdi (operands[0], scratch));
  emit_insn (gen_hilo_delay (operands[1]));
}
  else
{
  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));
  emit_insn (gen_hilo_delay (operands[1]));
}
  DONE;
}

/* This handles moves between a float register and HI/LO. */ emit_move_insn (scratch, operands[1]); emit_move_insn (operands[0], scratch); DONE; }")

;; 32-bit Integer moves

(define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "large_int" ""))] "!TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 3)))] " { operands[2] = GEN_INT (trunc_int_for_mode (INTVAL (operands[1]) & BITMASK_UPPER16, SImode)); operands[3] = GEN_INT (INTVAL (operands[1]) & BITMASK_LOWER16); }")

;; Unlike most other insns, the move insns can't be split with ;; different predicates, because register spilling and other parts of ;; the compiler, have memoized the insn number already.

(define_expand "movsi" [(set (match_operand:SI 0 "nonimmediate_operand" "") (match_operand:SI 1 "general_operand" ""))] "" " { if (mips_split_addresses && mips_check_split (operands[1], SImode)) { enum machine_mode mode = GET_MODE (operands[0]); rtx tem = ((reload_in_progress | reload_completed) ? operands[0] : gen_reg_rtx (mode));

  emit_insn (gen_rtx_SET (VOIDmode, tem,
		      gen_rtx_HIGH (mode, operands[1])));

  operands[1] = gen_rtx_LO_SUM (mode, tem, operands[1]);
}

/* 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_reg (),
		   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;
}

/* On the mips16, we can handle a GP relative reference by adding in $gp. We need to check the name to see whether this is a string constant. */ if (TARGET_MIPS16 && register_operand (operands[0], SImode) && GET_CODE (operands[1]) == SYMBOL_REF && SYMBOL_REF_FLAG (operands[1])) { const char *name = XSTR (operands[1], 0);

  if (name[0] != '*'
  || strncmp (name + 1, LOCAL_LABEL_PREFIX,
	      sizeof LOCAL_LABEL_PREFIX - 1) != 0)
{
  rtx base_reg;

  if (reload_in_progress || reload_completed)
    {
      /* We need to reload this address.  In this case we
             aren't going to have a chance to combine loading the
             address with the load or store.  That means that we
             can either generate a 2 byte move followed by a 4
             byte addition, or a 2 byte load with a 4 byte entry
             in the constant table.  Since the entry in the
             constant table might be shared, we're better off, on
             average, loading the address from the constant table.  */
      emit_move_insn (operands[0],
		      force_const_mem (SImode, operands[1]));
      DONE;
    }

  base_reg = gen_reg_rtx (Pmode);
  emit_move_insn (base_reg, mips16_gp_pseudo_reg ());

  emit_move_insn (operands[0],
		  gen_rtx (PLUS, Pmode, base_reg,
			   mips16_gp_offset (operands[1])));
  DONE;
}
}

if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], SImode) && !register_operand (operands[1], SImode) && (TARGET_MIPS16 || GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)) { rtx temp = force_reg (SImode, operands[1]); emit_move_insn (operands[0], temp); DONE; } }")

;; We can only store $ra directly into a small sp offset. Should the ;; offset be too wide, non-constant or not sp-based, leave it up to ;; reload to choose a scratch register.

(define_insn "" [(set (mem:SI (plus:SI (reg:SI 29) (match_operand:SI 0 "small_int" "n"))) (reg:SI 31))] "TARGET_MIPS16" "sw\t$31,%0($sp)" [(set_attr "type" "store") (set_attr "mode" "SI") (set_attr_alternative "length" [(if_then_else (lt (symbol_ref "(unsigned HOST_WIDE_INT) INTVAL (operands[0])") (const_int 1024)) (const_int 4) (const_int 8))])])

;; The difference between these two is whether or not ints are allowed ;; in FP registers (off by default, use -mdebugh to enable).

(define_insn "movsi_internal" [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m,*f,*f,*f,?*f,*d,*R,*m,*d,*z,*x,d,x,d,BCD,BCD,BCD,*d,*m,*R") (match_operand:SI 1 "move_operand" "d,IKL,Mnis,R,m,dJ,dJ,*f,dJ,*R,*m,*f,*f,*f,*z,*d,J,*x,*d,a,d,m,R,BCD,BCD,BCD"))] "!TARGET_MIPS16 && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" " return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "move,arith,arith,load,load,store,store,move,xfer,load,load,xfer,store,store,xfer,xfer,hilo,hilo,hilo,hilo,xfer,load,load,xfer,store,store") (set_attr "mode" "SI") (set_attr "length" "4,4,8,4,8,4,8,4,4,4,8,4,4,8,4,4,4,4,4,4,4,4,8,4,4,8")])

;; This is the mips16 movsi instruction. We accept a small integer as ;; the source if the destination is a GP memory reference. This is ;; because we want the combine pass to turn adding a GP reference to a ;; register into a direct GP reference, but the combine pass will pass ;; in the source as a constant if it finds an equivalent one. If the ;; instruction is recognized, reload will force the constant back out ;; into a register.

(define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,R,m,*d,*d") (match_operand:SI 1 "move_operand" "d,d,y,K,N,s,R,m,d,d,*x,a"))] "TARGET_MIPS16 && (register_operand (operands[0], SImode) || register_operand (operands[1], SImode) || (GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == PLUS && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST && mips16_gp_offset_p (XEXP (XEXP (operands[0], 0), 1)) && GET_CODE (operands[1]) == CONST_INT && (SMALL_INT (operands[1]) || SMALL_INT_UNSIGNED (operands[1]))))" " return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "move,move,move,arith,arith,arith,load,load,store,store,hilo,hilo") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (const_int 4) (const_int 4) (if_then_else (match_operand:VOID 1 "m16_uimm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "") (const_int 8) (const_int 12)) (if_then_else (match_operand:VOID 1 "m16_usym8_4" "") (const_int 4) (const_int 8)) (const_int 4) (const_int 8) (const_int 4) (const_int 8) (const_int 4) (const_int 4)])])

;; On the mips16, we can split lw $r,N($r) into an add and a load, ;; when the original load is a 4 byte instruction but the add and the ;; load are 2 2 byte instructions.

(define_split [(set (match_operand:SI 0 "register_operand" "") (mem:SI (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x80) || (INTVAL (operands[1]) >= 32 * 4 && INTVAL (operands[1]) <= 31 * 4 + 0x7c) || (INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) < 32 * 4 && (INTVAL (operands[1]) & 3) != 0))" [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) (set (match_dup 0) (mem:SI (plus:SI (match_dup 0) (match_dup 2))))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val < 0) operands[2] = GEN_INT (0); else if (val >= 32 * 4) { int off = val & 3;

  operands[1] = GEN_INT (0x7c + off);
  operands[2] = GEN_INT (val - off - 0x7c);
}

else { int off = val & 3;

  operands[1] = GEN_INT (off);
  operands[2] = GEN_INT (val - off);
}

}")

;; On the mips16, we can split a load of certain constants into a load ;; and an add. This turns a 4 byte instruction into 2 2 byte ;; instructions.

(define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) >= 0x100 && INTVAL (operands[1]) <= 0xff + 0x7f" [(set (match_dup 0) (match_dup 1)) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] " { int val = INTVAL (operands[1]);

operands[1] = GEN_INT (0xff); operands[2] = GEN_INT (val - 0xff); }")

;; On the mips16, we can split a load of a negative constant into a ;; load and a neg. That's what mips_move_1word will generate anyhow.

(define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > - 0x8000" [(set (match_dup 0) (match_dup 1)) (set (match_dup 0) (neg:SI (match_dup 0)))] " { operands[1] = GEN_INT (- INTVAL (operands[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" "b")) (clobber (match_operand:SI 2 "register_operand" "=&d"))] "TARGET_64BIT || TARGET_MIPS16" " { if (TARGET_64BIT && 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])); emit_insn (gen_hilo_delay (operands[0])); DONE; } /* Use a mult to reload LO on mips16. ??? This is hideous. / if (TARGET_MIPS16 && GET_CODE (operands[0]) == REG && REGNO (operands[0]) == LO_REGNUM) { emit_insn (gen_movsi (operands[2], GEN_INT (1))); / This is gen_mulsi3_internal, but we need to fill in the scratch registers. / emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3, gen_rtx (SET, VOIDmode, operands[0], gen_rtx (MULT, SImode, operands[1], operands[2])), gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 64)), gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 66))))); DONE; } / FIXME: I don't know how to get a value into the HI register. / if (GET_CODE (operands[0]) == REG && (TARGET_MIPS16 ? M16_REG_P (REGNO (operands[0])) : GP_REG_P (REGNO (operands[0])))) { emit_move_insn (operands[0], operands[1]); 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; }")

;; Reload a value into HI or LO. There is no mthi or mtlo on mips16, ;; so we use a mult. ??? This is hideous, and we ought to figure out ;; something better.

;; We use no predicate for operand1, because it may be a PLUS, and there ;; is no convenient predicate for that.

(define_expand "reload_insi" [(set (match_operand:SI 0 "register_operand" "=b") (match_operand:SI 1 "" "b")) (clobber (match_operand:SI 2 "register_operand" "=&d"))] "TARGET_MIPS16" " { if (TARGET_MIPS16 && GET_CODE (operands[0]) == REG && REGNO (operands[0]) == LO_REGNUM) { emit_insn (gen_movsi (operands[2], GEN_INT (1))); /* This is gen_mulsi3_internal, but we need to fill in the scratch registers. */ emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (3, gen_rtx (SET, VOIDmode, operands[0], gen_rtx (MULT, SImode, operands[1], operands[2])), gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 64)), gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 66))))); DONE; }

/* If this is a plus, then this must be an add of the stack pointer against either a hard register or a pseudo. */ if (TARGET_MIPS16 && GET_CODE (operands[1]) == PLUS) { rtx plus_op;

  if (XEXP (operands[1], 0) == stack_pointer_rtx)
plus_op = XEXP (operands[1], 1);
  else if (XEXP (operands[1], 1) == stack_pointer_rtx)
plus_op = XEXP (operands[1], 0);
  else
abort ();

  /* We should have a register now.  */
  if (GET_CODE (plus_op) != REG)
abort ();

  if (REGNO (plus_op) < FIRST_PSEUDO_REGISTER)
{
  /* We have to have at least one temporary register which is not
     overlapping plus_op.  */
  if (! rtx_equal_p (plus_op, operands[0]))
    {
      emit_move_insn (operands[0], stack_pointer_rtx);
      emit_insn (gen_addsi3 (operands[0], operands[0], plus_op));
    }
  else if (! rtx_equal_p (plus_op, operands[2]))
    {
      emit_move_insn (operands[2], stack_pointer_rtx);
      emit_insn (gen_addsi3 (operands[0], plus_op, operands[2]));
    }
  else
    abort ();
}
  else
{
  /* We need two registers in this case.  */
  if (! rtx_equal_p (operands[0], operands[2]))
    {
      emit_move_insn (operands[0], stack_pointer_rtx);
      emit_move_insn (operands[2], plus_op);
      emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
    }
  else
    abort ();
}
  DONE;
}

/* FIXME: I don't know how to get a value into the HI register. */ emit_move_insn (operands[0], operands[1]); DONE; }")

;; This insn is for the unspec delay for HILO.

(define_insn "hilo_delay" [(unspec [(match_operand 0 "register_operand" "=b")] UNSPEC_HILO_DELAY)] "" "" [(set_attr "type" "nop") (set_attr "mode" "none") (set_attr "can_delay" "no")])

;; This insn handles moving CCmode values. It's really just a ;; slightly simplified copy of movsi_internal2, with additional cases ;; to move a condition register to a general register and to move ;; between the general registers and the floating point registers.

(define_insn "movcc" [(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*d,*R,*m,*d,*f,*f,*f,*f,*R,*m") (match_operand:CC 1 "general_operand" "z,*d,*R,*m,*d,*d,*f,*d,*f,*R,*m,*f,f"))] "ISA_HAS_8CC && TARGET_HARD_FLOAT" " return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "move,move,load,load,store,store,xfer,xfer,move,load,load,store,store") (set_attr "mode" "SI") (set_attr "length" "8,4,4,8,4,8,4,4,4,4,8,4,8")])

;; Reload condition code registers. reload_incc and reload_outcc ;; both handle moves from arbitrary operands into condition code ;; registers. reload_incc handles the more common case in which ;; a source operand is constrained to be in a condition-code ;; register, but has not been allocated to one. ;; ;; Sometimes, such as in movcc, we have a CCmode destination whose ;; constraints do not include 'z'. reload_outcc handles the case ;; when such an operand is allocated to a condition-code register. ;; ;; Note that reloads from a condition code register to some ;; other location can be done using ordinary moves. Moving ;; into a GPR takes a single movcc, moving elsewhere takes ;; two. We can leave these cases to the generic reload code. (define_expand "reload_incc" [(set (match_operand:CC 0 "fcc_register_operand" "=z") (match_operand:CC 1 "general_operand" "")) (clobber (match_operand:TF 2 "register_operand" "=&f"))] "ISA_HAS_8CC && TARGET_HARD_FLOAT" " { mips_emit_fcc_reload (operands[0], operands[1], operands[2]); DONE; }")

(define_expand "reload_outcc" [(set (match_operand:CC 0 "fcc_register_operand" "=z") (match_operand:CC 1 "register_operand" "")) (clobber (match_operand:TF 2 "register_operand" "=&f"))] "ISA_HAS_8CC && TARGET_HARD_FLOAT" " { mips_emit_fcc_reload (operands[0], operands[1], operands[2]); DONE; }")

;; MIPS4 supports loading and storing a floating point register from ;; the sum of two general registers. We use two versions for each of ;; these four instructions: one where the two general registers are ;; SImode, and one where they are DImode. This is because general ;; registers will be in SImode when they hold 32 bit values, but, ;; since the 32 bit values are always sign extended, the [ls][wd]xc1 ;; instructions will still work correctly.

;; ??? Perhaps it would be better to support these instructions by ;; modifying GO_IF_LEGITIMATE_ADDRESS and friends. However, since ;; these instructions can only be used to load and store floating ;; point registers, that would probably cause trouble in reload.

(define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT" "lwxc1\t%0,%1(%2)" [(set_attr "type" "load") (set_attr "mode" "SF")])

(define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (mem:SF (plus:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT" "lwxc1\t%0,%1(%2)" [(set_attr "type" "load") (set_attr "mode" "SF")])

(define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "ldxc1\t%0,%1(%2)" [(set_attr "type" "load") (set_attr "mode" "DF")])

(define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (mem:DF (plus:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "ldxc1\t%0,%1(%2)" [(set_attr "type" "load") (set_attr "mode" "DF")])

(define_insn "" [(set (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (match_operand:SF 0 "register_operand" "f"))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT" "swxc1\t%0,%1(%2)" [(set_attr "type" "store") (set_attr "mode" "SF")])

(define_insn "" [(set (mem:SF (plus:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (match_operand:SF 0 "register_operand" "f"))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT" "swxc1\t%0,%1(%2)" [(set_attr "type" "store") (set_attr "mode" "SF")])

(define_insn "" [(set (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (match_operand:DF 0 "register_operand" "f"))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "sdxc1\t%0,%1(%2)" [(set_attr "type" "store") (set_attr "mode" "DF")])

(define_insn "" [(set (mem:DF (plus:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d"))) (match_operand:DF 0 "register_operand" "f"))] "ISA_HAS_FP4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "sdxc1\t%0,%1(%2)" [(set_attr "type" "store") (set_attr "mode" "DF")])

;; 16-bit Integer moves

;; Unlike most other insns, the move insns can't be split with ;; different predicates, because register spilling and other parts of ;; the compiler, have memoized the insn number already. ;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined

(define_expand "movhi" [(set (match_operand:HI 0 "nonimmediate_operand" "") (match_operand:HI 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], HImode) && !register_operand (operands[1], HImode) && (TARGET_MIPS16 || (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))) { rtx temp = force_reg (HImode, operands[1]); emit_move_insn (operands[0], temp); DONE; } }")

;; The difference between these two is whether or not ints are allowed ;; in FP registers (off by default, use -mdebugh to enable).

(define_insn "movhi_internal" [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,fz,*f,*x,*d") (match_operand:HI 1 "general_operand" "d,IK,R,m,dJ,dJ,fz,*d,*f,*d,x"))] "!TARGET_MIPS16 && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" " return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo") (set_attr "mode" "HI") (set_attr "length" "4,4,4,8,4,8,4,4,4,4,4")])

(define_insn "" [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d") (match_operand:HI 1 "general_operand" "d,d,y,K,N,R,m,d,d,x"))] "TARGET_MIPS16 && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" " return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "move,move,move,arith,arith,load,load,store,store,hilo") (set_attr "mode" "HI") (set_attr_alternative "length" [(const_int 4) (const_int 4) (const_int 4) (if_then_else (match_operand:VOID 1 "m16_uimm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "") (const_int 8) (const_int 12)) (const_int 4) (const_int 8) (const_int 4) (const_int 8) (const_int 4)])])

;; On the mips16, we can split lh $r,N($r) into an add and a load, ;; when the original load is a 4 byte instruction but the add and the ;; load are 2 2 byte instructions.

(define_split [(set (match_operand:HI 0 "register_operand" "") (mem:HI (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x80) || (INTVAL (operands[1]) >= 32 * 2 && INTVAL (operands[1]) <= 31 * 2 + 0x7e) || (INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) < 32 * 2 && (INTVAL (operands[1]) & 1) != 0))" [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) (set (match_dup 0) (mem:HI (plus:SI (match_dup 0) (match_dup 2))))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val < 0) operands[2] = GEN_INT (0); else if (val >= 32 * 2) { int off = val & 1;

  operands[1] = GEN_INT (0x7e + off);
  operands[2] = GEN_INT (val - off - 0x7e);
}

else { int off = val & 1;

  operands[1] = GEN_INT (off);
  operands[2] = GEN_INT (val - off);
}

}")

;; 8-bit Integer moves

;; Unlike most other insns, the move insns can't be split with ;; different predicates, because register spilling and other parts of ;; the compiler, have memoized the insn number already. ;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined

(define_expand "movqi" [(set (match_operand:QI 0 "nonimmediate_operand" "") (match_operand:QI 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], QImode) && !register_operand (operands[1], QImode) && (TARGET_MIPS16 || (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))) { rtx temp = force_reg (QImode, operands[1]); emit_move_insn (operands[0], temp); DONE; } }")

;; The difference between these two is whether or not ints are allowed ;; in FP registers (off by default, use -mdebugh to enable).

(define_insn "movqi_internal" [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,fz,*f,*x,*d") (match_operand:QI 1 "general_operand" "d,IK,R,m,dJ,dJ,fz,*d,*f,*d,x"))] "!TARGET_MIPS16 && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode) || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" " return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo") (set_attr "mode" "QI") (set_attr "length" "4,4,4,8,4,8,4,4,4,4,4")])

(define_insn "" [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,R,m,*d") (match_operand:QI 1 "general_operand" "d,d,y,K,N,R,m,d,d,x"))] "TARGET_MIPS16 && (register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" " return mips_move_1word (operands, insn, TRUE);" [(set_attr "type" "move,move,move,arith,arith,load,load,store,store,hilo") (set_attr "mode" "QI") (set_attr_alternative "length" [(const_int 4) (const_int 4) (const_int 4) (if_then_else (match_operand:VOID 1 "m16_uimm8_1" "") (const_int 4) (const_int 8)) (if_then_else (match_operand:VOID 1 "m16_nuimm8_1" "") (const_int 8) (const_int 12)) (const_int 4) (const_int 8) (const_int 4) (const_int 8) (const_int 4)])])

;; On the mips16, we can split lb $r,N($r) into an add and a load, ;; when the original load is a 4 byte instruction but the add and the ;; load are 2 2 byte instructions.

(define_split [(set (match_operand:QI 0 "register_operand" "") (mem:QI (plus:SI (match_dup 0) (match_operand:SI 1 "const_int_operand" ""))))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == CONST_INT && ((INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -0x80) || (INTVAL (operands[1]) >= 32 && INTVAL (operands[1]) <= 31 + 0x7f))" [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) (set (match_dup 0) (mem:QI (plus:SI (match_dup 0) (match_dup 2))))] " { HOST_WIDE_INT val = INTVAL (operands[1]);

if (val < 0) operands[2] = GEN_INT (0); else { operands[1] = GEN_INT (0x7f); operands[2] = GEN_INT (val - 0x7f); } }")

;; 32-bit floating point moves

(define_expand "movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], SFmode) && !nonmemory_operand (operands[1], SFmode)) operands[1] = force_reg (SFmode, operands[1]); }")

(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,m,fG,fG,*d,*f,Gd,*R,*m,*d,d"))] "TARGET_HARD_FLOAT && (register_operand (operands[0], SFmode) || nonmemory_operand (operands[1], SFmode))" " return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "move,xfer,load,load,store,store,xfer,xfer,move,load,load,store,store") (set_attr "mode" "SF") (set_attr "length" "4,4,4,8,4,8,4,4,4,4,8,4,8")])

(define_insn "movsf_internal2" [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,R,m") (match_operand:SF 1 "general_operand" " Gd,R,m,d,d"))] "TARGET_SOFT_FLOAT && !TARGET_MIPS16 && (register_operand (operands[0], SFmode) || nonmemory_operand (operands[1], SFmode))" "* return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "move,load,load,store,store") (set_attr "mode" "SF") (set_attr "length" "4,4,8,4,8")])

(define_insn "" [(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,d,R,m") (match_operand:SF 1 "nonimmediate_operand" "d,d,y,R,m,d,d"))] "TARGET_MIPS16 && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" "* return mips_move_1word (operands, insn, FALSE);" [(set_attr "type" "move,move,move,load,load,store,store") (set_attr "mode" "SF") (set_attr "length" "4,4,4,4,8,4,8")])

;; 64-bit floating point moves

(define_expand "movdf" [(set (match_operand:DF 0 "nonimmediate_operand" "") (match_operand:DF 1 "general_operand" ""))] "" " { if ((reload_in_progress | reload_completed) == 0 && !register_operand (operands[0], DFmode) && !nonmemory_operand (operands[1], DFmode)) operands[1] = force_reg (DFmode, operands[1]); }")

(define_insn "movdf_internal1" [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,f,R,To,*f,*d,*d,*d,*d,*R,*T") (match_operand:DF 1 "general_operand" "f,G,R,To,fG,fG,*d,*f,dG,*R,*T,*d,d"))] "TARGET_HARD_FLOAT && !(TARGET_FLOAT64 && !TARGET_64BIT) && TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || nonmemory_operand (operands[1], DFmode))" " return mips_move_2words (operands, insn); " [(set_attr "type" "move,move,load,load,store,store,xfer,xfer,move,load,load,store,store") (set_attr "mode" "DF") (set_attr "length" "4,8,8,16,8,16,8,8,8,8,16,8,16")])

(define_insn "movdf_internal1a" [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,R,R,To,To,*d,*d,*To,*R,*d") (match_operand:DF 1 "general_operand" " f,To,f,G,f,G,*To,*R,*d,*d,d"))] "TARGET_HARD_FLOAT && (TARGET_FLOAT64 && !TARGET_64BIT) && TARGET_DOUBLE_FLOAT && (register_operand (operands[0], DFmode) || nonmemory_operand (operands[1], DFmode))" " return mips_move_2words (operands, insn); " [(set_attr "type" "move,load,store,store,store,store,load,load,store,store,move") (set_attr "mode" "DF") (set_attr "length" "4,8,4,4,8,8,8,4,8,4,4")])

(define_insn "movdf_internal2" [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,R,To,d,f,f") (match_operand:DF 1 "general_operand" "dG,R,To,d,d,f,d,f"))] "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16 && (register_operand (operands[0], DFmode) || nonmemory_operand (operands[1], DFmode))" "* return mips_move_2words (operands, insn); " [(set_attr "type" "move,load,load,store,store,xfer,load,move") (set_attr "mode" "DF") (set_attr "length" "8,8,16,8,16,8,8,4")])

(define_insn "" [(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,d,R,To") (match_operand:DF 1 "nonimmediate_operand" "d,d,y,R,To,d,d"))] "TARGET_MIPS16 && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" "* return mips_move_2words (operands, insn);" [(set_attr "type" "move,move,move,load,load,store,store") (set_attr "mode" "DF") (set_attr "length" "8,8,8,8,16,8,16")])

(define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "register_operand" ""))] "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) 4) (subreg:SI (match_dup 1) 4))] "")

;; 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:DI [(match_operand:DI 0 "address_operand" "") (match_operand:DI 1 "register_operand" "")] UNSPEC_LOADGP)) (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,%1%]" [(set_attr "type" "move") (set_attr "mode" "DI") (set_attr "length" "12")]) ;; Block moves, see mips.c for more details. ;; Argument 0 is the destination ;; Argument 1 is the source ;; Argument 2 is the length ;; Argument 3 is the alignment

(define_expand "movstrsi" [(parallel [(set (match_operand:BLK 0 "general_operand" "") (match_operand:BLK 1 "general_operand" "")) (use (match_operand:SI 2 "arith32_operand" "")) (use (match_operand:SI 3 "immediate_operand" ""))])] "!TARGET_MIPS16" " { if (operands[0]) /* avoid unused code messages */ { expand_block_move (operands); DONE; } }")

;; Insn generated by block moves

(define_insn "movstrsi_internal" [(set (match_operand:BLK 0 "memory_operand" "=o") ;; destination (match_operand:BLK 1 "memory_operand" "o")) ;; source (clobber (match_scratch:SI 4 "=&d")) ;; temp 1 (clobber (match_scratch:SI 5 "=&d")) ;; temp 2 (clobber (match_scratch:SI 6 "=&d")) ;; temp 3 (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 0))] ;; normal block move "" "* return output_block_move (insn, operands, 4, BLOCK_MOVE_NORMAL);" [(set_attr "type" "store") (set_attr "mode" "none") (set_attr "length" "80")])

;; We need mips16 versions, because an offset from the stack pointer ;; is not offsettable, since the stack pointer can only handle 4 and 8 ;; byte loads.

(define_insn "" [(set (match_operand:BLK 0 "memory_operand" "=o") ;; destination (match_operand:BLK 1 "memory_operand" "o")) ;; source (clobber (match_scratch:SI 4 "=&d")) ;; temp 1 (clobber (match_scratch:SI 5 "=&d")) ;; temp 2 (clobber (match_scratch:SI 6 "=&d")) ;; temp 3 (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 0))] ;; normal block move "TARGET_MIPS16" "* return output_block_move (insn, operands, 4, BLOCK_MOVE_NORMAL);" [(set_attr "type" "multi") (set_attr "mode" "none") (set_attr "length" "80")])

;; Split a block move into 2 parts, the first part is everything ;; except for the last move, and the second part is just the last ;; store, which is exactly 1 instruction (ie, not a usw), so it can ;; fill a delay slot. This also prevents a bug in delayed branches ;; from showing up, which reuses one of the registers in our clobbers.

;; ??? Disabled because it doesn't preserve alias information for ;; operands 0 and 1. Also, the rtl for the second insn doesn't mention ;; that it uses the registers clobbered by the first. ;; ;; It would probably be better to split the block into individual ;; instructions instead. (define_split [(set (mem:BLK (match_operand:SI 0 "register_operand" "")) (mem:BLK (match_operand:SI 1 "register_operand" ""))) (clobber (match_operand:SI 4 "register_operand" "")) (clobber (match_operand:SI 5 "register_operand" "")) (clobber (match_operand:SI 6 "register_operand" "")) (clobber (match_operand:SI 7 "register_operand" "")) (use (match_operand:SI 2 "small_int" "")) (use (match_operand:SI 3 "small_int" "")) (use (const_int 0))]

"reload_completed && 0 && INTVAL (operands[2]) > 0"

;; All but the last move [(parallel [(set (mem:BLK (match_dup 0)) (mem:BLK (match_dup 1))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6)) (clobber (match_dup 7)) (use (match_dup 2)) (use (match_dup 3)) (use (const_int 1))])

;; The last store, so it can fill a delay slot (parallel [(set (mem:BLK (match_dup 0)) (mem:BLK (match_dup 1))) (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 6)) (clobber (match_dup 7)) (use (match_dup 2)) (use (match_dup 3)) (use (const_int 2))])]

"")

(define_insn "movstrsi_internal2" [(set (match_operand:BLK 0 "memory_operand" "=o") ;; destination (match_operand:BLK 1 "memory_operand" "o")) ;; source (clobber (match_scratch:SI 4 "=&d")) ;; temp 1 (clobber (match_scratch:SI 5 "=&d")) ;; temp 2 (clobber (match_scratch:SI 6 "=&d")) ;; temp 3 (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 1))] ;; all but last store "" "* return output_block_move (insn, operands, 4, BLOCK_MOVE_NOT_LAST);" [(set_attr "type" "store") (set_attr "mode" "none") (set_attr "length" "80")])

(define_insn "" [(set (match_operand:BLK 0 "memory_operand" "=o") ;; destination (match_operand:BLK 1 "memory_operand" "o")) ;; source (clobber (match_scratch:SI 4 "=&d")) ;; temp 1 (clobber (match_scratch:SI 5 "=&d")) ;; temp 2 (clobber (match_scratch:SI 6 "=&d")) ;; temp 3 (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 1))] ;; all but last store "TARGET_MIPS16" "* return output_block_move (insn, operands, 4, BLOCK_MOVE_NOT_LAST);" [(set_attr "type" "multi") (set_attr "mode" "none") (set_attr "length" "80")])

(define_insn "movstrsi_internal3" [(set (match_operand:BLK 0 "memory_operand" "=Ro") ;; destination (match_operand:BLK 1 "memory_operand" "Ro")) ;; source (clobber (match_scratch:SI 4 "=&d")) ;; temp 1 (clobber (match_scratch:SI 5 "=&d")) ;; temp 2 (clobber (match_scratch:SI 6 "=&d")) ;; temp 3 (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 move "" "* return output_block_move (insn, operands, 4, BLOCK_MOVE_LAST);" [(set_attr "type" "store") (set_attr "mode" "none")]) ;; ;; .................... ;; ;; SHIFTS ;; ;; ....................

;; Many of these instructions uses trivial define_expands, because we ;; want to use a different set of constraints when TARGET_MIPS16.

(define_expand "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=d") (ashift:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "" " { /* On the mips16, a shift of more than 8 is a four byte instruction, so, for a shift between 8 and 16, it is just as fast to do two shifts of 8 or less. If there is a lot of shifting going on, we may win in CSE. Otherwise combine will put the shifts back together again. This can be called by function_arg, so we must be careful not to allocate a new register if we've reached the reload pass. */ if (TARGET_MIPS16 && optimize && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16 && ! reload_in_progress && ! reload_completed) { rtx temp = gen_reg_rtx (SImode);

  emit_insn (gen_ashlsi3_internal2 (temp, operands[1], GEN_INT (8)));
  emit_insn (gen_ashlsi3_internal2 (operands[0], temp,
				GEN_INT (INTVAL (operands[2]) - 8)));
  DONE;
}

}")

(define_insn "ashlsi3_internal1" [(set (match_operand:SI 0 "register_operand" "=d") (ashift:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "!TARGET_MIPS16" "* { if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);

return "sll\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "ashlsi3_internal2" [(set (match_operand:SI 0 "register_operand" "=d,d") (ashift:SI (match_operand:SI 1 "register_operand" "0,d") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_MIPS16" "* { if (which_alternative == 0) return "sll\t%0,%2";

if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);

return "sll\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 4) (const_int 8))])])

;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.

(define_split [(set (match_operand:SI 0 "register_operand" "") (ashift:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (ashift:SI (match_dup 1) (const_int 8))) (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] " { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }")

(define_expand "ashldi3" [(parallel [(set (match_operand:DI 0 "register_operand" "") (ashift:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:SI 2 "arith_operand" ""))) (clobber (match_dup 3))])] "TARGET_64BIT || (!TARGET_DEBUG_G_MODE && !TARGET_MIPS16)" " { if (TARGET_64BIT) { /* On the mips16, a shift of more than 8 is a four byte instruction, so, for a shift between 8 and 16, it is just as fast to do two shifts of 8 or less. If there is a lot of shifting going on, we may win in CSE. Otherwise combine will put the shifts back together again. This can be called by function_arg, so we must be careful not to allocate a new register if we've reached the reload pass. */ if (TARGET_MIPS16 && optimize && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16 && ! reload_in_progress && ! reload_completed) { rtx temp = gen_reg_rtx (DImode);

  emit_insn (gen_ashldi3_internal4 (temp, operands[1], GEN_INT (8)));
  emit_insn (gen_ashldi3_internal4 (operands[0], temp,
				    GEN_INT (INTVAL (operands[2]) - 8)));
  DONE;
}

  emit_insn (gen_ashldi3_internal4 (operands[0], operands[1],
				operands[2]));
  DONE;
}

operands[3] = gen_reg_rtx (SImode); }")

(define_insn "ashldi3_internal" [(set (match_operand:DI 0 "register_operand" "=&d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16" "* { operands[4] = const0_rtx; dslots_jump_total += 3; dslots_jump_filled += 2;

return "sll\t%3,%2,26\n\ \tbgez\t%3,1f\n\ \tsll\t%M0,%L1,%2\n\ \t%(b\t3f\n\ \tmove\t%L0,%z4%)\n\ \n\ %~1:\n\ \t%(beq\t%3,%z4,2f\n\ \tsll\t%M0,%M1,%2%)\n\ \n\ \tsubu\t%3,%z4,%2\n\ \tsrl\t%3,%L1,%3\n\ \tor\t%M0,%M0,%3\n\ %~2:\n\ \tsll\t%L0,%L1,%2\n\ %~3:"; }" [(set_attr "type" "darith") (set_attr "mode" "SI") (set_attr "length" "48")])

(define_insn "ashldi3_internal2" [(set (match_operand:DI 0 "register_operand" "=d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && (INTVAL (operands[2]) & 32) != 0" "* { operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); operands[4] = const0_rtx; return "sll\t%M0,%L1,%2;move\t%L0,%z4"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (subreg:SI (match_dup 0) 4) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (const_int 0))]

"operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (subreg:SI (match_dup 0) 4) (const_int 0))]

"operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);")

(define_insn "ashldi3_internal3" [(set (match_operand:DI 0 "register_operand" "=d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" "* { int amount = INTVAL (operands[2]);

operands[2] = GEN_INT (amount & 31); operands[4] = const0_rtx; operands[5] = GEN_INT ((-amount) & 31);

return "sll\t%M0,%M1,%2;srl\t%3,%L1,%5;or\t%M0,%M0,%3;sll\t%L0,%L1,%2"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 && (INTVAL (operands[2]) & 63) != 0"

[(set (subreg:SI (match_dup 0) 4) (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))

(set (match_dup 3) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 4)))

(set (subreg:SI (match_dup 0) 4) (ior:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))

(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))] " { int amount = INTVAL (operands[2]); operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31); }")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 && (INTVAL (operands[2]) & 63) != 0"

[(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))

(set (match_dup 3) (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 4)))

(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 0) 0) (match_dup 3)))

(set (subreg:SI (match_dup 0) 4) (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))] " { int amount = INTVAL (operands[2]); operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31); }")

(define_insn "ashldi3_internal4" [(set (match_operand:DI 0 "register_operand" "=d") (ashift:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d") (ashift:DI (match_operand:DI 1 "se_register_operand" "0,d") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_64BIT && TARGET_MIPS16" "* { if (which_alternative == 0) return "dsll\t%0,%2";

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_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 4) (const_int 8))])])

;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.

(define_split [(set (match_operand:DI 0 "register_operand" "") (ashift:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && !TARGET_DEBUG_D_MODE && reload_completed && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (ashift:DI (match_dup 1) (const_int 8))) (set (match_dup 0) (ashift:DI (match_dup 0) (match_dup 2)))] " { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }")

(define_expand "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "" " { /* On the mips16, a shift of more than 8 is a four byte instruction, so, for a shift between 8 and 16, it is just as fast to do two shifts of 8 or less. If there is a lot of shifting going on, we may win in CSE. Otherwise combine will put the shifts back together again. */ if (TARGET_MIPS16 && optimize && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16) { rtx temp = gen_reg_rtx (SImode);

  emit_insn (gen_ashrsi3_internal2 (temp, operands[1], GEN_INT (8)));
  emit_insn (gen_ashrsi3_internal2 (operands[0], temp,
				GEN_INT (INTVAL (operands[2]) - 8)));
  DONE;
}

}")

(define_insn "ashrsi3_internal1" [(set (match_operand:SI 0 "register_operand" "=d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "!TARGET_MIPS16" "* { if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);

return "sra\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "ashrsi3_internal2" [(set (match_operand:SI 0 "register_operand" "=d,d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,d") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_MIPS16" "* { if (which_alternative == 0) return "sra\t%0,%2";

if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);

return "sra\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 4) (const_int 8))])])

;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.

(define_split [(set (match_operand:SI 0 "register_operand" "") (ashiftrt:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (ashiftrt:SI (match_dup 1) (const_int 8))) (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))] " { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }")

(define_expand "ashrdi3" [(parallel [(set (match_operand:DI 0 "register_operand" "") (ashiftrt:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:SI 2 "arith_operand" ""))) (clobber (match_dup 3))])] "TARGET_64BIT || (!TARGET_DEBUG_G_MODE && !TARGET_MIPS16)" " { if (TARGET_64BIT) { /* On the mips16, a shift of more than 8 is a four byte instruction, so, for a shift between 8 and 16, it is just as fast to do two shifts of 8 or less. If there is a lot of shifting going on, we may win in CSE. Otherwise combine will put the shifts back together again. */ if (TARGET_MIPS16 && optimize && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16) { rtx temp = gen_reg_rtx (DImode);

  emit_insn (gen_ashrdi3_internal4 (temp, operands[1], GEN_INT (8)));
  emit_insn (gen_ashrdi3_internal4 (operands[0], temp,
				    GEN_INT (INTVAL (operands[2]) - 8)));
  DONE;
}

  emit_insn (gen_ashrdi3_internal4 (operands[0], operands[1],
				operands[2]));
  DONE;
}

operands[3] = gen_reg_rtx (SImode); }")

(define_insn "ashrdi3_internal" [(set (match_operand:DI 0 "register_operand" "=&d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16" "* { operands[4] = const0_rtx; dslots_jump_total += 3; dslots_jump_filled += 2;

return "sll\t%3,%2,26\n\ \tbgez\t%3,1f\n\ \tsra\t%L0,%M1,%2\n\ \t%(b\t3f\n\ \tsra\t%M0,%M1,31%)\n\ \n\ %~1:\n\ \t%(beq\t%3,%z4,2f\n\ \tsrl\t%L0,%L1,%2%)\n\ \n\ \tsubu\t%3,%z4,%2\n\ \tsll\t%3,%M1,%3\n\ \tor\t%L0,%L0,%3\n\ %~2:\n\ \tsra\t%M0,%M1,%2\n\ %~3:"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "48")])

(define_insn "ashrdi3_internal2" [(set (match_operand:DI 0 "register_operand" "=d") (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_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0" "* { operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); return "sra\t%L0,%M1,%2;sra\t%M0,%M1,31"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_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"

[(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (subreg:SI (match_dup 0) 4) (ashiftrt:SI (subreg:SI (match_dup 1) 4) (const_int 31)))]

"operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_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"

[(set (subreg:SI (match_dup 0) 4) (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_INT (INTVAL (operands[2]) & 0x1f);")

(define_insn "ashrdi3_internal3" [(set (match_operand:DI 0 "register_operand" "=d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" "* { int amount = INTVAL (operands[2]);

operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31);

return "srl\t%L0,%L1,%2;sll\t%3,%M1,%4;or\t%L0,%L0,%3;sra\t%M0,%M1,%2"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 && (INTVAL (operands[2]) & 63) != 0"

[(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))

(set (match_dup 3) (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 4)))

(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 0) 0) (match_dup 3)))

(set (subreg:SI (match_dup 0) 4) (ashiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))] " { int amount = INTVAL (operands[2]); operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31); }")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 && (INTVAL (operands[2]) & 63) != 0"

[(set (subreg:SI (match_dup 0) 4) (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))

(set (match_dup 3) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 4)))

(set (subreg:SI (match_dup 0) 4) (ior:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))

(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))] " { int amount = INTVAL (operands[2]); operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31); }")

(define_insn "ashrdi3_internal4" [(set (match_operand:DI 0 "register_operand" "=d") (ashiftrt:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d") (ashiftrt:DI (match_operand:DI 1 "se_register_operand" "0,0") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_64BIT && TARGET_MIPS16" "* { if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);

return "dsra\t%0,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 4) (const_int 8))])])

;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.

(define_split [(set (match_operand:DI 0 "register_operand" "") (ashiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && !TARGET_DEBUG_D_MODE && reload_completed && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (ashiftrt:DI (match_dup 1) (const_int 8))) (set (match_dup 0) (ashiftrt:DI (match_dup 0) (match_dup 2)))] " { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }")

(define_expand "lshrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "" " { /* On the mips16, a shift of more than 8 is a four byte instruction, so, for a shift between 8 and 16, it is just as fast to do two shifts of 8 or less. If there is a lot of shifting going on, we may win in CSE. Otherwise combine will put the shifts back together again. */ if (TARGET_MIPS16 && optimize && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16) { rtx temp = gen_reg_rtx (SImode);

  emit_insn (gen_lshrsi3_internal2 (temp, operands[1], GEN_INT (8)));
  emit_insn (gen_lshrsi3_internal2 (operands[0], temp,
				GEN_INT (INTVAL (operands[2]) - 8)));
  DONE;
}

}")

(define_insn "lshrsi3_internal1" [(set (match_operand:SI 0 "register_operand" "=d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "!TARGET_MIPS16" "* { if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);

return "srl\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "lshrsi3_internal2" [(set (match_operand:SI 0 "register_operand" "=d,d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,d") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_MIPS16" "* { if (which_alternative == 0) return "srl\t%0,%2";

if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);

return "srl\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 4) (const_int 8))])])

;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.

(define_split [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (lshiftrt:SI (match_dup 1) (const_int 8))) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] " { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }")

;; If we load a byte on the mips16 as a bitfield, the resulting ;; sequence of instructions is too complicated for combine, because it ;; involves four instructions: a load, a shift, a constant load into a ;; register, and an and (the key problem here is that the mips16 does ;; not have and immediate). We recognize a shift of a load in order ;; to make it simple enough for combine to understand.

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,d") (lshiftrt:SI (match_operand:SI 1 "memory_operand" "R,m") (match_operand:SI 2 "immediate_operand" "I,I")))] "TARGET_MIPS16" "lw\t%0,%1;srl\t%0,%2" [(set_attr "type" "load") (set_attr "mode" "SI") (set_attr_alternative "length" [(if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 8) (const_int 12)) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 12) (const_int 16))])])

(define_split [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_operand:SI 1 "memory_operand" "") (match_operand:SI 2 "immediate_operand" "")))] "TARGET_MIPS16 && !TARGET_DEBUG_D_MODE" [(set (match_dup 0) (match_dup 1)) (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] "")

(define_expand "lshrdi3" [(parallel [(set (match_operand:DI 0 "register_operand" "") (lshiftrt:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:SI 2 "arith_operand" ""))) (clobber (match_dup 3))])] "TARGET_64BIT || (!TARGET_DEBUG_G_MODE && !TARGET_MIPS16)" " { if (TARGET_64BIT) { /* On the mips16, a shift of more than 8 is a four byte instruction, so, for a shift between 8 and 16, it is just as fast to do two shifts of 8 or less. If there is a lot of shifting going on, we may win in CSE. Otherwise combine will put the shifts back together again. */ if (TARGET_MIPS16 && optimize && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16) { rtx temp = gen_reg_rtx (DImode);

  emit_insn (gen_lshrdi3_internal4 (temp, operands[1], GEN_INT (8)));
  emit_insn (gen_lshrdi3_internal4 (operands[0], temp,
				    GEN_INT (INTVAL (operands[2]) - 8)));
  DONE;
}

  emit_insn (gen_lshrdi3_internal4 (operands[0], operands[1],
				operands[2]));
  DONE;
}

operands[3] = gen_reg_rtx (SImode); }")

(define_insn "lshrdi3_internal" [(set (match_operand:DI 0 "register_operand" "=&d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16" "* { operands[4] = const0_rtx; dslots_jump_total += 3; dslots_jump_filled += 2;

return "sll\t%3,%2,26\n\ \tbgez\t%3,1f\n\ \tsrl\t%L0,%M1,%2\n\ \t%(b\t3f\n\ \tmove\t%M0,%z4%)\n\ \n\ %~1:\n\ \t%(beq\t%3,%z4,2f\n\ \tsrl\t%L0,%L1,%2%)\n\ \n\ \tsubu\t%3,%z4,%2\n\ \tsll\t%3,%M1,%3\n\ \tor\t%L0,%L0,%3\n\ %~2:\n\ \tsrl\t%M0,%M1,%2\n\ %~3:"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "48")])

(define_insn "lshrdi3_internal2" [(set (match_operand:DI 0 "register_operand" "=d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && (INTVAL (operands[2]) & 32) != 0" "* { operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); operands[4] = const0_rtx; return "srl\t%L0,%M1,%2;move\t%M0,%z4"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (subreg:SI (match_dup 0) 4) (const_int 0))]

"operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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"

[(set (subreg:SI (match_dup 0) 4) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (const_int 0))]

"operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);")

(define_insn "lshrdi3_internal3" [(set (match_operand:DI 0 "register_operand" "=d") (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_64BIT && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" "* { int amount = INTVAL (operands[2]);

operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31);

return "srl\t%L0,%L1,%2;sll\t%3,%M1,%4;or\t%L0,%L0,%3;srl\t%M0,%M1,%2"; }" [(set_attr "type" "darith") (set_attr "mode" "DI") (set_attr "length" "16")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 && (INTVAL (operands[2]) & 63) != 0"

[(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))

(set (match_dup 3) (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 4)))

(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 0) 0) (match_dup 3)))

(set (subreg:SI (match_dup 0) 4) (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))] " { int amount = INTVAL (operands[2]); operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31); }")

(define_split [(set (match_operand:DI 0 "register_operand" "") (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_64BIT && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE && !TARGET_MIPS16 && 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 && (INTVAL (operands[2]) & 63) != 0"

[(set (subreg:SI (match_dup 0) 4) (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))

(set (match_dup 3) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 4)))

(set (subreg:SI (match_dup 0) 4) (ior:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))

(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))] " { int amount = INTVAL (operands[2]); operands[2] = GEN_INT (amount & 31); operands[4] = GEN_INT ((-amount) & 31); }")

(define_insn "lshrdi3_internal4" [(set (match_operand:DI 0 "register_operand" "=d") (lshiftrt:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16" "* { 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")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d,d") (lshiftrt:DI (match_operand:DI 1 "se_register_operand" "0,0") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_64BIT && TARGET_MIPS16" "* { if (GET_CODE (operands[2]) == CONST_INT) operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);

return "dsrl\t%0,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm3_b" "") (const_int 4) (const_int 8))])])

(define_insn "rotrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (rotatert:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dn")))] "ISA_HAS_ROTR_SI" "* { if (TARGET_SR71K && GET_CODE (operands[2]) != CONST_INT) return "rorv\t%0,%1,%2";

if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) >= 32)) abort ();

return "ror\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "rotrdi3" [(set (match_operand:DI 0 "register_operand" "=d") (rotatert:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "arith_operand" "dn")))] "ISA_HAS_ROTR_DI" "* { if (TARGET_SR71K) { if (GET_CODE (operands[2]) != CONST_INT) return "drorv\t%0,%1,%2";

  if (INTVAL (operands[2]) >= 32 && INTVAL (operands[2]) <= 63)
    return \"dror32\\t%0,%1,%2\";
}

if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) >= 64)) abort ();

return "dror\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI")])

;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts.

(define_split [(set (match_operand:DI 0 "register_operand" "") (lshiftrt:DI (match_operand:DI 1 "register_operand" "") (match_operand:SI 2 "const_int_operand" "")))] "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16" [(set (match_dup 0) (lshiftrt:DI (match_dup 1) (const_int 8))) (set (match_dup 0) (lshiftrt:DI (match_dup 0) (match_dup 2)))] " { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }")

;; ;; .................... ;; ;; COMPARISONS ;; ;; ....................

;; Flow here is rather complex: ;; ;; 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. ;; ;; 2) The appropriate branch define_expand is called, which then ;; creates the appropriate RTL for the comparison and branch. ;; Different CC modes are used, based on what type of branch is ;; done, so that we can constrain things appropriately. There ;; are assumptions in the rest of GCC that break if we fold the ;; operands into the branchs for integer operations, and use cc0 ;; for floating point, so we use the fp status register instead. ;; If needed, an appropriate temporary is created to hold the ;; of the integer compare.

(define_expand "cmpsi" [(set (cc0) (compare:CC (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "arith_operand" "")))] "" " { if (operands[0]) /* avoid unused code message */ { branch_cmp[0] = operands[0]; branch_cmp[1] = operands[1]; branch_type = CMP_SI; DONE; } }")

(define_expand "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" ""))] "" " { if (operands[0]) /* avoid unused code message */ { branch_cmp[0] = operands[0]; branch_cmp[1] = const0_rtx; branch_type = CMP_SI; DONE; } }")

(define_expand "cmpdi" [(set (cc0) (compare:CC (match_operand:DI 0 "se_register_operand" "") (match_operand:DI 1 "se_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 "se_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 (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "register_operand" "")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" " { if (operands[0]) /* avoid unused code message */ { branch_cmp[0] = operands[0]; branch_cmp[1] = operands[1]; branch_type = CMP_DF; DONE; } }")

(define_expand "cmpsf" [(set (cc0) (compare:CC (match_operand:SF 0 "register_operand" "") (match_operand:SF 1 "register_operand" "")))] "TARGET_HARD_FLOAT" " { if (operands[0]) /* avoid unused code message */ { branch_cmp[0] = operands[0]; branch_cmp[1] = operands[1]; branch_type = CMP_SF; DONE; } }")

;; ;; .................... ;; ;; CONDITIONAL BRANCHES ;; ;; ....................

;; Conditional branches on floating-point equality tests.

(define_insn "branch_fp" [(set (pc) (if_then_else (match_operator:CC 0 "cmp_op" [(match_operand:CC 2 "register_operand" "z") (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] "TARGET_HARD_FLOAT" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/0, /float_p=/1, /inverted_p=/0, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_fp_inverted" [(set (pc) (if_then_else (match_operator:CC 0 "cmp_op" [(match_operand:CC 2 "register_operand" "z") (const_int 0)]) (pc) (label_ref (match_operand 1 "" ""))))] "TARGET_HARD_FLOAT" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/0, /float_p=/1, /inverted_p=/1, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

;; Conditional branches on comparisons with zero.

(define_insn "branch_zero" [(set (pc) (if_then_else (match_operator:SI 0 "cmp_op" [(match_operand:SI 2 "register_operand" "d") (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/0, /float_p=/0, /inverted_p=/0, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_zero_inverted" [(set (pc) (if_then_else (match_operator:SI 0 "cmp_op" [(match_operand:SI 2 "register_operand" "d") (const_int 0)]) (pc) (label_ref (match_operand 1 "" ""))))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/0, /float_p=/0, /inverted_p=/1, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_zero_di" [(set (pc) (if_then_else (match_operator:DI 0 "cmp_op" [(match_operand:DI 2 "se_register_operand" "d") (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/0, /float_p=/0, /inverted_p=/0, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_zero_di_inverted" [(set (pc) (if_then_else (match_operator:DI 0 "cmp_op" [(match_operand:DI 2 "se_register_operand" "d") (const_int 0)]) (pc) (label_ref (match_operand 1 "" ""))))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/0, /float_p=/0, /inverted_p=/1, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

;; Conditional branch on equality comparision.

(define_insn "branch_equality" [(set (pc) (if_then_else (match_operator:SI 0 "equality_op" [(match_operand:SI 2 "register_operand" "d") (match_operand:SI 3 "register_operand" "d")]) (label_ref (match_operand 1 "" "")) (pc)))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/1, /float_p=/0, /inverted_p=/0, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_equality_di" [(set (pc) (if_then_else (match_operator:DI 0 "equality_op" [(match_operand:DI 2 "se_register_operand" "d") (match_operand:DI 3 "se_register_operand" "d")]) (label_ref (match_operand 1 "" "")) (pc)))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/1, /float_p=/0, /inverted_p=/0, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_equality_inverted" [(set (pc) (if_then_else (match_operator:SI 0 "equality_op" [(match_operand:SI 2 "register_operand" "d") (match_operand:SI 3 "register_operand" "d")]) (pc) (label_ref (match_operand 1 "" ""))))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/1, /float_p=/0, /inverted_p=/1, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

(define_insn "branch_equality_di_inverted" [(set (pc) (if_then_else (match_operator:DI 0 "equality_op" [(match_operand:DI 2 "se_register_operand" "d") (match_operand:DI 3 "se_register_operand" "d")]) (pc) (label_ref (match_operand 1 "" ""))))] "!TARGET_MIPS16" "* { return mips_output_conditional_branch (insn, operands, /two_operands_p=/1, /float_p=/0, /inverted_p=/1, get_attr_length (insn)); }" [(set_attr "type" "branch") (set_attr "mode" "none")])

;; MIPS16 branches

(define_insn "" [(set (pc) (if_then_else (match_operator:SI 0 "equality_op" [(match_operand:SI 1 "register_operand" "d,t") (const_int 0)]) (match_operand 2 "pc_or_label_operand" "") (match_operand 3 "pc_or_label_operand" "")))] "TARGET_MIPS16" "* { if (operands[2] != pc_rtx) { if (which_alternative == 0) return "%*b%C0z\t%1,%2"; else return "%*bt%C0z\t%2"; } else { if (which_alternative == 0) return "%*b%N0z\t%1,%3"; else return "%*bt%N0z\t%3"; } }" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

(define_insn "" [(set (pc) (if_then_else (match_operator:DI 0 "equality_op" [(match_operand:DI 1 "se_register_operand" "d,t") (const_int 0)]) (match_operand 2 "pc_or_label_operand" "") (match_operand 3 "pc_or_label_operand" "")))] "TARGET_MIPS16" "* { if (operands[2] != pc_rtx) { if (which_alternative == 0) return "%*b%C0z\t%1,%2"; else return "%*bt%C0z\t%2"; } else { if (which_alternative == 0) return "%*b%N0z\t%1,%3"; else return "%*bt%N0z\t%3"; } }" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

(define_expand "bunordered" [(set (pc) (if_then_else (unordered:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, UNORDERED); DONE; } }")

(define_expand "bordered" [(set (pc) (if_then_else (ordered:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, ORDERED); DONE; } }")

(define_expand "bunlt" [(set (pc) (if_then_else (unlt:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, UNLT); DONE; } }")

(define_expand "bunge" [(set (pc) (if_then_else (unge:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { gen_conditional_branch (operands, UNGE); DONE; }")

(define_expand "buneq" [(set (pc) (if_then_else (uneq:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, UNEQ); DONE; } }")

(define_expand "bltgt" [(set (pc) (if_then_else (ltgt:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { gen_conditional_branch (operands, LTGT); DONE; }")

(define_expand "bunle" [(set (pc) (if_then_else (unle:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, UNLE); DONE; } }")

(define_expand "bungt" [(set (pc) (if_then_else (ungt:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { gen_conditional_branch (operands, UNGT); DONE; }")

(define_expand "beq" [(set (pc) (if_then_else (eq:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, EQ); DONE; } }")

(define_expand "bne" [(set (pc) (if_then_else (ne:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, NE); DONE; } }")

(define_expand "bgt" [(set (pc) (if_then_else (gt:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, GT); DONE; } }")

(define_expand "bge" [(set (pc) (if_then_else (ge:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, GE); DONE; } }")

(define_expand "blt" [(set (pc) (if_then_else (lt:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, LT); DONE; } }")

(define_expand "ble" [(set (pc) (if_then_else (le:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, LE); DONE; } }")

(define_expand "bgtu" [(set (pc) (if_then_else (gtu:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, GTU); DONE; } }")

(define_expand "bgeu" [(set (pc) (if_then_else (geu:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, GEU); DONE; } }")

(define_expand "bltu" [(set (pc) (if_then_else (ltu:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, LTU); DONE; } }")

(define_expand "bleu" [(set (pc) (if_then_else (leu:CC (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" " { if (operands[0]) /* avoid unused code warning */ { gen_conditional_branch (operands, LEU); DONE; } }")

;; ;; .................... ;; ;; SETTING A REGISTER FROM A COMPARISON ;; ;; ....................

(define_expand "seq" [(set (match_operand:SI 0 "register_operand" "=d") (eq:SI (match_dup 1) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (EQ, operands[0], operands[1], operands[2], (int *)0); DONE; }

if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) operands[2] = force_reg (SImode, operands[2]);

/* fall through and generate default code */ }")

(define_insn "seq_si_zero" [(set (match_operand:SI 0 "register_operand" "=d") (eq:SI (match_operand:SI 1 "register_operand" "d") (const_int 0)))] "!TARGET_MIPS16" "sltu\t%0,%1,1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t") (eq:SI (match_operand:SI 1 "register_operand" "d") (const_int 0)))] "TARGET_MIPS16" "sltu\t%1,1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "seq_di_zero" [(set (match_operand:DI 0 "register_operand" "=d") (eq:DI (match_operand:DI 1 "se_register_operand" "d") (const_int 0)))] "TARGET_64BIT && !TARGET_MIPS16" "sltu\t%0,%1,1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=t") (eq:DI (match_operand:DI 1 "se_register_operand" "d") (const_int 0)))] "TARGET_64BIT && TARGET_MIPS16" "sltu\t%1,1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "seq_si" [(set (match_operand:SI 0 "register_operand" "=d,d") (eq:SI (match_operand:SI 1 "register_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "@ 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" "SI") (set_attr "length" "8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (eq:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "uns_arith_operand" "")))] "TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)" [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (ltu:SI (match_dup 0) (const_int 1)))] "")

(define_insn "seq_di" [(set (match_operand:DI 0 "register_operand" "=d,d") (eq:DI (match_operand:DI 1 "se_register_operand" "%d,d") (match_operand:DI 2 "se_uns_arith_operand" "d,K")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "@ 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" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (eq:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_uns_arith_operand" "")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16 && (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)))] "")

;; On the mips16 the default code is better than using sltu.

(define_expand "sne" [(set (match_operand:SI 0 "register_operand" "=d") (ne:SI (match_dup 1) (match_dup 2)))] "!TARGET_MIPS16" " { 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_64BIT || !TARGET_DEBUG_C_MODE) { gen_int_relational (NE, operands[0], operands[1], operands[2], (int *)0); DONE; }

if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) operands[2] = force_reg (SImode, operands[2]);

/* fall through and generate default code */ }")

(define_insn "sne_si_zero" [(set (match_operand:SI 0 "register_operand" "=d") (ne:SI (match_operand:SI 1 "register_operand" "d") (const_int 0)))] "!TARGET_MIPS16" "sltu\t%0,%.,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "sne_di_zero" [(set (match_operand:DI 0 "register_operand" "=d") (ne:DI (match_operand:DI 1 "se_register_operand" "d") (const_int 0)))] "TARGET_64BIT && !TARGET_MIPS16" "sltu\t%0,%.,%1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "sne_si" [(set (match_operand:SI 0 "register_operand" "=d,d") (ne:SI (match_operand:SI 1 "register_operand" "%d,d") (match_operand:SI 2 "uns_arith_operand" "d,K")))] "TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "@ 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" "SI") (set_attr "length" "8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (ne:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "uns_arith_operand" "")))] "TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16 && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)" [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (gtu:SI (match_dup 0) (const_int 0)))] "")

(define_insn "sne_di" [(set (match_operand:DI 0 "register_operand" "=d,d") (ne:DI (match_operand:DI 1 "se_register_operand" "%d,d") (match_operand:DI 2 "se_uns_arith_operand" "d,K")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "@ 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" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (ne:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_uns_arith_operand" "")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16 && (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) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (GT, operands[0], operands[1], operands[2], (int *)0); DONE; }

if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0) operands[2] = force_reg (SImode, operands[2]);

/* fall through and generate default code */ }")

(define_insn "sgt_si" [(set (match_operand:SI 0 "register_operand" "=d") (gt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "reg_or_0_operand" "dJ")))] "!TARGET_MIPS16" "slt\t%0,%z2,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t") (gt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")))] "TARGET_MIPS16" "slt\t%2,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "sgt_di" [(set (match_operand:DI 0 "register_operand" "=d") (gt:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_reg_or_0_operand" "dJ")))] "TARGET_64BIT && !TARGET_MIPS16" "slt\t%0,%z2,%1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=d") (gt:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT && TARGET_MIPS16" "slt\t%2,%1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_expand "sge" [(set (match_operand:SI 0 "register_operand" "=d") (ge:SI (match_dup 1) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (GE, operands[0], operands[1], operands[2], (int *)0); DONE; }

/* fall through and generate default code */ }")

(define_insn "sge_si" [(set (match_operand:SI 0 "register_operand" "=d") (ge:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "slt\t%0,%1,%2;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (ge:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "arith_operand" "")))] "TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(set (match_dup 0) (lt:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))] "")

(define_insn "sge_di" [(set (match_operand:DI 0 "register_operand" "=d") (ge:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_arith_operand" "dI")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "slt\t%0,%1,%2;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (ge:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_arith_operand" "")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(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) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (LT, operands[0], operands[1], operands[2], (int *)0); DONE; }

/* fall through and generate default code */ }")

(define_insn "slt_si" [(set (match_operand:SI 0 "register_operand" "=d") (lt:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "!TARGET_MIPS16" "slt\t%0,%1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t,t") (lt:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_MIPS16" "slt\t%1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm8_1" "") (const_int 4) (const_int 8))])])

(define_insn "slt_di" [(set (match_operand:DI 0 "register_operand" "=d") (lt:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16" "slt\t%0,%1,%2" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=t,t") (lt:DI (match_operand:DI 1 "se_register_operand" "d,d") (match_operand:DI 2 "se_arith_operand" "d,I")))] "TARGET_64BIT && TARGET_MIPS16" "slt\t%1,%2" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm8_1" "") (const_int 4) (const_int 8))])])

(define_expand "sle" [(set (match_operand:SI 0 "register_operand" "=d") (le:SI (match_dup 1) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (LE, operands[0], operands[1], operands[2], (int *)0); DONE; }

if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32767) operands[2] = force_reg (SImode, operands[2]);

/* fall through and generate default code */ }")

(define_insn "sle_si_const" [(set (match_operand:SI 0 "register_operand" "=d") (le:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "I")))] "!TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2])+1); return "slt\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t") (le:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "I")))] "TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2])+1); return "slt\t%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (match_operand:VOID 2 "m16_uimm8_m1_1" "") (const_int 4) (const_int 8)))])

(define_insn "sle_di_const" [(set (match_operand:DI 0 "register_operand" "=d") (le:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "small_int" "I")))] "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2])+1); return "slt\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=t") (le:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "small_int" "I")))] "TARGET_64BIT && TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2])+1); return "slt\t%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (match_operand:VOID 2 "m16_uimm8_m1_1" "") (const_int 4) (const_int 8)))])

(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 && !TARGET_MIPS16" "slt\t%0,%z2,%1;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (le:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand" "")))] "TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(set (match_dup 0) (lt:SI (match_dup 2) (match_dup 1))) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))] "")

(define_insn "sle_di_reg" [(set (match_operand:DI 0 "register_operand" "=d") (le:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "slt\t%0,%z2,%1;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (le:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_register_operand" "")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(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) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (GTU, operands[0], operands[1], operands[2], (int *)0); DONE; }

if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0) operands[2] = force_reg (SImode, operands[2]);

/* fall through and generate default code */ }")

(define_insn "sgtu_si" [(set (match_operand:SI 0 "register_operand" "=d") (gtu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "reg_or_0_operand" "dJ")))] "!TARGET_MIPS16" "sltu\t%0,%z2,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t") (gtu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d")))] "TARGET_MIPS16" "sltu\t%2,%1" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "sgtu_di" [(set (match_operand:DI 0 "register_operand" "=d") (gtu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_reg_or_0_operand" "dJ")))] "TARGET_64BIT && !TARGET_MIPS16" "sltu\t%0,%z2,%1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=t") (gtu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT && TARGET_MIPS16" "sltu\t%2,%1" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_expand "sgeu" [(set (match_operand:SI 0 "register_operand" "=d") (geu:SI (match_dup 1) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (GEU, operands[0], operands[1], operands[2], (int *)0); DONE; }

/* fall through and generate default code */ }")

(define_insn "sgeu_si" [(set (match_operand:SI 0 "register_operand" "=d") (geu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "sltu\t%0,%1,%2;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (geu:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "arith_operand" "")))] "TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(set (match_dup 0) (ltu:SI (match_dup 1) (match_dup 2))) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))] "")

(define_insn "sgeu_di" [(set (match_operand:DI 0 "register_operand" "=d") (geu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_arith_operand" "dI")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "sltu\t%0,%1,%2;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (geu:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_arith_operand" "")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(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) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (LTU, operands[0], operands[1], operands[2], (int *)0); DONE; }

/* fall through and generate default code */ }")

(define_insn "sltu_si" [(set (match_operand:SI 0 "register_operand" "=d") (ltu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "arith_operand" "dI")))] "!TARGET_MIPS16" "sltu\t%0,%1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t,t") (ltu:SI (match_operand:SI 1 "register_operand" "d,d") (match_operand:SI 2 "arith_operand" "d,I")))] "TARGET_MIPS16" "sltu\t%1,%2" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm8_1" "") (const_int 4) (const_int 8))])])

(define_insn "sltu_di" [(set (match_operand:DI 0 "register_operand" "=d") (ltu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_arith_operand" "dI")))] "TARGET_64BIT && !TARGET_MIPS16" "sltu\t%0,%1,%2" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=t,t") (ltu:DI (match_operand:DI 1 "se_register_operand" "d,d") (match_operand:DI 2 "se_arith_operand" "d,I")))] "TARGET_64BIT && TARGET_MIPS16" "sltu\t%1,%2" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr_alternative "length" [(const_int 4) (if_then_else (match_operand:VOID 2 "m16_uimm8_1" "") (const_int 4) (const_int 8))])])

(define_expand "sleu" [(set (match_operand:SI 0 "register_operand" "=d") (leu:SI (match_dup 1) (match_dup 2)))] "" " { 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_64BIT || !TARGET_DEBUG_C_MODE || TARGET_MIPS16) { gen_int_relational (LEU, operands[0], operands[1], operands[2], (int *)0); DONE; }

if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32767) operands[2] = force_reg (SImode, operands[2]);

/* fall through and generate default code */ }")

(define_insn "sleu_si_const" [(set (match_operand:SI 0 "register_operand" "=d") (leu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "I")))] "!TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2]) + 1); return "sltu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=t") (leu:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "small_int" "I")))] "TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2])+1); return "sltu\t%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "SI") (set (attr "length") (if_then_else (match_operand:VOID 2 "m16_uimm8_m1_1" "") (const_int 4) (const_int 8)))])

(define_insn "sleu_di_const" [(set (match_operand:DI 0 "register_operand" "=d") (leu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "small_int" "I")))] "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2]) + 1); return "sltu\t%0,%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI")])

(define_insn "" [(set (match_operand:DI 0 "register_operand" "=t") (leu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "small_int" "I")))] "TARGET_64BIT && TARGET_MIPS16 && INTVAL (operands[2]) < 32767" "* { operands[2] = GEN_INT (INTVAL (operands[2])+1); return "sltu\t%1,%2"; }" [(set_attr "type" "arith") (set_attr "mode" "DI") (set (attr "length") (if_then_else (match_operand:VOID 2 "m16_uimm8_m1_1" "") (const_int 4) (const_int 8)))])

(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 && !TARGET_MIPS16" "sltu\t%0,%z2,%1;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "8")])

(define_split [(set (match_operand:SI 0 "register_operand" "") (leu:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand" "")))] "TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(set (match_dup 0) (ltu:SI (match_dup 2) (match_dup 1))) (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))] "")

(define_insn "sleu_di_reg" [(set (match_operand:DI 0 "register_operand" "=d") (leu:DI (match_operand:DI 1 "se_register_operand" "d") (match_operand:DI 2 "se_register_operand" "d")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_MIPS16" "sltu\t%0,%z2,%1;xori\t%0,%0,0x0001" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr "length" "8")])

(define_split [(set (match_operand:DI 0 "register_operand" "") (leu:DI (match_operand:DI 1 "se_register_operand" "") (match_operand:DI 2 "se_register_operand" "")))] "TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE && !TARGET_MIPS16" [(set (match_dup 0) (ltu:DI (match_dup 2) (match_dup 1))) (set (match_dup 0) (xor:DI (match_dup 0) (const_int 1)))] "")

;; ;; .................... ;; ;; FLOATING POINT COMPARISONS ;; ;; ....................

(define_insn "sunordered_df" [(set (match_operand:CC 0 "register_operand" "=z") (unordered:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.un.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sunlt_df" [(set (match_operand:CC 0 "register_operand" "=z") (unlt:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.ult.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "suneq_df" [(set (match_operand:CC 0 "register_operand" "=z") (uneq:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.ueq.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sunle_df" [(set (match_operand:CC 0 "register_operand" "=z") (unle:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.ule.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "seq_df" [(set (match_operand:CC 0 "register_operand" "=z") (eq:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.eq.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "slt_df" [(set (match_operand:CC 0 "register_operand" "=z") (lt:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.lt.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sle_df" [(set (match_operand:CC 0 "register_operand" "=z") (le:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.le.d\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sgt_df" [(set (match_operand:CC 0 "register_operand" "=z") (gt:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.lt.d\t%Z0%2,%1", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sge_df" [(set (match_operand:CC 0 "register_operand" "=z") (ge:CC (match_operand:DF 1 "register_operand" "f") (match_operand:DF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "* { return mips_fill_delay_slot ("c.le.d\t%Z0%2,%1", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sunordered_sf" [(set (match_operand:CC 0 "register_operand" "=z") (unordered:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.un.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sunlt_sf" [(set (match_operand:CC 0 "register_operand" "=z") (unlt:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.ult.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "suneq_sf" [(set (match_operand:CC 0 "register_operand" "=z") (uneq:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.ueq.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sunle_sf" [(set (match_operand:CC 0 "register_operand" "=z") (unle:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.ule.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "seq_sf" [(set (match_operand:CC 0 "register_operand" "=z") (eq:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.eq.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "slt_sf" [(set (match_operand:CC 0 "register_operand" "=z") (lt:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.lt.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sle_sf" [(set (match_operand:CC 0 "register_operand" "=z") (le:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.le.s\t%Z0%1,%2", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sgt_sf" [(set (match_operand:CC 0 "register_operand" "=z") (gt:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.lt.s\t%Z0%2,%1", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

(define_insn "sge_sf" [(set (match_operand:CC 0 "register_operand" "=z") (ge:CC (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] "TARGET_HARD_FLOAT" "* { return mips_fill_delay_slot ("c.le.s\t%Z0%2,%1", DELAY_FCMP, operands, insn); }" [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")])

;; ;; .................... ;; ;; UNCONDITIONAL BRANCHES ;; ;; ....................

;; Unconditional branches.

(define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "!TARGET_MIPS16" "* { if (flag_pic && ! TARGET_EMBEDDED_PIC) { if (get_attr_length (insn) <= 8) return "%*b\t%l0"; else if (Pmode == DImode) return "%[dla\t%@,%l0;%*jr\t%@%]"; else return "%[la\t%@,%l0;%*jr\t%@%]"; } else return "%*j\t%l0"; }" [(set_attr "type" "jump") (set_attr "mode" "none") (set (attr "length") ;; we can't use `j' when emitting non-embedded PIC, so we emit ;; branch, if it's in range, or load the address of the branch ;; target into $at in a PIC-compatible way and then jump to it. (if_then_else (ior (eq (symbol_ref "flag_pic && ! TARGET_EMBEDDED_PIC") (const_int 0)) (lt (abs (minus (match_dup 0) (plus (pc) (const_int 4)))) (const_int 131072))) (const_int 4) (const_int 16)))])

;; We need a different insn for the mips16, because a mips16 branch ;; does not have a delay slot.

(define_insn "" [(set (pc) (label_ref (match_operand 0 "" "")))] "TARGET_MIPS16" "b\t%l0" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

(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 (!(Pmode == DImode))
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"))] "!(Pmode == DImode)" "%*j\t%0" [(set_attr "type" "jump") (set_attr "mode" "none")])

(define_insn "indirect_jump_internal2" [(set (pc) (match_operand:DI 0 "se_register_operand" "d"))] "Pmode == DImode" "%*j\t%0" [(set_attr "type" "jump") (set_attr "mode" "none")])

(define_expand "tablejump" [(set (pc) (match_operand 0 "register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] "" " { if (operands[0]) /* eliminate unused code warnings */ { if (TARGET_MIPS16) { if (GET_MODE (operands[0]) != HImode) abort (); if (!(Pmode == DImode)) emit_insn (gen_tablejump_mips161 (operands[0], operands[1])); else emit_insn (gen_tablejump_mips162 (operands[0], operands[1])); DONE; }

  if (GET_MODE (operands[0]) != Pmode)
abort ();

  if (! flag_pic)
{
  if (!(Pmode == DImode))
    emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
  else
    emit_jump_insn (gen_tablejump_internal2 (operands[0], operands[1]));
}
  else
{
  if (!(Pmode == DImode))
    emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
  else
    emit_jump_insn (gen_tablejump_internal4 (operands[0], operands[1]));
}

  DONE;
}

}")

(define_insn "tablejump_internal1" [(set (pc) (match_operand:SI 0 "register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] "!(Pmode == DImode)" "%*j\t%0" [(set_attr "type" "jump") (set_attr "mode" "none")])

(define_insn "tablejump_internal2" [(set (pc) (match_operand:DI 0 "se_register_operand" "d")) (use (label_ref (match_operand 1 "" "")))] "Pmode == DImode" "%*j\t%0" [(set_attr "type" "jump") (set_attr "mode" "none")])

(define_expand "tablejump_internal3" [(parallel [(set (pc) (plus:SI (match_operand:SI 0 "register_operand" "d") (label_ref:SI (match_operand 1 "" "")))) (use (label_ref:SI (match_dup 1)))])] "" "")

(define_expand "tablejump_mips161" [(set (pc) (plus:SI (sign_extend:SI (match_operand:HI 0 "register_operand" "d")) (label_ref:SI (match_operand 1 "" ""))))] "TARGET_MIPS16 && !(Pmode == DImode)" " { if (operands[0]) /* eliminate unused code warnings. */ { rtx t1, t2, t3;

  t1 = gen_reg_rtx (SImode);
  t2 = gen_reg_rtx (SImode);
  t3 = gen_reg_rtx (SImode);
  emit_insn (gen_extendhisi2 (t1, operands[0]));
  emit_move_insn (t2, gen_rtx_LABEL_REF (SImode, operands[1]));
  emit_insn (gen_addsi3 (t3, t1, t2));
  emit_jump_insn (gen_tablejump_internal1 (t3, operands[1]));
  DONE;
}

}")

(define_expand "tablejump_mips162" [(set (pc) (plus:DI (sign_extend:DI (match_operand:HI 0 "register_operand" "d")) (label_ref:DI (match_operand 1 "" ""))))] "TARGET_MIPS16 && Pmode == DImode" " { if (operands[0]) /* eliminate unused code warnings. */ { rtx t1, t2, t3;

  t1 = gen_reg_rtx (DImode);
  t2 = gen_reg_rtx (DImode);
  t3 = gen_reg_rtx (DImode);
  emit_insn (gen_extendhidi2 (t1, operands[0]));
  emit_move_insn (t2, gen_rtx_LABEL_REF (DImode, operands[1]));
  emit_insn (gen_adddi3 (t3, t1, t2));
  emit_jump_insn (gen_tablejump_internal2 (t3, operands[1]));
  DONE;
}

}")

;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise ;;; it is not valid. ??? With the USE, the condition tests may not be required ;;; any longer.

;;; ??? The length depends on the ABI. It is two for o32, and one for n32. ;;; We just use the conservative number here.

(define_insn "" [(set (pc) (plus:SI (match_operand:SI 0 "register_operand" "d") (label_ref:SI (match_operand 1 "" "")))) (use (label_ref:SI (match_dup 1)))] "!(Pmode == DImode) && next_active_insn (insn) != 0 && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC && PREV_INSN (next_active_insn (insn)) == operands[1]" "* { /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */ if (mips_abi == ABI_32 || mips_abi == ABI_O64 || (mips_abi == ABI_N32 && TARGET_GAS)) output_asm_insn (".cpadd\t%0", operands); return "%*j\t%0"; }" [(set_attr "type" "jump") (set_attr "mode" "none") (set_attr "length" "8")])

(define_expand "tablejump_internal4" [(parallel [(set (pc) (plus:DI (match_operand:DI 0 "se_register_operand" "d") (label_ref:DI (match_operand 1 "" "")))) (use (label_ref:DI (match_dup 1)))])] "" "")

;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise ;;; it is not valid. ??? With the USE, the condition tests may not be required ;;; any longer.

(define_insn "" [(set (pc) (plus:DI (match_operand:DI 0 "se_register_operand" "d") (label_ref:DI (match_operand 1 "" "")))) (use (label_ref:DI (match_dup 1)))] "Pmode == DImode && next_active_insn (insn) != 0 && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC && PREV_INSN (next_active_insn (insn)) == operands[1]" "* { /* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */ if (TARGET_GAS && mips_abi == ABI_64) output_asm_insn (".cpadd\t%0", operands); return "%*j\t%0"; }" [(set_attr "type" "jump") (set_attr "mode" "none") (set_attr "length" "8")])

;; 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" " { 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.  */
  if (Pmode != DImode)
    emit_jump_insn (gen_casesi_internal (reg, operands[3],
				     gen_reg_rtx (SImode)));
  else
    emit_jump_insn (gen_casesi_internal_di (reg, operands[3],
					gen_reg_rtx (DImode)));

  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" "%(bal\t%S1;sll\t%2,%0,2\n%~%S1:;addu\t%2,%2,$31%);\ lw\t%2,%1-%S1(%2);addu\t%2,%2,$31\n\t%*j\t%2" [(set_attr "type" "jump") (set_attr "mode" "none") (set_attr "length" "24")])

;; This code assumes that the table index will never be >= 29 bits wide, ;; which allows the 'sign extend' from SI to DI be a no-op. (define_insn "casesi_internal_di" [(set (pc) (mem:DI (plus:DI (sign_extend:DI (mult:SI (match_operand:SI 0 "register_operand" "d") (const_int 8))) (label_ref (match_operand 1 "" ""))))) (clobber (match_operand:DI 2 "register_operand" "=d")) (clobber (reg:DI 31))] "TARGET_EMBEDDED_PIC" "%(bal\t%S1;sll\t%2,%0,3\n%~%S1:;daddu\t%2,%2,$31%);\ ld\t%2,%1-%S1(%2);daddu\t%2,%2,$31\n\t%*j\t%2" [(set_attr "type" "jump") (set_attr "mode" "none") (set_attr "length" "24")])

;; For o32/n32/n64, we save the gp in the jmp_buf as well. While it is ;; possible to either pull it off the stack (in the o32 case) or recalculate ;; it given t9 and our target label, it takes 3 or 4 insns to do so, and ;; this is easy.

(define_expand "builtin_setjmp_setup" [(unspec [(match_operand 0 "register_operand" "r")] UNSPEC_SETJMP)] "TARGET_ABICALLS" " { if (Pmode == DImode) emit_insn (gen_builtin_setjmp_setup_64 (operands[0])); else emit_insn (gen_builtin_setjmp_setup_32 (operands[0])); DONE; }")

(define_expand "builtin_setjmp_setup_32" [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r") (const_int 12))) (reg:SI 28))] "TARGET_ABICALLS && ! (Pmode == DImode)" "")

(define_expand "builtin_setjmp_setup_64" [(set (mem:DI (plus:DI (match_operand:DI 0 "register_operand" "r") (const_int 24))) (reg:DI 28))] "TARGET_ABICALLS && Pmode == DImode" "")

;; For o32/n32/n64, we need to arrange for longjmp to put the ;; target address in t9 so that we can use it for loading $gp.

(define_expand "builtin_longjmp" [(unspec_volatile [(match_operand 0 "register_operand" "r")] UNSPEC_LONGJMP)] "TARGET_ABICALLS" " { /* The elements of the buffer are, in order: / int W = (Pmode == DImode ? 8 : 4); rtx fp = gen_rtx_MEM (Pmode, operands[0]); rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1W)); rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2W)); rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3W)); rtx pv = gen_rtx_REG (Pmode, 25); rtx gp = gen_rtx_REG (Pmode, 28);

/* This bit is the same as expand_builtin_longjmp. */ emit_move_insn (hard_frame_pointer_rtx, fp); emit_move_insn (pv, lab); emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); emit_move_insn (gp, gpv); emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); emit_insn (gen_rtx_USE (VOIDmode, gp)); emit_indirect_jump (pv); DONE; }") ;; ;; .................... ;; ;; Function prologue/epilogue ;; ;; .................... ;;

(define_expand "prologue" [(const_int 1)] "" " { if (mips_isa >= 0) /* avoid unused code warnings */ { mips_expand_prologue (); DONE; } }")

;; Block any insns from being moved before this point, since the ;; profiling call to mcount can use various registers that aren't ;; saved or used to pass arguments.

(define_insn "blockage" [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] "" "" [(set_attr "type" "unknown") (set_attr "mode" "none") (set_attr "length" "0")])

(define_expand "epilogue" [(const_int 2)] "" " { if (mips_isa >= 0) /* avoid unused code warnings */ { mips_expand_epilogue (); DONE; } }")

;; Trivial return. Make it look like a normal return insn as that ;; allows jump optimizations to work better . (define_insn "return" [(return)] "mips_can_use_return_insn ()" "%*j\t$31" [(set_attr "type" "jump") (set_attr "mode" "none")])

;; Normal return.

(define_insn "return_internal" [(use (match_operand 0 "pmode_register_operand" "")) (return)] "" "* { return "%*j\t%0"; }" [(set_attr "type" "jump") (set_attr "mode" "none")])

;; 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 "" "")] UNSPEC_GET_FNADDR)) (clobber (reg:SI 31))] "TARGET_EMBEDDED_PIC && GET_CODE (operands[1]) == SYMBOL_REF" "%($LF%= = . + 8;bal\t$LF%=;nop;la\t%0,%1-$LF%=%);addu\t%0,%0,$31" [(set_attr "type" "call") (set_attr "mode" "none") (set_attr "length" "20")])

;; This is used in compiling the unwind routines. (define_expand "eh_return" [(use (match_operand 0 "general_operand" "")) (use (match_operand 1 "general_operand" ""))] "" " { enum machine_mode gpr_mode = TARGET_64BIT ? DImode : SImode;

if (GET_MODE (operands[1]) != gpr_mode) operands[1] = convert_to_mode (gpr_mode, operands[1], 0); if (TARGET_64BIT) emit_insn (gen_eh_set_lr_di (operands[1])); else emit_insn (gen_eh_set_lr_si (operands[1]));

emit_move_insn (EH_RETURN_STACKADJ_RTX, operands[0]); DONE; }")

;; Clobber the return address on the stack. We can't expand this ;; until we know where it will be put in the stack frame.

(define_insn "eh_set_lr_si" [(unspec [(match_operand:SI 0 "register_operand" "d")] UNSPEC_EH_RETURN) (clobber (match_scratch:SI 1 "=&d"))] "! TARGET_64BIT" "#")

(define_insn "eh_set_lr_di" [(unspec [(match_operand:DI 0 "register_operand" "d")] UNSPEC_EH_RETURN) (clobber (match_scratch:DI 1 "=&d"))] "TARGET_64BIT" "#")

(define_split [(unspec [(match_operand 0 "register_operand" "")] UNSPEC_EH_RETURN) (clobber (match_scratch 1 ""))] "reload_completed && !TARGET_DEBUG_D_MODE" [(const_int 0)] " { mips_set_return_address (operands[0], operands[1]); DONE; }")

(define_insn "exception_receiver" [(unspec_volatile [(const_int 0)] UNSPEC_EH_RECEIVER)] "TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)" "* return mips_restore_gp (operands, insn);" [(set_attr "type" "load") (set_attr "length" "8")]) ;; ;; .................... ;; ;; FUNCTION CALLS ;; ;; ....................

;; calls.c now passes a third argument, make saber happy

(define_expand "call" [(parallel [(call (match_operand 0 "memory_operand" "m") (match_operand 1 "" "i")) (clobber (reg:SI 31)) (use (match_operand 2 "" "")) ;; next_arg_reg (use (match_operand 3 "" ""))])] ;; struct_value_size_rtx "" " { rtx addr;

if (operands[0]) /* eliminate unused code warnings */ { addr = XEXP (operands[0], 0); if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS)) || ! call_insn_operand (addr, VOIDmode)) XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);

  /* In order to pass small structures by value in registers
 compatibly with the MIPS compiler, we need to shift the value
 into the high part of the register.  Function_arg has encoded
 a PARALLEL rtx, holding a vector of adjustments to be made
 as the next_arg_reg variable, so we split up the insns,
 and emit them separately.  */

  if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL)
{
  rtvec adjust = XVEC (operands[2], 0);
  int num = GET_NUM_ELEM (adjust);
  int i;

  for (i = 0; i < num; i++)
    emit_insn (RTVEC_ELT (adjust, i));
}

  if (TARGET_MIPS16
  && mips16_hard_float
  && operands[2] != 0
  && (int) GET_MODE (operands[2]) != 0)
{
  if (build_mips16_call_stub (NULL_RTX, operands[0], operands[1],
			      (int) GET_MODE (operands[2])))
    DONE;
}

  emit_call_insn (gen_call_internal0 (operands[0], operands[1],
				  gen_rtx_REG (SImode,
					       GP_REG_FIRST + 31)));
  DONE;
}

}")

(define_expand "call_internal0" [(parallel [(call (match_operand 0 "" "") (match_operand 1 "" "")) (clobber (match_operand:SI 2 "" ""))])] "" "")

;; We need to recognize reg:SI 31 specially for the mips16, because we ;; don't have a constraint letter for it.

(define_insn "" [(call (mem (match_operand 0 "call_insn_operand" "ei")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=y"))] "TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS && GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 31" "%*jal\t%0" [(set_attr "type" "call") (set_attr "mode" "none") (set_attr "length" "8")])

(define_insn "call_internal1" [(call (mem (match_operand 0 "call_insn_operand" "ri")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=d"))] "!TARGET_ABICALLS && !TARGET_LONG_CALLS" "* { register rtx target = operands[0];

if (GET_CODE (target) == CONST_INT) return "%[li\t%@,%0\n\t%*jal\t%2,%@%]"; else if (CONSTANT_ADDRESS_P (target)) return "%*jal\t%0"; else return "%*jal\t%2,%0"; }" [(set_attr "type" "call") (set_attr "mode" "none")])

(define_insn "call_internal2" [(call (mem (match_operand 0 "call_insn_operand" "ri")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=d"))] "TARGET_ABICALLS && !TARGET_LONG_CALLS" "* { register rtx target = operands[0];

if (GET_CODE (target) == CONST_INT) return "li\t%^,%0\n\tjal\t%2,%^"; else if (CONSTANT_ADDRESS_P (target)) { if (GET_MODE (target) == SImode) return "la\t%^,%0\n\tjal\t%2,%^"; else return "dla\t%^,%0\n\tjal\t%2,%^"; } else if (REGNO (target) != 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" "8")])

(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_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS" "%*jal\t%2,%0" [(set_attr "type" "call") (set_attr "mode" "none")])

(define_insn "call_internal3b" [(call (mem:DI (match_operand:DI 0 "se_register_operand" "r")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=d"))] "!TARGET_MIPS16 && Pmode == DImode && !TARGET_ABICALLS && TARGET_LONG_CALLS" "%*jal\t%2,%0" [(set_attr "type" "call") (set_attr "mode" "none") (set_attr "length" "1")])

(define_insn "call_internal3c" [(call (mem:SI (match_operand:SI 0 "register_operand" "e")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=y"))] "TARGET_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS && GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 31" "%*jal\t%2,%0" [(set_attr "type" "call") (set_attr "mode" "none")])

(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"))] "!(Pmode == DImode) && 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" "8")])

(define_insn "call_internal4b" [(call (mem:DI (match_operand:DI 0 "se_register_operand" "r")) (match_operand 1 "" "i")) (clobber (match_operand:SI 2 "register_operand" "=d"))] "Pmode == DImode && 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" "8")])

;; calls.c now passes a fourth argument, make saber happy

(define_expand "call_value" [(parallel [(set (match_operand 0 "register_operand" "=df") (call (match_operand 1 "memory_operand" "m") (match_operand 2 "" "i"))) (clobber (reg:SI 31)) (use (match_operand 3 "" ""))])] ;; next_arg_reg "" " { rtx addr;

if (operands[0]) /* eliminate unused code warning */ { addr = XEXP (operands[1], 0); if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS)) || ! call_insn_operand (addr, VOIDmode)) XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);

  /* In order to pass small structures by value in registers
 compatibly with the MIPS compiler, we need to shift the value
 into the high part of the register.  Function_arg has encoded
 a PARALLEL rtx, holding a vector of adjustments to be made
 as the next_arg_reg variable, so we split up the insns,
 and emit them separately.  */

  if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL)
{
  rtvec adjust = XVEC (operands[3], 0);
  int num = GET_NUM_ELEM (adjust);
  int i;

  for (i = 0; i < num; i++)
    emit_insn (RTVEC_ELT (adjust, i));
}

  if (TARGET_MIPS16
  && mips16_hard_float
  && ((operands[3] != 0
       && (int) GET_MODE (operands[3]) != 0)
      || GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT))
{
  if (build_mips16_call_stub (operands[0], operands[1], operands[2],
			      (operands[3] == 0 ? 0
			       : (int) GET_MODE (operands[3]))))
    DONE;
}

  /* Handle Irix6 function calls that have multiple non-contiguous
 results.  */
  if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1)
{
  emit_call_insn (gen_call_value_multiple_internal0
		  (XEXP (XVECEXP (operands[0], 0, 0), 0),
		   operands[1], operands[2],
		   XEXP (XVECEXP (operands[0], 0, 1), 0),
		   gen_rtx_REG (SImode, GP_REG_FIRST + 31)));
  DONE;
}

  /* We have a call returning a DImode structure in an FP reg.
 Strip off the now unnecessary PARALLEL.  */
  if (GET_CODE (operands[0]) == PARALLEL)
operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);

  emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], operands[2],
				        gen_rtx_REG (SImode,
						     GP_REG_FIRST + 31)));

  DONE;
}

}")

(define_expand "call_value_internal0" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (clobber (match_operand:SI 3 "" ""))])] "" "")

;; Recognize $31 specially on the mips16, because we don't have a ;; constraint letter for it.

(define_insn "" [(set (match_operand 0 "register_operand" "=d") (call (mem (match_operand 1 "call_insn_operand" "ei")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=y"))] "TARGET_MIPS16 && !TARGET_ABICALLS && !TARGET_LONG_CALLS && GET_CODE (operands[3]) == REG && REGNO (operands[3]) == 31" "%*jal\t%1" [(set_attr "type" "call") (set_attr "mode" "none") (set_attr "length" "8")])

(define_insn "call_value_internal1" [(set (match_operand 0 "register_operand" "=df") (call (mem (match_operand 1 "call_insn_operand" "ri")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] "!TARGET_ABICALLS && !TARGET_LONG_CALLS" "* { register rtx target = operands[1];

if (GET_CODE (target) == CONST_INT) return "%[li\t%@,%1\n\t%*jal\t%3,%@%]"; else if (CONSTANT_ADDRESS_P (target)) return "%*jal\t%1"; else return "%*jal\t%3,%1"; }" [(set_attr "type" "call") (set_attr "mode" "none")])

(define_insn "call_value_internal2" [(set (match_operand 0 "register_operand" "=df") (call (mem (match_operand 1 "call_insn_operand" "ri")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] "TARGET_ABICALLS && !TARGET_LONG_CALLS" "* { register rtx target = operands[1];

if (GET_CODE (target) == CONST_INT) return "li\t%^,%1\n\tjal\t%3,%^"; else if (CONSTANT_ADDRESS_P (target)) { if (GET_MODE (target) == SImode) return "la\t%^,%1\n\tjal\t%3,%^"; else return "dla\t%^,%1\n\tjal\t%3,%^"; } else if (REGNO (target) != 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" "8")])

(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_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS" "%*jal\t%3,%1" [(set_attr "type" "call") (set_attr "mode" "none")])

(define_insn "call_value_internal3b" [(set (match_operand 0 "register_operand" "=df") (call (mem:DI (match_operand:DI 1 "se_register_operand" "r")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] "!TARGET_MIPS16 && Pmode == DImode && !TARGET_ABICALLS && TARGET_LONG_CALLS" "%*jal\t%3,%1" [(set_attr "type" "call") (set_attr "mode" "none")])

(define_insn "call_value_internal3c" [(set (match_operand 0 "register_operand" "=df") (call (mem:SI (match_operand:SI 1 "register_operand" "e")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=y"))] "TARGET_MIPS16 && !(Pmode == DImode) && !TARGET_ABICALLS && TARGET_LONG_CALLS && GET_CODE (operands[3]) == REG && REGNO (operands[3]) == 31" "%*jal\t%3,%1" [(set_attr "type" "call") (set_attr "mode" "none")])

(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"))] "!(Pmode == DImode) && 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" "8")])

(define_insn "call_value_internal4b" [(set (match_operand 0 "register_operand" "=df") (call (mem:DI (match_operand:DI 1 "se_register_operand" "r")) (match_operand 2 "" "i"))) (clobber (match_operand:SI 3 "register_operand" "=d"))] "Pmode == DImode && TARGET_ABICALLS && TARGET_LONG_CALLS" "* { 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" "8")])

(define_expand "call_value_multiple_internal0" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (set (match_operand 3 "" "") (call (match_dup 1) (match_dup 2))) (clobber (match_operand:SI 4 "" ""))])] "" "")

;; ??? May eventually need all 6 versions of the call patterns with multiple ;; return values.

(define_insn "call_value_multiple_internal1" [(set (match_operand 0 "register_operand" "=df") (call (mem (match_operand 1 "call_insn_operand" "ri")) (match_operand 2 "" "i"))) (set (match_operand 3 "register_operand" "=df") (call (mem (match_dup 1)) (match_dup 2))) (clobber (match_operand:SI 4 "register_operand" "=d"))] "!TARGET_ABICALLS && !TARGET_LONG_CALLS" "* { register rtx target = operands[1];

if (GET_CODE (target) == CONST_INT) return "%[li\t%@,%1\n\t%*jal\t%4,%@%]"; else if (CONSTANT_ADDRESS_P (target)) return "%*jal\t%1"; else return "%*jal\t%4,%1"; }" [(set_attr "type" "call") (set_attr "mode" "none")])

(define_insn "call_value_multiple_internal2" [(set (match_operand 0 "register_operand" "=df") (call (mem (match_operand 1 "call_insn_operand" "ri")) (match_operand 2 "" "i"))) (set (match_operand 3 "register_operand" "=df") (call (mem (match_dup 1)) (match_dup 2))) (clobber (match_operand:SI 4 "register_operand" "=d"))] "TARGET_ABICALLS && !TARGET_LONG_CALLS" "* { register rtx target = operands[1];

if (GET_CODE (target) == CONST_INT) return "li\t%^,%1\n\tjal\t%4,%^"; else if (CONSTANT_ADDRESS_P (target)) { if (GET_MODE (target) == SImode) return "la\t%^,%1\n\tjal\t%4,%^"; else return "dla\t%^,%1\n\tjal\t%4,%^"; } else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM) return "move\t%^,%1\n\tjal\t%4,%^"; else return "jal\t%4,%1"; }" [(set_attr "type" "call") (set_attr "mode" "none") (set_attr "length" "8")])

;; Call subroutine returning any type.

(define_expand "untyped_call" [(parallel [(call (match_operand 0 "" "") (const_int 0)) (match_operand 1 "" "") (match_operand 2 "" "")])] "" " { if (operands[0]) /* silence statement not reached warnings */ { int i;

  emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));

  for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
  rtx set = XVECEXP (operands[2], 0, i);
  emit_move_insn (SET_DEST (set), SET_SRC (set));
}

  emit_insn (gen_blockage ());
  DONE;
}

}") ;; ;; .................... ;; ;; MISC. ;; ;; .................... ;;

(define_expand "prefetch" [(prefetch (match_operand 0 "address_operand" "") (match_operand 1 "const_int_operand" "") (match_operand 2 "const_int_operand" ""))] "ISA_HAS_PREFETCH" "{ if (symbolic_operand (operands[0], GET_MODE (operands[0]))) operands[0] = force_reg (GET_MODE (operands[0]), operands[0]); }")

(define_insn "prefetch_si_address" [(prefetch (plus:SI (match_operand:SI 0 "register_operand" "r") (match_operand:SI 3 "const_int_operand" "i")) (match_operand:SI 1 "const_int_operand" "n") (match_operand:SI 2 "const_int_operand" "n"))] "ISA_HAS_PREFETCH && Pmode == SImode" "* return mips_emit_prefetch (operands);" [(set_attr "type" "load")])

(define_insn "prefetch_si" [(prefetch (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "const_int_operand" "n") (match_operand:SI 2 "const_int_operand" "n"))] "ISA_HAS_PREFETCH && Pmode == SImode" "* return mips_emit_prefetch (operands);" [(set_attr "type" "load")])

(define_insn "prefetch_di_address" [(prefetch (plus:DI (match_operand:DI 0 "se_register_operand" "r") (match_operand:DI 3 "const_int_operand" "i")) (match_operand:DI 1 "const_int_operand" "n") (match_operand:DI 2 "const_int_operand" "n"))] "ISA_HAS_PREFETCH && Pmode == DImode" "* return mips_emit_prefetch (operands);" [(set_attr "type" "load")])

(define_insn "prefetch_di" [(prefetch (match_operand:DI 0 "se_register_operand" "r") (match_operand:DI 1 "const_int_operand" "n") (match_operand:DI 2 "const_int_operand" "n"))] "ISA_HAS_PREFETCH && Pmode == DImode" "* return mips_emit_prefetch (operands);" [(set_attr "type" "load")])

(define_insn "nop" [(const_int 0)] "" "%(nop%)" [(set_attr "type" "nop") (set_attr "mode" "none")])

;; The MIPS chip does not seem to require stack probes. ;; ;; (define_expand "probe" ;; [(set (match_dup 0) ;; (match_dup 1))] ;; "" ;; " ;; { ;; operands[0] = gen_reg_rtx (SImode); ;; operands[1] = gen_rtx_MEM (SImode, stack_pointer_rtx); ;; MEM_VOLATILE_P (operands[1]) = TRUE; ;; ;; /* 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")))] "ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE" "@ 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 4 "equality_op" [(match_operand:DI 1 "se_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")))] "ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE" "@ 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" [(match_operand:CC 4 "register_operand" "z,z") (const_int 0)]) (match_operand:SI 1 "reg_or_0_operand" "dJ,0") (match_operand:SI 2 "reg_or_0_operand" "0,dJ")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT" "@ mov%T3\t%0,%z1,%4 mov%t3\t%0,%z2,%4" [(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:SI 1 "register_operand" "d,d") (const_int 0)]) (match_operand:DI 2 "se_reg_or_0_operand" "dJ,0") (match_operand:DI 3 "se_reg_or_0_operand" "0,dJ")))] "(ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE) && TARGET_64BIT" "@ 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 4 "equality_op" [(match_operand:DI 1 "se_register_operand" "d,d") (const_int 0)]) (match_operand:DI 2 "se_reg_or_0_operand" "dJ,0") (match_operand:DI 3 "se_reg_or_0_operand" "0,dJ")))] "(ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE) && TARGET_64BIT" "@ 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" [(match_operand:CC 4 "register_operand" "z,z") (const_int 0)]) (match_operand:DI 1 "se_reg_or_0_operand" "dJ,0") (match_operand:DI 2 "se_reg_or_0_operand" "0,dJ")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT && TARGET_64BIT" "@ mov%T3\t%0,%z1,%4 mov%t3\t%0,%z2,%4" [(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")))] "ISA_HAS_CONDMOVE && 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 4 "equality_op" [(match_operand:DI 1 "se_register_operand" "d,d") (const_int 0)]) (match_operand:SF 2 "register_operand" "f,0") (match_operand:SF 3 "register_operand" "0,f")))] "ISA_HAS_CONDMOVE && 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" [(match_operand:CC 4 "register_operand" "z,z") (const_int 0)]) (match_operand:SF 1 "register_operand" "f,0") (match_operand:SF 2 "register_operand" "0,f")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT" "@ mov%T3.s\t%0,%1,%4 mov%t3.s\t%0,%2,%4" [(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")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE_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 4 "equality_op" [(match_operand:DI 1 "se_register_operand" "d,d") (const_int 0)]) (match_operand:DF 2 "register_operand" "f,0") (match_operand:DF 3 "register_operand" "0,f")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE_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" [(match_operand:CC 4 "register_operand" "z,z") (const_int 0)]) (match_operand:DF 1 "register_operand" "f,0") (match_operand:DF 2 "register_operand" "0,f")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" "@ mov%T3.d\t%0,%1,%4 mov%t3.d\t%0,%2,%4" [(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" "")))] "ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE" " { gen_conditional_move (operands); DONE; }")

(define_expand "movdicc" [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) (set (match_operand:DI 0 "register_operand" "") (if_then_else:DI (match_dup 5) (match_operand:DI 2 "se_reg_or_0_operand" "") (match_operand:DI 3 "se_reg_or_0_operand" "")))] "(ISA_HAS_CONDMOVE || ISA_HAS_INT_CONDMOVE) && TARGET_64BIT" " { gen_conditional_move (operands); DONE; }")

(define_expand "movsfcc" [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) (set (match_operand:SF 0 "register_operand" "") (if_then_else:SF (match_dup 5) (match_operand:SF 2 "register_operand" "") (match_operand:SF 3 "register_operand" "")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT" " { gen_conditional_move (operands); DONE; }")

(define_expand "movdfcc" [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) (set (match_operand:DF 0 "register_operand" "") (if_then_else:DF (match_dup 5) (match_operand:DF 2 "register_operand" "") (match_operand:DF 3 "register_operand" "")))] "ISA_HAS_CONDMOVE && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" " { gen_conditional_move (operands); DONE; }") ;; ;; .................... ;; ;; mips16 inline constant tables ;; ;; .................... ;;

(define_insn "consttable_qi" [(unspec_volatile [(match_operand:QI 0 "consttable_operand" "=g")] UNSPEC_CONSTTABLE_QI)] "TARGET_MIPS16" "* { assemble_integer (operands[0], 1, BITS_PER_UNIT, 1); return ""; }" [(set_attr "type" "unknown") (set_attr "mode" "QI") (set_attr "length" "8")])

(define_insn "consttable_hi" [(unspec_volatile [(match_operand:HI 0 "consttable_operand" "=g")] UNSPEC_CONSTTABLE_HI)] "TARGET_MIPS16" "* { assemble_integer (operands[0], 2, BITS_PER_UNIT * 2, 1); return ""; }" [(set_attr "type" "unknown") (set_attr "mode" "HI") (set_attr "length" "8")])

(define_insn "consttable_si" [(unspec_volatile [(match_operand:SI 0 "consttable_operand" "=g")] UNSPEC_CONSTTABLE_SI)] "TARGET_MIPS16" "* { assemble_integer (operands[0], 4, BITS_PER_UNIT * 4, 1); return ""; }" [(set_attr "type" "unknown") (set_attr "mode" "SI") (set_attr "length" "8")])

(define_insn "consttable_di" [(unspec_volatile [(match_operand:DI 0 "consttable_operand" "=g")] UNSPEC_CONSTTABLE_DI)] "TARGET_MIPS16" "* { assemble_integer (operands[0], 8, BITS_PER_UNIT * 8, 1); return ""; }" [(set_attr "type" "unknown") (set_attr "mode" "DI") (set_attr "length" "16")])

(define_insn "consttable_sf" [(unspec_volatile [(match_operand:SF 0 "consttable_operand" "=g")] UNSPEC_CONSTTABLE_SF)] "TARGET_MIPS16" "* { REAL_VALUE_TYPE d;

if (GET_CODE (operands[0]) != CONST_DOUBLE) abort (); REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]); assemble_real (d, SFmode, GET_MODE_ALIGNMENT (SFmode)); return ""; }" [(set_attr "type" "unknown") (set_attr "mode" "SF") (set_attr "length" "8")])

(define_insn "consttable_df" [(unspec_volatile [(match_operand:DF 0 "consttable_operand" "=g")] UNSPEC_CONSTTABLE_DF)] "TARGET_MIPS16" "* { REAL_VALUE_TYPE d;

if (GET_CODE (operands[0]) != CONST_DOUBLE) abort (); REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]); assemble_real (d, DFmode, GET_MODE_ALIGNMENT (DFmode)); return ""; }" [(set_attr "type" "unknown") (set_attr "mode" "DF") (set_attr "length" "16")])

(define_insn "align_2" [(unspec_volatile [(const_int 0)] UNSPEC_ALIGN_2)] "TARGET_MIPS16" ".align 1" [(set_attr "type" "unknown") (set_attr "mode" "HI") (set_attr "length" "8")])

(define_insn "align_4" [(unspec_volatile [(const_int 0)] UNSPEC_ALIGN_4)] "TARGET_MIPS16" ".align 2" [(set_attr "type" "unknown") (set_attr "mode" "SI") (set_attr "length" "8")])

(define_insn "align_8" [(unspec_volatile [(const_int 0)] UNSPEC_ALIGN_8)] "TARGET_MIPS16" ".align 3" [(set_attr "type" "unknown") (set_attr "mode" "DI") (set_attr "length" "12")]) ;; ;; .................... ;; ;; mips16 peepholes ;; ;; .................... ;;

;; On the mips16, reload will sometimes decide that a pseudo register ;; should go into $24, and then later on have to reload that register. ;; When that happens, we get a load of a general register followed by ;; a move from the general register to $24 followed by a branch. ;; These peepholes catch the common case, and fix it to just use the ;; general register for the branch.

(define_peephole [(set (match_operand:SI 0 "register_operand" "=t") (match_operand:SI 1 "register_operand" "d")) (set (pc) (if_then_else (match_operator:SI 2 "equality_op" [(match_dup 0) (const_int 0)]) (match_operand 3 "pc_or_label_operand" "") (match_operand 4 "pc_or_label_operand" "")))] "TARGET_MIPS16 && GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 24 && dead_or_set_p (insn, operands[0]) && GET_CODE (operands[1]) == REG && M16_REG_P (REGNO (operands[1]))" "* { if (operands[3] != pc_rtx) return "%*b%C2z\t%1,%3"; else return "%*b%N2z\t%1,%4"; }" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

(define_peephole [(set (match_operand:DI 0 "register_operand" "=t") (match_operand:DI 1 "register_operand" "d")) (set (pc) (if_then_else (match_operator:DI 2 "equality_op" [(match_dup 0) (const_int 0)]) (match_operand 3 "pc_or_label_operand" "") (match_operand 4 "pc_or_label_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 24 && dead_or_set_p (insn, operands[0]) && GET_CODE (operands[1]) == REG && M16_REG_P (REGNO (operands[1]))" "* { if (operands[3] != pc_rtx) return "%*b%C2z\t%1,%3"; else return "%*b%N2z\t%1,%4"; }" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

;; We can also have the reverse reload: reload will spill $24 into ;; another register, and then do a branch on that register when it ;; could have just stuck with $24.

(define_peephole [(set (match_operand:SI 0 "register_operand" "=d") (match_operand:SI 1 "register_operand" "t")) (set (pc) (if_then_else (match_operator:SI 2 "equality_op" [(match_dup 0) (const_int 0)]) (match_operand 3 "pc_or_label_operand" "") (match_operand 4 "pc_or_label_operand" "")))] "TARGET_MIPS16 && GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 24 && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && dead_or_set_p (insn, operands[0])" "* { if (operands[3] != pc_rtx) return "%*bt%C2z\t%3"; else return "%*bt%N2z\t%4"; }" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

(define_peephole [(set (match_operand:DI 0 "register_operand" "=d") (match_operand:DI 1 "register_operand" "t")) (set (pc) (if_then_else (match_operator:DI 2 "equality_op" [(match_dup 0) (const_int 0)]) (match_operand 3 "pc_or_label_operand" "") (match_operand 4 "pc_or_label_operand" "")))] "TARGET_MIPS16 && TARGET_64BIT && GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 24 && GET_CODE (operands[0]) == REG && M16_REG_P (REGNO (operands[0])) && dead_or_set_p (insn, operands[0])" "* { if (operands[3] != pc_rtx) return "%*bt%C2z\t%3"; else return "%*bt%N2z\t%4"; }" [(set_attr "type" "branch") (set_attr "mode" "none") (set_attr "length" "8")])

;; For the rare case where we need to load an address into a register ;; that can not be recognized by the normal movsi/addsi instructions. ;; I have no idea how many insns this can actually generate. It should ;; be rare, so over-estimating as 10 instructions should not have any ;; real performance impact. (define_insn "leasi" [(set (match_operand:SI 0 "register_operand" "=d") (match_operand:SI 1 "address_operand" "p"))] "Pmode == SImode" "la %0,%a1" [(set_attr "type" "arith") (set_attr "mode" "SI") (set_attr "length" "40")])

;; Similarly for targets where we have 64bit pointers. (define_insn "leadi" [(set (match_operand:DI 0 "register_operand" "=d") (match_operand:DI 1 "address_operand" "p"))] "Pmode == DImode" "dla %0,%a1" [(set_attr "type" "arith") (set_attr "mode" "DI") (set_attr "length" "40")])