1169689Skan;; Mips.md Machine Description for MIPS based processors 2169689Skan;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3169689Skan;; 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 4169689Skan;; Contributed by A. Lichnewsky, lich@inria.inria.fr 5169689Skan;; Changes by Michael Meissner, meissner@osf.org 6169689Skan;; 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and 7169689Skan;; Brendan Eich, brendan@microunity.com. 8169689Skan 9169689Skan;; This file is part of GCC. 10169689Skan 11169689Skan;; GCC is free software; you can redistribute it and/or modify 12169689Skan;; it under the terms of the GNU General Public License as published by 13169689Skan;; the Free Software Foundation; either version 2, or (at your option) 14169689Skan;; any later version. 15169689Skan 16169689Skan;; GCC is distributed in the hope that it will be useful, 17169689Skan;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18169689Skan;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19169689Skan;; GNU General Public License for more details. 20169689Skan 21169689Skan;; You should have received a copy of the GNU General Public License 22169689Skan;; along with GCC; see the file COPYING. If not, write to 23169689Skan;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, 24169689Skan;; Boston, MA 02110-1301, USA. 25169689Skan 26169689Skan(define_constants 27169689Skan [(UNSPEC_LOAD_DF_LOW 0) 28169689Skan (UNSPEC_LOAD_DF_HIGH 1) 29169689Skan (UNSPEC_STORE_DF_HIGH 2) 30169689Skan (UNSPEC_GET_FNADDR 3) 31169689Skan (UNSPEC_BLOCKAGE 4) 32169689Skan (UNSPEC_CPRESTORE 5) 33169689Skan (UNSPEC_EH_RECEIVER 6) 34169689Skan (UNSPEC_EH_RETURN 7) 35169689Skan (UNSPEC_CONSTTABLE_INT 8) 36169689Skan (UNSPEC_CONSTTABLE_FLOAT 9) 37169689Skan (UNSPEC_ALIGN 14) 38169689Skan (UNSPEC_HIGH 17) 39169689Skan (UNSPEC_LOAD_LEFT 18) 40169689Skan (UNSPEC_LOAD_RIGHT 19) 41169689Skan (UNSPEC_STORE_LEFT 20) 42169689Skan (UNSPEC_STORE_RIGHT 21) 43169689Skan (UNSPEC_LOADGP 22) 44169689Skan (UNSPEC_LOAD_CALL 23) 45169689Skan (UNSPEC_LOAD_GOT 24) 46169689Skan (UNSPEC_GP 25) 47169689Skan (UNSPEC_MFHILO 26) 48169689Skan (UNSPEC_TLS_LDM 27) 49169689Skan (UNSPEC_TLS_GET_TP 28) 50169689Skan 51169689Skan (UNSPEC_ADDRESS_FIRST 100) 52169689Skan 53169689Skan (FAKE_CALL_REGNO 79) 54169689Skan 55169689Skan ;; For MIPS Paired-Singled Floating Point Instructions. 56169689Skan 57169689Skan (UNSPEC_MOVE_TF_PS 200) 58169689Skan (UNSPEC_C 201) 59169689Skan 60169689Skan ;; MIPS64/MIPS32R2 alnv.ps 61169689Skan (UNSPEC_ALNV_PS 202) 62169689Skan 63169689Skan ;; MIPS-3D instructions 64169689Skan (UNSPEC_CABS 203) 65169689Skan 66169689Skan (UNSPEC_ADDR_PS 204) 67169689Skan (UNSPEC_CVT_PW_PS 205) 68169689Skan (UNSPEC_CVT_PS_PW 206) 69169689Skan (UNSPEC_MULR_PS 207) 70169689Skan (UNSPEC_ABS_PS 208) 71169689Skan 72169689Skan (UNSPEC_RSQRT1 209) 73169689Skan (UNSPEC_RSQRT2 210) 74169689Skan (UNSPEC_RECIP1 211) 75169689Skan (UNSPEC_RECIP2 212) 76169689Skan (UNSPEC_SINGLE_CC 213) 77169689Skan (UNSPEC_SCC 214) 78169689Skan 79169689Skan ;; MIPS DSP ASE Revision 0.98 3/24/2005 80169689Skan (UNSPEC_ADDQ 300) 81169689Skan (UNSPEC_ADDQ_S 301) 82169689Skan (UNSPEC_SUBQ 302) 83169689Skan (UNSPEC_SUBQ_S 303) 84169689Skan (UNSPEC_ADDSC 304) 85169689Skan (UNSPEC_ADDWC 305) 86169689Skan (UNSPEC_MODSUB 306) 87169689Skan (UNSPEC_RADDU_W_QB 307) 88169689Skan (UNSPEC_ABSQ_S 308) 89169689Skan (UNSPEC_PRECRQ_QB_PH 309) 90169689Skan (UNSPEC_PRECRQ_PH_W 310) 91169689Skan (UNSPEC_PRECRQ_RS_PH_W 311) 92169689Skan (UNSPEC_PRECRQU_S_QB_PH 312) 93169689Skan (UNSPEC_PRECEQ_W_PHL 313) 94169689Skan (UNSPEC_PRECEQ_W_PHR 314) 95169689Skan (UNSPEC_PRECEQU_PH_QBL 315) 96169689Skan (UNSPEC_PRECEQU_PH_QBR 316) 97169689Skan (UNSPEC_PRECEQU_PH_QBLA 317) 98169689Skan (UNSPEC_PRECEQU_PH_QBRA 318) 99169689Skan (UNSPEC_PRECEU_PH_QBL 319) 100169689Skan (UNSPEC_PRECEU_PH_QBR 320) 101169689Skan (UNSPEC_PRECEU_PH_QBLA 321) 102169689Skan (UNSPEC_PRECEU_PH_QBRA 322) 103169689Skan (UNSPEC_SHLL 323) 104169689Skan (UNSPEC_SHLL_S 324) 105169689Skan (UNSPEC_SHRL_QB 325) 106169689Skan (UNSPEC_SHRA_PH 326) 107169689Skan (UNSPEC_SHRA_R 327) 108169689Skan (UNSPEC_MULEU_S_PH_QBL 328) 109169689Skan (UNSPEC_MULEU_S_PH_QBR 329) 110169689Skan (UNSPEC_MULQ_RS_PH 330) 111169689Skan (UNSPEC_MULEQ_S_W_PHL 331) 112169689Skan (UNSPEC_MULEQ_S_W_PHR 332) 113169689Skan (UNSPEC_DPAU_H_QBL 333) 114169689Skan (UNSPEC_DPAU_H_QBR 334) 115169689Skan (UNSPEC_DPSU_H_QBL 335) 116169689Skan (UNSPEC_DPSU_H_QBR 336) 117169689Skan (UNSPEC_DPAQ_S_W_PH 337) 118169689Skan (UNSPEC_DPSQ_S_W_PH 338) 119169689Skan (UNSPEC_MULSAQ_S_W_PH 339) 120169689Skan (UNSPEC_DPAQ_SA_L_W 340) 121169689Skan (UNSPEC_DPSQ_SA_L_W 341) 122169689Skan (UNSPEC_MAQ_S_W_PHL 342) 123169689Skan (UNSPEC_MAQ_S_W_PHR 343) 124169689Skan (UNSPEC_MAQ_SA_W_PHL 344) 125169689Skan (UNSPEC_MAQ_SA_W_PHR 345) 126169689Skan (UNSPEC_BITREV 346) 127169689Skan (UNSPEC_INSV 347) 128169689Skan (UNSPEC_REPL_QB 348) 129169689Skan (UNSPEC_REPL_PH 349) 130169689Skan (UNSPEC_CMP_EQ 350) 131169689Skan (UNSPEC_CMP_LT 351) 132169689Skan (UNSPEC_CMP_LE 352) 133169689Skan (UNSPEC_CMPGU_EQ_QB 353) 134169689Skan (UNSPEC_CMPGU_LT_QB 354) 135169689Skan (UNSPEC_CMPGU_LE_QB 355) 136169689Skan (UNSPEC_PICK 356) 137169689Skan (UNSPEC_PACKRL_PH 357) 138169689Skan (UNSPEC_EXTR_W 358) 139169689Skan (UNSPEC_EXTR_R_W 359) 140169689Skan (UNSPEC_EXTR_RS_W 360) 141169689Skan (UNSPEC_EXTR_S_H 361) 142169689Skan (UNSPEC_EXTP 362) 143169689Skan (UNSPEC_EXTPDP 363) 144169689Skan (UNSPEC_SHILO 364) 145169689Skan (UNSPEC_MTHLIP 365) 146169689Skan (UNSPEC_WRDSP 366) 147169689Skan (UNSPEC_RDDSP 367) 148169689Skan ] 149169689Skan) 150169689Skan 151169689Skan(include "predicates.md") 152169689Skan(include "constraints.md") 153169689Skan 154169689Skan;; .................... 155169689Skan;; 156169689Skan;; Attributes 157169689Skan;; 158169689Skan;; .................... 159169689Skan 160169689Skan(define_attr "got" "unset,xgot_high,load" 161169689Skan (const_string "unset")) 162169689Skan 163169689Skan;; For jal instructions, this attribute is DIRECT when the target address 164169689Skan;; is symbolic and INDIRECT when it is a register. 165169689Skan(define_attr "jal" "unset,direct,indirect" 166169689Skan (const_string "unset")) 167169689Skan 168169689Skan;; This attribute is YES if the instruction is a jal macro (not a 169169689Skan;; real jal instruction). 170169689Skan;; 171169689Skan;; jal is always a macro for o32 and o64 abicalls because it includes an 172169689Skan;; instruction to restore $gp. Direct jals are also macros for -mshared 173169689Skan;; abicalls because they first load the target address into $25. 174169689Skan(define_attr "jal_macro" "no,yes" 175169689Skan (cond [(eq_attr "jal" "direct") 176169689Skan (symbol_ref "TARGET_ABICALLS 177169689Skan && (TARGET_OLDABI || !TARGET_ABSOLUTE_ABICALLS)") 178169689Skan (eq_attr "jal" "indirect") 179169689Skan (symbol_ref "TARGET_ABICALLS && TARGET_OLDABI")] 180169689Skan (const_string "no"))) 181169689Skan 182169689Skan;; Classification of each insn. 183169689Skan;; branch conditional branch 184169689Skan;; jump unconditional jump 185169689Skan;; call unconditional call 186169689Skan;; load load instruction(s) 187169689Skan;; fpload floating point load 188169689Skan;; fpidxload floating point indexed load 189169689Skan;; store store instruction(s) 190169689Skan;; fpstore floating point store 191169689Skan;; fpidxstore floating point indexed store 192169689Skan;; prefetch memory prefetch (register + offset) 193169689Skan;; prefetchx memory indexed prefetch (register + register) 194169689Skan;; condmove conditional moves 195169689Skan;; xfer transfer to/from coprocessor 196169689Skan;; mthilo transfer to hi/lo registers 197169689Skan;; mfhilo transfer from hi/lo registers 198169689Skan;; const load constant 199169689Skan;; arith integer arithmetic and logical instructions 200169689Skan;; shift integer shift instructions 201169689Skan;; slt set less than instructions 202169689Skan;; clz the clz and clo instructions 203169689Skan;; trap trap if instructions 204169689Skan;; imul integer multiply 2 operands 205169689Skan;; imul3 integer multiply 3 operands 206169689Skan;; imadd integer multiply-add 207169689Skan;; idiv integer divide 208169689Skan;; fmove floating point register move 209169689Skan;; fadd floating point add/subtract 210169689Skan;; fmul floating point multiply 211169689Skan;; fmadd floating point multiply-add 212169689Skan;; fdiv floating point divide 213169689Skan;; frdiv floating point reciprocal divide 214169689Skan;; frdiv1 floating point reciprocal divide step 1 215169689Skan;; frdiv2 floating point reciprocal divide step 2 216169689Skan;; fabs floating point absolute value 217169689Skan;; fneg floating point negation 218169689Skan;; fcmp floating point compare 219169689Skan;; fcvt floating point convert 220169689Skan;; fsqrt floating point square root 221169689Skan;; frsqrt floating point reciprocal square root 222169689Skan;; frsqrt1 floating point reciprocal square root step1 223169689Skan;; frsqrt2 floating point reciprocal square root step2 224169689Skan;; multi multiword sequence (or user asm statements) 225169689Skan;; nop no operation 226169689Skan(define_attr "type" 227169689Skan "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,prefetch,prefetchx,condmove,xfer,mthilo,mfhilo,const,arith,shift,slt,clz,trap,imul,imul3,imadd,idiv,fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,frsqrt1,frsqrt2,multi,nop" 228169689Skan (cond [(eq_attr "jal" "!unset") (const_string "call") 229169689Skan (eq_attr "got" "load") (const_string "load")] 230169689Skan (const_string "unknown"))) 231169689Skan 232169689Skan;; Main data type used by the insn 233169689Skan(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF,FPSW" 234169689Skan (const_string "unknown")) 235169689Skan 236169689Skan;; Mode for conversion types (fcvt) 237169689Skan;; I2S integer to float single (SI/DI to SF) 238169689Skan;; I2D integer to float double (SI/DI to DF) 239169689Skan;; S2I float to integer (SF to SI/DI) 240169689Skan;; D2I float to integer (DF to SI/DI) 241169689Skan;; D2S double to float single 242169689Skan;; S2D float single to double 243169689Skan 244169689Skan(define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D" 245169689Skan (const_string "unknown")) 246169689Skan 247169689Skan;; Is this an extended instruction in mips16 mode? 248169689Skan(define_attr "extended_mips16" "no,yes" 249169689Skan (const_string "no")) 250169689Skan 251169689Skan;; Length of instruction in bytes. 252169689Skan(define_attr "length" "" 253169689Skan (cond [;; Direct branch instructions have a range of [-0x40000,0x3fffc]. 254169689Skan ;; If a branch is outside this range, we have a choice of two 255169689Skan ;; sequences. For PIC, an out-of-range branch like: 256169689Skan ;; 257169689Skan ;; bne r1,r2,target 258169689Skan ;; dslot 259169689Skan ;; 260169689Skan ;; becomes the equivalent of: 261169689Skan ;; 262169689Skan ;; beq r1,r2,1f 263169689Skan ;; dslot 264169689Skan ;; la $at,target 265169689Skan ;; jr $at 266169689Skan ;; nop 267169689Skan ;; 1: 268169689Skan ;; 269169689Skan ;; where the load address can be up to three instructions long 270169689Skan ;; (lw, nop, addiu). 271169689Skan ;; 272169689Skan ;; The non-PIC case is similar except that we use a direct 273169689Skan ;; jump instead of an la/jr pair. Since the target of this 274169689Skan ;; jump is an absolute 28-bit bit address (the other bits 275169689Skan ;; coming from the address of the delay slot) this form cannot 276169689Skan ;; cross a 256MB boundary. We could provide the option of 277169689Skan ;; using la/jr in this case too, but we do not do so at 278169689Skan ;; present. 279169689Skan ;; 280169689Skan ;; Note that this value does not account for the delay slot 281169689Skan ;; instruction, whose length is added separately. If the RTL 282169689Skan ;; pattern has no explicit delay slot, mips_adjust_insn_length 283169689Skan ;; will add the length of the implicit nop. The values for 284169689Skan ;; forward and backward branches will be different as well. 285169689Skan (eq_attr "type" "branch") 286169689Skan (cond [(and (le (minus (match_dup 1) (pc)) (const_int 131064)) 287169689Skan (le (minus (pc) (match_dup 1)) (const_int 131068))) 288169689Skan (const_int 4) 289169689Skan (ne (symbol_ref "flag_pic") (const_int 0)) 290169689Skan (const_int 24) 291169689Skan ] (const_int 12)) 292169689Skan 293169689Skan (eq_attr "got" "load") 294169689Skan (const_int 4) 295169689Skan (eq_attr "got" "xgot_high") 296169689Skan (const_int 8) 297169689Skan 298169689Skan (eq_attr "type" "const") 299169689Skan (symbol_ref "mips_const_insns (operands[1]) * 4") 300169689Skan (eq_attr "type" "load,fpload") 301169689Skan (symbol_ref "mips_fetch_insns (operands[1]) * 4") 302169689Skan (eq_attr "type" "store,fpstore") 303169689Skan (symbol_ref "mips_fetch_insns (operands[0]) * 4") 304169689Skan 305169689Skan ;; In the worst case, a call macro will take 8 instructions: 306169689Skan ;; 307169689Skan ;; lui $25,%call_hi(FOO) 308169689Skan ;; addu $25,$25,$28 309169689Skan ;; lw $25,%call_lo(FOO)($25) 310169689Skan ;; nop 311169689Skan ;; jalr $25 312169689Skan ;; nop 313169689Skan ;; lw $gp,X($sp) 314169689Skan ;; nop 315169689Skan (eq_attr "jal_macro" "yes") 316169689Skan (const_int 32) 317169689Skan 318169689Skan (and (eq_attr "extended_mips16" "yes") 319169689Skan (ne (symbol_ref "TARGET_MIPS16") (const_int 0))) 320169689Skan (const_int 8) 321169689Skan 322169689Skan ;; Various VR4120 errata require a nop to be inserted after a macc 323169689Skan ;; instruction. The assembler does this for us, so account for 324169689Skan ;; the worst-case length here. 325169689Skan (and (eq_attr "type" "imadd") 326169689Skan (ne (symbol_ref "TARGET_FIX_VR4120") (const_int 0))) 327169689Skan (const_int 8) 328169689Skan 329169689Skan ;; VR4120 errata MD(4): if there are consecutive dmult instructions, 330169689Skan ;; the result of the second one is missed. The assembler should work 331169689Skan ;; around this by inserting a nop after the first dmult. 332169689Skan (and (eq_attr "type" "imul,imul3") 333169689Skan (and (eq_attr "mode" "DI") 334169689Skan (ne (symbol_ref "TARGET_FIX_VR4120") (const_int 0)))) 335169689Skan (const_int 8) 336169689Skan 337169689Skan (eq_attr "type" "idiv") 338169689Skan (symbol_ref "mips_idiv_insns () * 4") 339169689Skan ] (const_int 4))) 340169689Skan 341169689Skan;; Attribute describing the processor. This attribute must match exactly 342169689Skan;; with the processor_type enumeration in mips.h. 343169689Skan(define_attr "cpu" 344169689Skan "r3000,4kc,4kp,5kc,5kf,20kc,24k,24kx,m4k,r3900,r6000,r4000,r4100,r4111,r4120,r4130,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,sb1,sb1a,sr71000" 345169689Skan (const (symbol_ref "mips_tune"))) 346169689Skan 347169689Skan;; The type of hardware hazard associated with this instruction. 348169689Skan;; DELAY means that the next instruction cannot read the result 349169689Skan;; of this one. HILO means that the next two instructions cannot 350169689Skan;; write to HI or LO. 351169689Skan(define_attr "hazard" "none,delay,hilo" 352169689Skan (cond [(and (eq_attr "type" "load,fpload,fpidxload") 353169689Skan (ne (symbol_ref "ISA_HAS_LOAD_DELAY") (const_int 0))) 354169689Skan (const_string "delay") 355169689Skan 356169689Skan (and (eq_attr "type" "xfer") 357169689Skan (ne (symbol_ref "ISA_HAS_XFER_DELAY") (const_int 0))) 358169689Skan (const_string "delay") 359169689Skan 360169689Skan (and (eq_attr "type" "fcmp") 361169689Skan (ne (symbol_ref "ISA_HAS_FCMP_DELAY") (const_int 0))) 362169689Skan (const_string "delay") 363169689Skan 364169689Skan ;; The r4000 multiplication patterns include an mflo instruction. 365169689Skan (and (eq_attr "type" "imul") 366169689Skan (ne (symbol_ref "TARGET_FIX_R4000") (const_int 0))) 367169689Skan (const_string "hilo") 368169689Skan 369169689Skan (and (eq_attr "type" "mfhilo") 370169689Skan (eq (symbol_ref "ISA_HAS_HILO_INTERLOCKS") (const_int 0))) 371169689Skan (const_string "hilo")] 372169689Skan (const_string "none"))) 373169689Skan 374169689Skan;; Is it a single instruction? 375169689Skan(define_attr "single_insn" "no,yes" 376169689Skan (symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)")) 377169689Skan 378169689Skan;; Can the instruction be put into a delay slot? 379169689Skan(define_attr "can_delay" "no,yes" 380169689Skan (if_then_else (and (eq_attr "type" "!branch,call,jump") 381169689Skan (and (eq_attr "hazard" "none") 382169689Skan (eq_attr "single_insn" "yes"))) 383169689Skan (const_string "yes") 384169689Skan (const_string "no"))) 385169689Skan 386169689Skan;; Attribute defining whether or not we can use the branch-likely instructions 387169689Skan(define_attr "branch_likely" "no,yes" 388169689Skan (const 389169689Skan (if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0)) 390169689Skan (const_string "yes") 391169689Skan (const_string "no")))) 392169689Skan 393169689Skan;; True if an instruction might assign to hi or lo when reloaded. 394169689Skan;; This is used by the TUNE_MACC_CHAINS code. 395169689Skan(define_attr "may_clobber_hilo" "no,yes" 396169689Skan (if_then_else (eq_attr "type" "imul,imul3,imadd,idiv,mthilo") 397169689Skan (const_string "yes") 398169689Skan (const_string "no"))) 399169689Skan 400169689Skan;; Describe a user's asm statement. 401169689Skan(define_asm_attributes 402169689Skan [(set_attr "type" "multi") 403169689Skan (set_attr "can_delay" "no")]) 404169689Skan 405169689Skan;; This mode macro allows 32-bit and 64-bit GPR patterns to be generated 406169689Skan;; from the same template. 407169689Skan(define_mode_macro GPR [SI (DI "TARGET_64BIT")]) 408169689Skan 409169689Skan;; This mode macro allows :P to be used for patterns that operate on 410169689Skan;; pointer-sized quantities. Exactly one of the two alternatives will match. 411169689Skan(define_mode_macro P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) 412169689Skan 413169689Skan;; This mode macro allows :MOVECC to be used anywhere that a 414169689Skan;; conditional-move-type condition is needed. 415169689Skan(define_mode_macro MOVECC [SI (DI "TARGET_64BIT") (CC "TARGET_HARD_FLOAT")]) 416169689Skan 417169689Skan;; This mode macro allows the QI and HI extension patterns to be defined from 418169689Skan;; the same template. 419169689Skan(define_mode_macro SHORT [QI HI]) 420169689Skan 421169689Skan;; This mode macro allows :ANYF to be used wherever a scalar or vector 422169689Skan;; floating-point mode is allowed. 423169689Skan(define_mode_macro ANYF [(SF "TARGET_HARD_FLOAT") 424169689Skan (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT") 425169689Skan (V2SF "TARGET_PAIRED_SINGLE_FLOAT")]) 426169689Skan 427169689Skan;; Like ANYF, but only applies to scalar modes. 428169689Skan(define_mode_macro SCALARF [(SF "TARGET_HARD_FLOAT") 429169689Skan (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")]) 430169689Skan 431169689Skan;; In GPR templates, a string like "<d>subu" will expand to "subu" in the 432169689Skan;; 32-bit version and "dsubu" in the 64-bit version. 433169689Skan(define_mode_attr d [(SI "") (DI "d")]) 434169689Skan 435169689Skan;; This attribute gives the length suffix for a sign- or zero-extension 436169689Skan;; instruction. 437169689Skan(define_mode_attr size [(QI "b") (HI "h")]) 438169689Skan 439169689Skan;; This attributes gives the mode mask of a SHORT. 440169689Skan(define_mode_attr mask [(QI "0x00ff") (HI "0xffff")]) 441169689Skan 442169689Skan;; Mode attributes for GPR loads and stores. 443169689Skan(define_mode_attr load [(SI "lw") (DI "ld")]) 444169689Skan(define_mode_attr store [(SI "sw") (DI "sd")]) 445169689Skan 446169689Skan;; Similarly for MIPS IV indexed FPR loads and stores. 447169689Skan(define_mode_attr loadx [(SF "lwxc1") (DF "ldxc1") (V2SF "ldxc1")]) 448169689Skan(define_mode_attr storex [(SF "swxc1") (DF "sdxc1") (V2SF "sdxc1")]) 449169689Skan 450169689Skan;; The unextended ranges of the MIPS16 addiu and daddiu instructions 451169689Skan;; are different. Some forms of unextended addiu have an 8-bit immediate 452169689Skan;; field but the equivalent daddiu has only a 5-bit field. 453169689Skan(define_mode_attr si8_di5 [(SI "8") (DI "5")]) 454169689Skan 455169689Skan;; This attribute gives the best constraint to use for registers of 456169689Skan;; a given mode. 457169689Skan(define_mode_attr reg [(SI "d") (DI "d") (CC "z")]) 458169689Skan 459169689Skan;; This attribute gives the format suffix for floating-point operations. 460169689Skan(define_mode_attr fmt [(SF "s") (DF "d") (V2SF "ps")]) 461169689Skan 462169689Skan;; This attribute gives the upper-case mode name for one unit of a 463169689Skan;; floating-point mode. 464169689Skan(define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF")]) 465169689Skan 466169689Skan;; This attribute works around the early SB-1 rev2 core "F2" erratum: 467169689Skan;; 468169689Skan;; In certain cases, div.s and div.ps may have a rounding error 469169689Skan;; and/or wrong inexact flag. 470169689Skan;; 471169689Skan;; Therefore, we only allow div.s if not working around SB-1 rev2 472169689Skan;; errata or if a slight loss of precision is OK. 473169689Skan(define_mode_attr divide_condition 474169689Skan [DF (SF "!TARGET_FIX_SB1 || flag_unsafe_math_optimizations") 475169689Skan (V2SF "TARGET_SB1 && (!TARGET_FIX_SB1 || flag_unsafe_math_optimizations)")]) 476169689Skan 477169689Skan; This attribute gives the condition for which sqrt instructions exist. 478169689Skan(define_mode_attr sqrt_condition 479169689Skan [(SF "!ISA_MIPS1") (DF "!ISA_MIPS1") (V2SF "TARGET_SB1")]) 480169689Skan 481169689Skan; This attribute gives the condition for which recip and rsqrt instructions 482169689Skan; exist. 483169689Skan(define_mode_attr recip_condition 484169689Skan [(SF "ISA_HAS_FP4") (DF "ISA_HAS_FP4") (V2SF "TARGET_SB1")]) 485169689Skan 486169689Skan;; This code macro allows all branch instructions to be generated from 487169689Skan;; a single define_expand template. 488169689Skan(define_code_macro any_cond [unordered ordered unlt unge uneq ltgt unle ungt 489169689Skan eq ne gt ge lt le gtu geu ltu leu]) 490169689Skan 491169689Skan;; This code macro allows signed and unsigned widening multiplications 492169689Skan;; to use the same template. 493169689Skan(define_code_macro any_extend [sign_extend zero_extend]) 494169689Skan 495169689Skan;; This code macro allows the three shift instructions to be generated 496169689Skan;; from the same template. 497169689Skan(define_code_macro any_shift [ashift ashiftrt lshiftrt]) 498169689Skan 499169689Skan;; This code macro allows all native floating-point comparisons to be 500169689Skan;; generated from the same template. 501169689Skan(define_code_macro fcond [unordered uneq unlt unle eq lt le]) 502169689Skan 503169689Skan;; This code macro is used for comparisons that can be implemented 504169689Skan;; by swapping the operands. 505169689Skan(define_code_macro swapped_fcond [ge gt unge ungt]) 506169689Skan 507169689Skan;; <u> expands to an empty string when doing a signed operation and 508169689Skan;; "u" when doing an unsigned operation. 509169689Skan(define_code_attr u [(sign_extend "") (zero_extend "u")]) 510169689Skan 511169689Skan;; <su> is like <u>, but the signed form expands to "s" rather than "". 512169689Skan(define_code_attr su [(sign_extend "s") (zero_extend "u")]) 513169689Skan 514169689Skan;; <optab> expands to the name of the optab for a particular code. 515169689Skan(define_code_attr optab [(ashift "ashl") 516169689Skan (ashiftrt "ashr") 517169689Skan (lshiftrt "lshr")]) 518169689Skan 519169689Skan;; <insn> expands to the name of the insn that implements a particular code. 520169689Skan(define_code_attr insn [(ashift "sll") 521169689Skan (ashiftrt "sra") 522169689Skan (lshiftrt "srl")]) 523169689Skan 524169689Skan;; <fcond> is the c.cond.fmt condition associated with a particular code. 525169689Skan(define_code_attr fcond [(unordered "un") 526169689Skan (uneq "ueq") 527169689Skan (unlt "ult") 528169689Skan (unle "ule") 529169689Skan (eq "eq") 530169689Skan (lt "lt") 531169689Skan (le "le")]) 532169689Skan 533169689Skan;; Similar, but for swapped conditions. 534169689Skan(define_code_attr swapped_fcond [(ge "le") 535169689Skan (gt "lt") 536169689Skan (unge "ule") 537169689Skan (ungt "ult")]) 538169689Skan 539169689Skan;; ......................... 540169689Skan;; 541169689Skan;; Branch, call and jump delay slots 542169689Skan;; 543169689Skan;; ......................... 544169689Skan 545169689Skan(define_delay (and (eq_attr "type" "branch") 546169689Skan (eq (symbol_ref "TARGET_MIPS16") (const_int 0))) 547169689Skan [(eq_attr "can_delay" "yes") 548169689Skan (nil) 549169689Skan (and (eq_attr "branch_likely" "yes") 550169689Skan (eq_attr "can_delay" "yes"))]) 551169689Skan 552169689Skan(define_delay (eq_attr "type" "jump") 553169689Skan [(eq_attr "can_delay" "yes") 554169689Skan (nil) 555169689Skan (nil)]) 556169689Skan 557169689Skan(define_delay (and (eq_attr "type" "call") 558169689Skan (eq_attr "jal_macro" "no")) 559169689Skan [(eq_attr "can_delay" "yes") 560169689Skan (nil) 561169689Skan (nil)]) 562169689Skan 563169689Skan;; Pipeline descriptions. 564169689Skan;; 565169689Skan;; generic.md provides a fallback for processors without a specific 566169689Skan;; pipeline description. It is derived from the old define_function_unit 567169689Skan;; version and uses the "alu" and "imuldiv" units declared below. 568169689Skan;; 569169689Skan;; Some of the processor-specific files are also derived from old 570169689Skan;; define_function_unit descriptions and simply override the parts of 571169689Skan;; generic.md that don't apply. The other processor-specific files 572169689Skan;; are self-contained. 573169689Skan(define_automaton "alu,imuldiv") 574169689Skan 575169689Skan(define_cpu_unit "alu" "alu") 576169689Skan(define_cpu_unit "imuldiv" "imuldiv") 577169689Skan 578169689Skan(include "4k.md") 579169689Skan(include "5k.md") 580169689Skan(include "24k.md") 581169689Skan(include "3000.md") 582169689Skan(include "4000.md") 583169689Skan(include "4100.md") 584169689Skan(include "4130.md") 585169689Skan(include "4300.md") 586169689Skan(include "4600.md") 587169689Skan(include "5000.md") 588169689Skan(include "5400.md") 589169689Skan(include "5500.md") 590169689Skan(include "6000.md") 591169689Skan(include "7000.md") 592169689Skan(include "9000.md") 593169689Skan(include "sb1.md") 594169689Skan(include "sr71k.md") 595169689Skan(include "generic.md") 596169689Skan 597169689Skan;; 598169689Skan;; .................... 599169689Skan;; 600169689Skan;; CONDITIONAL TRAPS 601169689Skan;; 602169689Skan;; .................... 603169689Skan;; 604169689Skan 605169689Skan(define_insn "trap" 606169689Skan [(trap_if (const_int 1) (const_int 0))] 607169689Skan "" 608169689Skan{ 609169689Skan if (ISA_HAS_COND_TRAP) 610169689Skan return "teq\t$0,$0"; 611169689Skan else if (TARGET_MIPS16) 612169689Skan return "break 0"; 613169689Skan else 614169689Skan return "break"; 615169689Skan} 616169689Skan [(set_attr "type" "trap")]) 617169689Skan 618169689Skan(define_expand "conditional_trap" 619169689Skan [(trap_if (match_operator 0 "comparison_operator" 620169689Skan [(match_dup 2) (match_dup 3)]) 621169689Skan (match_operand 1 "const_int_operand"))] 622169689Skan "ISA_HAS_COND_TRAP" 623169689Skan{ 624169689Skan if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) == MODE_INT 625169689Skan && operands[1] == const0_rtx) 626169689Skan { 627169689Skan mips_gen_conditional_trap (operands); 628169689Skan DONE; 629169689Skan } 630169689Skan else 631169689Skan FAIL; 632169689Skan}) 633169689Skan 634169689Skan(define_insn "*conditional_trap<mode>" 635169689Skan [(trap_if (match_operator:GPR 0 "trap_comparison_operator" 636169689Skan [(match_operand:GPR 1 "reg_or_0_operand" "dJ") 637169689Skan (match_operand:GPR 2 "arith_operand" "dI")]) 638169689Skan (const_int 0))] 639169689Skan "ISA_HAS_COND_TRAP" 640169689Skan "t%C0\t%z1,%2" 641169689Skan [(set_attr "type" "trap")]) 642169689Skan 643169689Skan;; 644169689Skan;; .................... 645169689Skan;; 646169689Skan;; ADDITION 647169689Skan;; 648169689Skan;; .................... 649169689Skan;; 650169689Skan 651169689Skan(define_insn "add<mode>3" 652169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 653169689Skan (plus:ANYF (match_operand:ANYF 1 "register_operand" "f") 654169689Skan (match_operand:ANYF 2 "register_operand" "f")))] 655169689Skan "" 656169689Skan "add.<fmt>\t%0,%1,%2" 657169689Skan [(set_attr "type" "fadd") 658169689Skan (set_attr "mode" "<UNITMODE>")]) 659169689Skan 660169689Skan(define_expand "add<mode>3" 661169689Skan [(set (match_operand:GPR 0 "register_operand") 662169689Skan (plus:GPR (match_operand:GPR 1 "register_operand") 663169689Skan (match_operand:GPR 2 "arith_operand")))] 664169689Skan "") 665169689Skan 666169689Skan(define_insn "*add<mode>3" 667169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 668169689Skan (plus:GPR (match_operand:GPR 1 "register_operand" "d,d") 669169689Skan (match_operand:GPR 2 "arith_operand" "d,Q")))] 670169689Skan "!TARGET_MIPS16" 671169689Skan "@ 672169689Skan <d>addu\t%0,%1,%2 673169689Skan <d>addiu\t%0,%1,%2" 674169689Skan [(set_attr "type" "arith") 675169689Skan (set_attr "mode" "<MODE>")]) 676169689Skan 677169689Skan;; We need to recognize MIPS16 stack pointer additions explicitly, since 678169689Skan;; we don't have a constraint for $sp. These insns will be generated by 679169689Skan;; the save_restore_insns functions. 680169689Skan 681169689Skan(define_insn "*add<mode>3_sp1" 682169689Skan [(set (reg:GPR 29) 683169689Skan (plus:GPR (reg:GPR 29) 684169689Skan (match_operand:GPR 0 "const_arith_operand" "")))] 685169689Skan "TARGET_MIPS16" 686169689Skan "<d>addiu\t%$,%$,%0" 687169689Skan [(set_attr "type" "arith") 688169689Skan (set_attr "mode" "<MODE>") 689169689Skan (set (attr "length") (if_then_else (match_operand 0 "m16_simm8_8") 690169689Skan (const_int 4) 691169689Skan (const_int 8)))]) 692169689Skan 693169689Skan(define_insn "*add<mode>3_sp2" 694169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 695169689Skan (plus:GPR (reg:GPR 29) 696169689Skan (match_operand:GPR 1 "const_arith_operand" "")))] 697169689Skan "TARGET_MIPS16" 698169689Skan "<d>addiu\t%0,%$,%1" 699169689Skan [(set_attr "type" "arith") 700169689Skan (set_attr "mode" "<MODE>") 701169689Skan (set (attr "length") (if_then_else (match_operand 1 "m16_uimm<si8_di5>_4") 702169689Skan (const_int 4) 703169689Skan (const_int 8)))]) 704169689Skan 705169689Skan(define_insn "*add<mode>3_mips16" 706169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d,d") 707169689Skan (plus:GPR (match_operand:GPR 1 "register_operand" "0,d,d") 708169689Skan (match_operand:GPR 2 "arith_operand" "Q,O,d")))] 709169689Skan "TARGET_MIPS16" 710169689Skan "@ 711169689Skan <d>addiu\t%0,%2 712169689Skan <d>addiu\t%0,%1,%2 713169689Skan <d>addu\t%0,%1,%2" 714169689Skan [(set_attr "type" "arith") 715169689Skan (set_attr "mode" "<MODE>") 716169689Skan (set_attr_alternative "length" 717169689Skan [(if_then_else (match_operand 2 "m16_simm<si8_di5>_1") 718169689Skan (const_int 4) 719169689Skan (const_int 8)) 720169689Skan (if_then_else (match_operand 2 "m16_simm4_1") 721169689Skan (const_int 4) 722169689Skan (const_int 8)) 723169689Skan (const_int 4)])]) 724169689Skan 725169689Skan 726169689Skan;; On the mips16, we can sometimes split an add of a constant which is 727169689Skan;; a 4 byte instruction into two adds which are both 2 byte 728169689Skan;; instructions. There are two cases: one where we are adding a 729169689Skan;; constant plus a register to another register, and one where we are 730169689Skan;; simply adding a constant to a register. 731169689Skan 732169689Skan(define_split 733169689Skan [(set (match_operand:SI 0 "register_operand") 734169689Skan (plus:SI (match_dup 0) 735169689Skan (match_operand:SI 1 "const_int_operand")))] 736169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 737169689Skan && REG_P (operands[0]) 738169689Skan && M16_REG_P (REGNO (operands[0])) 739169689Skan && GET_CODE (operands[1]) == CONST_INT 740169689Skan && ((INTVAL (operands[1]) > 0x7f 741169689Skan && INTVAL (operands[1]) <= 0x7f + 0x7f) 742169689Skan || (INTVAL (operands[1]) < - 0x80 743169689Skan && INTVAL (operands[1]) >= - 0x80 - 0x80))" 744169689Skan [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) 745169689Skan (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] 746169689Skan{ 747169689Skan HOST_WIDE_INT val = INTVAL (operands[1]); 748169689Skan 749169689Skan if (val >= 0) 750169689Skan { 751169689Skan operands[1] = GEN_INT (0x7f); 752169689Skan operands[2] = GEN_INT (val - 0x7f); 753169689Skan } 754169689Skan else 755169689Skan { 756169689Skan operands[1] = GEN_INT (- 0x80); 757169689Skan operands[2] = GEN_INT (val + 0x80); 758169689Skan } 759169689Skan}) 760169689Skan 761169689Skan(define_split 762169689Skan [(set (match_operand:SI 0 "register_operand") 763169689Skan (plus:SI (match_operand:SI 1 "register_operand") 764169689Skan (match_operand:SI 2 "const_int_operand")))] 765169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 766169689Skan && REG_P (operands[0]) 767169689Skan && M16_REG_P (REGNO (operands[0])) 768169689Skan && REG_P (operands[1]) 769169689Skan && M16_REG_P (REGNO (operands[1])) 770169689Skan && REGNO (operands[0]) != REGNO (operands[1]) 771169689Skan && GET_CODE (operands[2]) == CONST_INT 772169689Skan && ((INTVAL (operands[2]) > 0x7 773169689Skan && INTVAL (operands[2]) <= 0x7 + 0x7f) 774169689Skan || (INTVAL (operands[2]) < - 0x8 775169689Skan && INTVAL (operands[2]) >= - 0x8 - 0x80))" 776169689Skan [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) 777169689Skan (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] 778169689Skan{ 779169689Skan HOST_WIDE_INT val = INTVAL (operands[2]); 780169689Skan 781169689Skan if (val >= 0) 782169689Skan { 783169689Skan operands[2] = GEN_INT (0x7); 784169689Skan operands[3] = GEN_INT (val - 0x7); 785169689Skan } 786169689Skan else 787169689Skan { 788169689Skan operands[2] = GEN_INT (- 0x8); 789169689Skan operands[3] = GEN_INT (val + 0x8); 790169689Skan } 791169689Skan}) 792169689Skan 793169689Skan(define_split 794169689Skan [(set (match_operand:DI 0 "register_operand") 795169689Skan (plus:DI (match_dup 0) 796169689Skan (match_operand:DI 1 "const_int_operand")))] 797169689Skan "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE 798169689Skan && REG_P (operands[0]) 799169689Skan && M16_REG_P (REGNO (operands[0])) 800169689Skan && GET_CODE (operands[1]) == CONST_INT 801169689Skan && ((INTVAL (operands[1]) > 0xf 802169689Skan && INTVAL (operands[1]) <= 0xf + 0xf) 803169689Skan || (INTVAL (operands[1]) < - 0x10 804169689Skan && INTVAL (operands[1]) >= - 0x10 - 0x10))" 805169689Skan [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) 806169689Skan (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))] 807169689Skan{ 808169689Skan HOST_WIDE_INT val = INTVAL (operands[1]); 809169689Skan 810169689Skan if (val >= 0) 811169689Skan { 812169689Skan operands[1] = GEN_INT (0xf); 813169689Skan operands[2] = GEN_INT (val - 0xf); 814169689Skan } 815169689Skan else 816169689Skan { 817169689Skan operands[1] = GEN_INT (- 0x10); 818169689Skan operands[2] = GEN_INT (val + 0x10); 819169689Skan } 820169689Skan}) 821169689Skan 822169689Skan(define_split 823169689Skan [(set (match_operand:DI 0 "register_operand") 824169689Skan (plus:DI (match_operand:DI 1 "register_operand") 825169689Skan (match_operand:DI 2 "const_int_operand")))] 826169689Skan "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE 827169689Skan && REG_P (operands[0]) 828169689Skan && M16_REG_P (REGNO (operands[0])) 829169689Skan && REG_P (operands[1]) 830169689Skan && M16_REG_P (REGNO (operands[1])) 831169689Skan && REGNO (operands[0]) != REGNO (operands[1]) 832169689Skan && GET_CODE (operands[2]) == CONST_INT 833169689Skan && ((INTVAL (operands[2]) > 0x7 834169689Skan && INTVAL (operands[2]) <= 0x7 + 0xf) 835169689Skan || (INTVAL (operands[2]) < - 0x8 836169689Skan && INTVAL (operands[2]) >= - 0x8 - 0x10))" 837169689Skan [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2))) 838169689Skan (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] 839169689Skan{ 840169689Skan HOST_WIDE_INT val = INTVAL (operands[2]); 841169689Skan 842169689Skan if (val >= 0) 843169689Skan { 844169689Skan operands[2] = GEN_INT (0x7); 845169689Skan operands[3] = GEN_INT (val - 0x7); 846169689Skan } 847169689Skan else 848169689Skan { 849169689Skan operands[2] = GEN_INT (- 0x8); 850169689Skan operands[3] = GEN_INT (val + 0x8); 851169689Skan } 852169689Skan}) 853169689Skan 854169689Skan(define_insn "*addsi3_extended" 855169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 856169689Skan (sign_extend:DI 857169689Skan (plus:SI (match_operand:SI 1 "register_operand" "d,d") 858169689Skan (match_operand:SI 2 "arith_operand" "d,Q"))))] 859169689Skan "TARGET_64BIT && !TARGET_MIPS16" 860169689Skan "@ 861169689Skan addu\t%0,%1,%2 862169689Skan addiu\t%0,%1,%2" 863169689Skan [(set_attr "type" "arith") 864169689Skan (set_attr "mode" "SI")]) 865169689Skan 866169689Skan;; Split this insn so that the addiu splitters can have a crack at it. 867169689Skan;; Use a conservative length estimate until the split. 868169689Skan(define_insn_and_split "*addsi3_extended_mips16" 869169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d,d") 870169689Skan (sign_extend:DI 871169689Skan (plus:SI (match_operand:SI 1 "register_operand" "0,d,d") 872169689Skan (match_operand:SI 2 "arith_operand" "Q,O,d"))))] 873169689Skan "TARGET_64BIT && TARGET_MIPS16" 874169689Skan "#" 875169689Skan "&& reload_completed" 876169689Skan [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))] 877169689Skan { operands[3] = gen_lowpart (SImode, operands[0]); } 878169689Skan [(set_attr "type" "arith") 879169689Skan (set_attr "mode" "SI") 880169689Skan (set_attr "extended_mips16" "yes")]) 881169689Skan 882169689Skan;; 883169689Skan;; .................... 884169689Skan;; 885169689Skan;; SUBTRACTION 886169689Skan;; 887169689Skan;; .................... 888169689Skan;; 889169689Skan 890169689Skan(define_insn "sub<mode>3" 891169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 892169689Skan (minus:ANYF (match_operand:ANYF 1 "register_operand" "f") 893169689Skan (match_operand:ANYF 2 "register_operand" "f")))] 894169689Skan "" 895169689Skan "sub.<fmt>\t%0,%1,%2" 896169689Skan [(set_attr "type" "fadd") 897169689Skan (set_attr "mode" "<UNITMODE>")]) 898169689Skan 899169689Skan(define_insn "sub<mode>3" 900169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 901169689Skan (minus:GPR (match_operand:GPR 1 "register_operand" "d") 902169689Skan (match_operand:GPR 2 "register_operand" "d")))] 903169689Skan "" 904169689Skan "<d>subu\t%0,%1,%2" 905169689Skan [(set_attr "type" "arith") 906169689Skan (set_attr "mode" "<MODE>")]) 907169689Skan 908169689Skan(define_insn "*subsi3_extended" 909169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 910169689Skan (sign_extend:DI 911169689Skan (minus:SI (match_operand:SI 1 "register_operand" "d") 912169689Skan (match_operand:SI 2 "register_operand" "d"))))] 913169689Skan "TARGET_64BIT" 914169689Skan "subu\t%0,%1,%2" 915169689Skan [(set_attr "type" "arith") 916169689Skan (set_attr "mode" "DI")]) 917169689Skan 918169689Skan;; 919169689Skan;; .................... 920169689Skan;; 921169689Skan;; MULTIPLICATION 922169689Skan;; 923169689Skan;; .................... 924169689Skan;; 925169689Skan 926169689Skan(define_expand "mul<mode>3" 927169689Skan [(set (match_operand:SCALARF 0 "register_operand") 928169689Skan (mult:SCALARF (match_operand:SCALARF 1 "register_operand") 929169689Skan (match_operand:SCALARF 2 "register_operand")))] 930169689Skan "" 931169689Skan "") 932169689Skan 933169689Skan(define_insn "*mul<mode>3" 934169689Skan [(set (match_operand:SCALARF 0 "register_operand" "=f") 935169689Skan (mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f") 936169689Skan (match_operand:SCALARF 2 "register_operand" "f")))] 937169689Skan "!TARGET_4300_MUL_FIX" 938169689Skan "mul.<fmt>\t%0,%1,%2" 939169689Skan [(set_attr "type" "fmul") 940169689Skan (set_attr "mode" "<MODE>")]) 941169689Skan 942169689Skan;; Early VR4300 silicon has a CPU bug where multiplies with certain 943169689Skan;; operands may corrupt immediately following multiplies. This is a 944169689Skan;; simple fix to insert NOPs. 945169689Skan 946169689Skan(define_insn "*mul<mode>3_r4300" 947169689Skan [(set (match_operand:SCALARF 0 "register_operand" "=f") 948169689Skan (mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f") 949169689Skan (match_operand:SCALARF 2 "register_operand" "f")))] 950169689Skan "TARGET_4300_MUL_FIX" 951169689Skan "mul.<fmt>\t%0,%1,%2\;nop" 952169689Skan [(set_attr "type" "fmul") 953169689Skan (set_attr "mode" "<MODE>") 954169689Skan (set_attr "length" "8")]) 955169689Skan 956169689Skan(define_insn "mulv2sf3" 957169689Skan [(set (match_operand:V2SF 0 "register_operand" "=f") 958169689Skan (mult:V2SF (match_operand:V2SF 1 "register_operand" "f") 959169689Skan (match_operand:V2SF 2 "register_operand" "f")))] 960169689Skan "TARGET_PAIRED_SINGLE_FLOAT" 961169689Skan "mul.ps\t%0,%1,%2" 962169689Skan [(set_attr "type" "fmul") 963169689Skan (set_attr "mode" "SF")]) 964169689Skan 965169689Skan;; The original R4000 has a cpu bug. If a double-word or a variable 966169689Skan;; shift executes while an integer multiplication is in progress, the 967169689Skan;; shift may give an incorrect result. Avoid this by keeping the mflo 968169689Skan;; with the mult on the R4000. 969169689Skan;; 970169689Skan;; From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0" 971169689Skan;; (also valid for MIPS R4000MC processors): 972169689Skan;; 973169689Skan;; "16. R4000PC, R4000SC: Please refer to errata 28 for an update to 974169689Skan;; this errata description. 975169689Skan;; The following code sequence causes the R4000 to incorrectly 976169689Skan;; execute the Double Shift Right Arithmetic 32 (dsra32) 977169689Skan;; instruction. If the dsra32 instruction is executed during an 978169689Skan;; integer multiply, the dsra32 will only shift by the amount in 979169689Skan;; specified in the instruction rather than the amount plus 32 980169689Skan;; bits. 981169689Skan;; instruction 1: mult rs,rt integer multiply 982169689Skan;; instruction 2-12: dsra32 rd,rt,rs doubleword shift 983169689Skan;; right arithmetic + 32 984169689Skan;; Workaround: A dsra32 instruction placed after an integer 985169689Skan;; multiply should not be one of the 11 instructions after the 986169689Skan;; multiply instruction." 987169689Skan;; 988169689Skan;; and: 989169689Skan;; 990169689Skan;; "28. R4000PC, R4000SC: The text from errata 16 should be replaced by 991169689Skan;; the following description. 992169689Skan;; All extended shifts (shift by n+32) and variable shifts (32 and 993169689Skan;; 64-bit versions) may produce incorrect results under the 994169689Skan;; following conditions: 995169689Skan;; 1) An integer multiply is currently executing 996169689Skan;; 2) These types of shift instructions are executed immediately 997169689Skan;; following an integer divide instruction. 998169689Skan;; Workaround: 999169689Skan;; 1) Make sure no integer multiply is running wihen these 1000169689Skan;; instruction are executed. If this cannot be predicted at 1001169689Skan;; compile time, then insert a "mfhi" to R0 instruction 1002169689Skan;; immediately after the integer multiply instruction. This 1003169689Skan;; will cause the integer multiply to complete before the shift 1004169689Skan;; is executed. 1005169689Skan;; 2) Separate integer divide and these two classes of shift 1006169689Skan;; instructions by another instruction or a noop." 1007169689Skan;; 1008169689Skan;; These processors have PRId values of 0x00004220 and 0x00004300, 1009169689Skan;; respectively. 1010169689Skan 1011169689Skan(define_expand "mul<mode>3" 1012169689Skan [(set (match_operand:GPR 0 "register_operand") 1013169689Skan (mult:GPR (match_operand:GPR 1 "register_operand") 1014169689Skan (match_operand:GPR 2 "register_operand")))] 1015169689Skan "" 1016169689Skan{ 1017169689Skan if (GENERATE_MULT3_<MODE>) 1018169689Skan emit_insn (gen_mul<mode>3_mult3 (operands[0], operands[1], operands[2])); 1019169689Skan else if (!TARGET_FIX_R4000) 1020169689Skan emit_insn (gen_mul<mode>3_internal (operands[0], operands[1], 1021169689Skan operands[2])); 1022169689Skan else 1023169689Skan emit_insn (gen_mul<mode>3_r4000 (operands[0], operands[1], operands[2])); 1024169689Skan DONE; 1025169689Skan}) 1026169689Skan 1027169689Skan(define_insn "mulsi3_mult3" 1028169689Skan [(set (match_operand:SI 0 "register_operand" "=d,l") 1029169689Skan (mult:SI (match_operand:SI 1 "register_operand" "d,d") 1030169689Skan (match_operand:SI 2 "register_operand" "d,d"))) 1031169689Skan (clobber (match_scratch:SI 3 "=h,h")) 1032169689Skan (clobber (match_scratch:SI 4 "=l,X"))] 1033169689Skan "GENERATE_MULT3_SI" 1034169689Skan{ 1035169689Skan if (which_alternative == 1) 1036169689Skan return "mult\t%1,%2"; 1037169689Skan if (TARGET_MAD 1038169689Skan || TARGET_MIPS5400 1039169689Skan || TARGET_MIPS5500 1040169689Skan || TARGET_MIPS7000 1041169689Skan || TARGET_MIPS9000 1042169689Skan || ISA_MIPS32 1043169689Skan || ISA_MIPS32R2 1044208737Sjmallett || ISA_MIPS64 1045208737Sjmallett || ISA_MIPS64R2) 1046169689Skan return "mul\t%0,%1,%2"; 1047169689Skan return "mult\t%0,%1,%2"; 1048169689Skan} 1049169689Skan [(set_attr "type" "imul3,imul") 1050169689Skan (set_attr "mode" "SI")]) 1051169689Skan 1052169689Skan(define_insn "muldi3_mult3" 1053169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 1054169689Skan (mult:DI (match_operand:DI 1 "register_operand" "d") 1055169689Skan (match_operand:DI 2 "register_operand" "d"))) 1056169689Skan (clobber (match_scratch:DI 3 "=h")) 1057169689Skan (clobber (match_scratch:DI 4 "=l"))] 1058169689Skan "TARGET_64BIT && GENERATE_MULT3_DI" 1059169689Skan "dmult\t%0,%1,%2" 1060169689Skan [(set_attr "type" "imul3") 1061169689Skan (set_attr "mode" "DI")]) 1062169689Skan 1063169689Skan;; If a register gets allocated to LO, and we spill to memory, the reload 1064169689Skan;; will include a move from LO to a GPR. Merge it into the multiplication 1065169689Skan;; if it can set the GPR directly. 1066169689Skan;; 1067169689Skan;; Operand 0: LO 1068169689Skan;; Operand 1: GPR (1st multiplication operand) 1069169689Skan;; Operand 2: GPR (2nd multiplication operand) 1070169689Skan;; Operand 3: HI 1071169689Skan;; Operand 4: GPR (destination) 1072169689Skan(define_peephole2 1073169689Skan [(parallel 1074169689Skan [(set (match_operand:SI 0 "register_operand") 1075169689Skan (mult:SI (match_operand:SI 1 "register_operand") 1076169689Skan (match_operand:SI 2 "register_operand"))) 1077169689Skan (clobber (match_operand:SI 3 "register_operand")) 1078169689Skan (clobber (scratch:SI))]) 1079169689Skan (set (match_operand:SI 4 "register_operand") 1080169689Skan (unspec [(match_dup 0) (match_dup 3)] UNSPEC_MFHILO))] 1081169689Skan "GENERATE_MULT3_SI && peep2_reg_dead_p (2, operands[0])" 1082169689Skan [(parallel 1083169689Skan [(set (match_dup 4) 1084169689Skan (mult:SI (match_dup 1) 1085169689Skan (match_dup 2))) 1086169689Skan (clobber (match_dup 3)) 1087169689Skan (clobber (match_dup 0))])]) 1088169689Skan 1089169689Skan(define_insn "mul<mode>3_internal" 1090169689Skan [(set (match_operand:GPR 0 "register_operand" "=l") 1091169689Skan (mult:GPR (match_operand:GPR 1 "register_operand" "d") 1092169689Skan (match_operand:GPR 2 "register_operand" "d"))) 1093169689Skan (clobber (match_scratch:GPR 3 "=h"))] 1094169689Skan "!TARGET_FIX_R4000" 1095169689Skan "<d>mult\t%1,%2" 1096169689Skan [(set_attr "type" "imul") 1097169689Skan (set_attr "mode" "<MODE>")]) 1098169689Skan 1099169689Skan(define_insn "mul<mode>3_r4000" 1100169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 1101169689Skan (mult:GPR (match_operand:GPR 1 "register_operand" "d") 1102169689Skan (match_operand:GPR 2 "register_operand" "d"))) 1103169689Skan (clobber (match_scratch:GPR 3 "=h")) 1104169689Skan (clobber (match_scratch:GPR 4 "=l"))] 1105169689Skan "TARGET_FIX_R4000" 1106169689Skan "<d>mult\t%1,%2\;mflo\t%0" 1107169689Skan [(set_attr "type" "imul") 1108169689Skan (set_attr "mode" "<MODE>") 1109169689Skan (set_attr "length" "8")]) 1110169689Skan 1111169689Skan;; On the VR4120 and VR4130, it is better to use "mtlo $0; macc" instead 1112169689Skan;; of "mult; mflo". They have the same latency, but the first form gives 1113169689Skan;; us an extra cycle to compute the operands. 1114169689Skan 1115169689Skan;; Operand 0: LO 1116169689Skan;; Operand 1: GPR (1st multiplication operand) 1117169689Skan;; Operand 2: GPR (2nd multiplication operand) 1118169689Skan;; Operand 3: HI 1119169689Skan;; Operand 4: GPR (destination) 1120169689Skan(define_peephole2 1121169689Skan [(parallel 1122169689Skan [(set (match_operand:SI 0 "register_operand") 1123169689Skan (mult:SI (match_operand:SI 1 "register_operand") 1124169689Skan (match_operand:SI 2 "register_operand"))) 1125169689Skan (clobber (match_operand:SI 3 "register_operand"))]) 1126169689Skan (set (match_operand:SI 4 "register_operand") 1127169689Skan (unspec:SI [(match_dup 0) (match_dup 3)] UNSPEC_MFHILO))] 1128169689Skan "ISA_HAS_MACC && !GENERATE_MULT3_SI" 1129169689Skan [(set (match_dup 0) 1130169689Skan (const_int 0)) 1131169689Skan (parallel 1132169689Skan [(set (match_dup 0) 1133169689Skan (plus:SI (mult:SI (match_dup 1) 1134169689Skan (match_dup 2)) 1135169689Skan (match_dup 0))) 1136169689Skan (set (match_dup 4) 1137169689Skan (plus:SI (mult:SI (match_dup 1) 1138169689Skan (match_dup 2)) 1139169689Skan (match_dup 0))) 1140169689Skan (clobber (match_dup 3))])]) 1141169689Skan 1142169689Skan;; Multiply-accumulate patterns 1143169689Skan 1144169689Skan;; For processors that can copy the output to a general register: 1145169689Skan;; 1146169689Skan;; The all-d alternative is needed because the combiner will find this 1147169689Skan;; pattern and then register alloc/reload will move registers around to 1148169689Skan;; make them fit, and we don't want to trigger unnecessary loads to LO. 1149169689Skan;; 1150169689Skan;; The last alternative should be made slightly less desirable, but adding 1151169689Skan;; "?" to the constraint is too strong, and causes values to be loaded into 1152169689Skan;; LO even when that's more costly. For now, using "*d" mostly does the 1153169689Skan;; trick. 1154169689Skan(define_insn "*mul_acc_si" 1155169689Skan [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") 1156169689Skan (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d") 1157169689Skan (match_operand:SI 2 "register_operand" "d,d,d")) 1158169689Skan (match_operand:SI 3 "register_operand" "0,l,*d"))) 1159169689Skan (clobber (match_scratch:SI 4 "=h,h,h")) 1160169689Skan (clobber (match_scratch:SI 5 "=X,3,l")) 1161169689Skan (clobber (match_scratch:SI 6 "=X,X,&d"))] 1162169689Skan "(TARGET_MIPS3900 1163169689Skan || ISA_HAS_MADD_MSUB) 1164169689Skan && !TARGET_MIPS16" 1165169689Skan{ 1166169689Skan static const char *const madd[] = { "madd\t%1,%2", "madd\t%0,%1,%2" }; 1167169689Skan if (which_alternative == 2) 1168169689Skan return "#"; 1169169689Skan if (ISA_HAS_MADD_MSUB && which_alternative != 0) 1170169689Skan return "#"; 1171169689Skan return madd[which_alternative]; 1172169689Skan} 1173169689Skan [(set_attr "type" "imadd,imadd,multi") 1174169689Skan (set_attr "mode" "SI") 1175169689Skan (set_attr "length" "4,4,8")]) 1176169689Skan 1177169689Skan;; Split the above insn if we failed to get LO allocated. 1178169689Skan(define_split 1179169689Skan [(set (match_operand:SI 0 "register_operand") 1180169689Skan (plus:SI (mult:SI (match_operand:SI 1 "register_operand") 1181169689Skan (match_operand:SI 2 "register_operand")) 1182169689Skan (match_operand:SI 3 "register_operand"))) 1183169689Skan (clobber (match_scratch:SI 4)) 1184169689Skan (clobber (match_scratch:SI 5)) 1185169689Skan (clobber (match_scratch:SI 6))] 1186169689Skan "reload_completed && !TARGET_DEBUG_D_MODE 1187169689Skan && GP_REG_P (true_regnum (operands[0])) 1188169689Skan && GP_REG_P (true_regnum (operands[3]))" 1189169689Skan [(parallel [(set (match_dup 6) 1190169689Skan (mult:SI (match_dup 1) (match_dup 2))) 1191169689Skan (clobber (match_dup 4)) 1192169689Skan (clobber (match_dup 5))]) 1193169689Skan (set (match_dup 0) (plus:SI (match_dup 6) (match_dup 3)))] 1194169689Skan "") 1195169689Skan 1196169689Skan;; Splitter to copy result of MADD to a general register 1197169689Skan(define_split 1198169689Skan [(set (match_operand:SI 0 "register_operand") 1199169689Skan (plus:SI (mult:SI (match_operand:SI 1 "register_operand") 1200169689Skan (match_operand:SI 2 "register_operand")) 1201169689Skan (match_operand:SI 3 "register_operand"))) 1202169689Skan (clobber (match_scratch:SI 4)) 1203169689Skan (clobber (match_scratch:SI 5)) 1204169689Skan (clobber (match_scratch:SI 6))] 1205169689Skan "reload_completed && !TARGET_DEBUG_D_MODE 1206169689Skan && GP_REG_P (true_regnum (operands[0])) 1207169689Skan && true_regnum (operands[3]) == LO_REGNUM" 1208169689Skan [(parallel [(set (match_dup 3) 1209169689Skan (plus:SI (mult:SI (match_dup 1) (match_dup 2)) 1210169689Skan (match_dup 3))) 1211169689Skan (clobber (match_dup 4)) 1212169689Skan (clobber (match_dup 5)) 1213169689Skan (clobber (match_dup 6))]) 1214169689Skan (set (match_dup 0) (unspec:SI [(match_dup 5) (match_dup 4)] UNSPEC_MFHILO))] 1215169689Skan "") 1216169689Skan 1217169689Skan(define_insn "*macc" 1218169689Skan [(set (match_operand:SI 0 "register_operand" "=l,d") 1219169689Skan (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") 1220169689Skan (match_operand:SI 2 "register_operand" "d,d")) 1221169689Skan (match_operand:SI 3 "register_operand" "0,l"))) 1222169689Skan (clobber (match_scratch:SI 4 "=h,h")) 1223169689Skan (clobber (match_scratch:SI 5 "=X,3"))] 1224169689Skan "ISA_HAS_MACC" 1225169689Skan{ 1226169689Skan if (which_alternative == 1) 1227169689Skan return "macc\t%0,%1,%2"; 1228169689Skan else if (TARGET_MIPS5500) 1229169689Skan return "madd\t%1,%2"; 1230169689Skan else 1231169689Skan /* The VR4130 assumes that there is a two-cycle latency between a macc 1232169689Skan that "writes" to $0 and an instruction that reads from it. We avoid 1233169689Skan this by assigning to $1 instead. */ 1234169689Skan return "%[macc\t%@,%1,%2%]"; 1235169689Skan} 1236169689Skan [(set_attr "type" "imadd") 1237169689Skan (set_attr "mode" "SI")]) 1238169689Skan 1239169689Skan(define_insn "*msac" 1240169689Skan [(set (match_operand:SI 0 "register_operand" "=l,d") 1241169689Skan (minus:SI (match_operand:SI 1 "register_operand" "0,l") 1242169689Skan (mult:SI (match_operand:SI 2 "register_operand" "d,d") 1243169689Skan (match_operand:SI 3 "register_operand" "d,d")))) 1244169689Skan (clobber (match_scratch:SI 4 "=h,h")) 1245169689Skan (clobber (match_scratch:SI 5 "=X,1"))] 1246169689Skan "ISA_HAS_MSAC" 1247169689Skan{ 1248169689Skan if (which_alternative == 1) 1249169689Skan return "msac\t%0,%2,%3"; 1250169689Skan else if (TARGET_MIPS5500) 1251169689Skan return "msub\t%2,%3"; 1252169689Skan else 1253169689Skan return "msac\t$0,%2,%3"; 1254169689Skan} 1255169689Skan [(set_attr "type" "imadd") 1256169689Skan (set_attr "mode" "SI")]) 1257169689Skan 1258169689Skan;; An msac-like instruction implemented using negation and a macc. 1259169689Skan(define_insn_and_split "*msac_using_macc" 1260169689Skan [(set (match_operand:SI 0 "register_operand" "=l,d") 1261169689Skan (minus:SI (match_operand:SI 1 "register_operand" "0,l") 1262169689Skan (mult:SI (match_operand:SI 2 "register_operand" "d,d") 1263169689Skan (match_operand:SI 3 "register_operand" "d,d")))) 1264169689Skan (clobber (match_scratch:SI 4 "=h,h")) 1265169689Skan (clobber (match_scratch:SI 5 "=X,1")) 1266169689Skan (clobber (match_scratch:SI 6 "=d,d"))] 1267169689Skan "ISA_HAS_MACC && !ISA_HAS_MSAC" 1268169689Skan "#" 1269169689Skan "&& reload_completed" 1270169689Skan [(set (match_dup 6) 1271169689Skan (neg:SI (match_dup 3))) 1272169689Skan (parallel 1273169689Skan [(set (match_dup 0) 1274169689Skan (plus:SI (mult:SI (match_dup 2) 1275169689Skan (match_dup 6)) 1276169689Skan (match_dup 1))) 1277169689Skan (clobber (match_dup 4)) 1278169689Skan (clobber (match_dup 5))])] 1279169689Skan "" 1280169689Skan [(set_attr "type" "imadd") 1281169689Skan (set_attr "length" "8")]) 1282169689Skan 1283169689Skan;; Patterns generated by the define_peephole2 below. 1284169689Skan 1285169689Skan(define_insn "*macc2" 1286169689Skan [(set (match_operand:SI 0 "register_operand" "=l") 1287169689Skan (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d") 1288169689Skan (match_operand:SI 2 "register_operand" "d")) 1289169689Skan (match_dup 0))) 1290169689Skan (set (match_operand:SI 3 "register_operand" "=d") 1291169689Skan (plus:SI (mult:SI (match_dup 1) 1292169689Skan (match_dup 2)) 1293169689Skan (match_dup 0))) 1294169689Skan (clobber (match_scratch:SI 4 "=h"))] 1295169689Skan "ISA_HAS_MACC && reload_completed" 1296169689Skan "macc\t%3,%1,%2" 1297169689Skan [(set_attr "type" "imadd") 1298169689Skan (set_attr "mode" "SI")]) 1299169689Skan 1300169689Skan(define_insn "*msac2" 1301169689Skan [(set (match_operand:SI 0 "register_operand" "=l") 1302169689Skan (minus:SI (match_dup 0) 1303169689Skan (mult:SI (match_operand:SI 1 "register_operand" "d") 1304169689Skan (match_operand:SI 2 "register_operand" "d")))) 1305169689Skan (set (match_operand:SI 3 "register_operand" "=d") 1306169689Skan (minus:SI (match_dup 0) 1307169689Skan (mult:SI (match_dup 1) 1308169689Skan (match_dup 2)))) 1309169689Skan (clobber (match_scratch:SI 4 "=h"))] 1310169689Skan "ISA_HAS_MSAC && reload_completed" 1311169689Skan "msac\t%3,%1,%2" 1312169689Skan [(set_attr "type" "imadd") 1313169689Skan (set_attr "mode" "SI")]) 1314169689Skan 1315169689Skan;; Convert macc $0,<r1>,<r2> & mflo <r3> into macc <r3>,<r1>,<r2> 1316169689Skan;; Similarly msac. 1317169689Skan;; 1318169689Skan;; Operand 0: LO 1319169689Skan;; Operand 1: macc/msac 1320169689Skan;; Operand 2: HI 1321169689Skan;; Operand 3: GPR (destination) 1322169689Skan(define_peephole2 1323169689Skan [(parallel 1324169689Skan [(set (match_operand:SI 0 "register_operand") 1325169689Skan (match_operand:SI 1 "macc_msac_operand")) 1326169689Skan (clobber (match_operand:SI 2 "register_operand")) 1327169689Skan (clobber (scratch:SI))]) 1328169689Skan (set (match_operand:SI 3 "register_operand") 1329169689Skan (unspec:SI [(match_dup 0) (match_dup 2)] UNSPEC_MFHILO))] 1330169689Skan "" 1331169689Skan [(parallel [(set (match_dup 0) 1332169689Skan (match_dup 1)) 1333169689Skan (set (match_dup 3) 1334169689Skan (match_dup 1)) 1335169689Skan (clobber (match_dup 2))])] 1336169689Skan "") 1337169689Skan 1338169689Skan;; When we have a three-address multiplication instruction, it should 1339169689Skan;; be faster to do a separate multiply and add, rather than moving 1340169689Skan;; something into LO in order to use a macc instruction. 1341169689Skan;; 1342169689Skan;; This peephole needs a scratch register to cater for the case when one 1343169689Skan;; of the multiplication operands is the same as the destination. 1344169689Skan;; 1345169689Skan;; Operand 0: GPR (scratch) 1346169689Skan;; Operand 1: LO 1347169689Skan;; Operand 2: GPR (addend) 1348169689Skan;; Operand 3: GPR (destination) 1349169689Skan;; Operand 4: macc/msac 1350169689Skan;; Operand 5: HI 1351169689Skan;; Operand 6: new multiplication 1352169689Skan;; Operand 7: new addition/subtraction 1353169689Skan(define_peephole2 1354169689Skan [(match_scratch:SI 0 "d") 1355169689Skan (set (match_operand:SI 1 "register_operand") 1356169689Skan (match_operand:SI 2 "register_operand")) 1357169689Skan (match_dup 0) 1358169689Skan (parallel 1359169689Skan [(set (match_operand:SI 3 "register_operand") 1360169689Skan (match_operand:SI 4 "macc_msac_operand")) 1361169689Skan (clobber (match_operand:SI 5 "register_operand")) 1362169689Skan (clobber (match_dup 1))])] 1363169689Skan "GENERATE_MULT3_SI 1364169689Skan && true_regnum (operands[1]) == LO_REGNUM 1365169689Skan && peep2_reg_dead_p (2, operands[1]) 1366169689Skan && GP_REG_P (true_regnum (operands[3]))" 1367169689Skan [(parallel [(set (match_dup 0) 1368169689Skan (match_dup 6)) 1369169689Skan (clobber (match_dup 5)) 1370169689Skan (clobber (match_dup 1))]) 1371169689Skan (set (match_dup 3) 1372169689Skan (match_dup 7))] 1373169689Skan{ 1374169689Skan operands[6] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1); 1375169689Skan operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, 1376169689Skan operands[2], operands[0]); 1377169689Skan}) 1378169689Skan 1379169689Skan;; Same as above, except LO is the initial target of the macc. 1380169689Skan;; 1381169689Skan;; Operand 0: GPR (scratch) 1382169689Skan;; Operand 1: LO 1383169689Skan;; Operand 2: GPR (addend) 1384169689Skan;; Operand 3: macc/msac 1385169689Skan;; Operand 4: HI 1386169689Skan;; Operand 5: GPR (destination) 1387169689Skan;; Operand 6: new multiplication 1388169689Skan;; Operand 7: new addition/subtraction 1389169689Skan(define_peephole2 1390169689Skan [(match_scratch:SI 0 "d") 1391169689Skan (set (match_operand:SI 1 "register_operand") 1392169689Skan (match_operand:SI 2 "register_operand")) 1393169689Skan (match_dup 0) 1394169689Skan (parallel 1395169689Skan [(set (match_dup 1) 1396169689Skan (match_operand:SI 3 "macc_msac_operand")) 1397169689Skan (clobber (match_operand:SI 4 "register_operand")) 1398169689Skan (clobber (scratch:SI))]) 1399169689Skan (match_dup 0) 1400169689Skan (set (match_operand:SI 5 "register_operand") 1401169689Skan (unspec:SI [(match_dup 1) (match_dup 4)] UNSPEC_MFHILO))] 1402169689Skan "GENERATE_MULT3_SI && peep2_reg_dead_p (3, operands[1])" 1403169689Skan [(parallel [(set (match_dup 0) 1404169689Skan (match_dup 6)) 1405169689Skan (clobber (match_dup 4)) 1406169689Skan (clobber (match_dup 1))]) 1407169689Skan (set (match_dup 5) 1408169689Skan (match_dup 7))] 1409169689Skan{ 1410169689Skan operands[6] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1); 1411169689Skan operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, 1412169689Skan operands[2], operands[0]); 1413169689Skan}) 1414169689Skan 1415169689Skan(define_insn "*mul_sub_si" 1416169689Skan [(set (match_operand:SI 0 "register_operand" "=l,*d,*d") 1417169689Skan (minus:SI (match_operand:SI 1 "register_operand" "0,l,*d") 1418169689Skan (mult:SI (match_operand:SI 2 "register_operand" "d,d,d") 1419169689Skan (match_operand:SI 3 "register_operand" "d,d,d")))) 1420169689Skan (clobber (match_scratch:SI 4 "=h,h,h")) 1421169689Skan (clobber (match_scratch:SI 5 "=X,1,l")) 1422169689Skan (clobber (match_scratch:SI 6 "=X,X,&d"))] 1423169689Skan "ISA_HAS_MADD_MSUB" 1424169689Skan "@ 1425169689Skan msub\t%2,%3 1426169689Skan # 1427169689Skan #" 1428169689Skan [(set_attr "type" "imadd,multi,multi") 1429169689Skan (set_attr "mode" "SI") 1430169689Skan (set_attr "length" "4,8,8")]) 1431169689Skan 1432169689Skan;; Split the above insn if we failed to get LO allocated. 1433169689Skan(define_split 1434169689Skan [(set (match_operand:SI 0 "register_operand") 1435169689Skan (minus:SI (match_operand:SI 1 "register_operand") 1436169689Skan (mult:SI (match_operand:SI 2 "register_operand") 1437169689Skan (match_operand:SI 3 "register_operand")))) 1438169689Skan (clobber (match_scratch:SI 4)) 1439169689Skan (clobber (match_scratch:SI 5)) 1440169689Skan (clobber (match_scratch:SI 6))] 1441169689Skan "reload_completed && !TARGET_DEBUG_D_MODE 1442169689Skan && GP_REG_P (true_regnum (operands[0])) 1443169689Skan && GP_REG_P (true_regnum (operands[1]))" 1444169689Skan [(parallel [(set (match_dup 6) 1445169689Skan (mult:SI (match_dup 2) (match_dup 3))) 1446169689Skan (clobber (match_dup 4)) 1447169689Skan (clobber (match_dup 5))]) 1448169689Skan (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 6)))] 1449169689Skan "") 1450169689Skan 1451169689Skan;; Splitter to copy result of MSUB to a general register 1452169689Skan(define_split 1453169689Skan [(set (match_operand:SI 0 "register_operand") 1454169689Skan (minus:SI (match_operand:SI 1 "register_operand") 1455169689Skan (mult:SI (match_operand:SI 2 "register_operand") 1456169689Skan (match_operand:SI 3 "register_operand")))) 1457169689Skan (clobber (match_scratch:SI 4)) 1458169689Skan (clobber (match_scratch:SI 5)) 1459169689Skan (clobber (match_scratch:SI 6))] 1460169689Skan "reload_completed && !TARGET_DEBUG_D_MODE 1461169689Skan && GP_REG_P (true_regnum (operands[0])) 1462169689Skan && true_regnum (operands[1]) == LO_REGNUM" 1463169689Skan [(parallel [(set (match_dup 1) 1464169689Skan (minus:SI (match_dup 1) 1465169689Skan (mult:SI (match_dup 2) (match_dup 3)))) 1466169689Skan (clobber (match_dup 4)) 1467169689Skan (clobber (match_dup 5)) 1468169689Skan (clobber (match_dup 6))]) 1469169689Skan (set (match_dup 0) (unspec:SI [(match_dup 5) (match_dup 4)] UNSPEC_MFHILO))] 1470169689Skan "") 1471169689Skan 1472169689Skan(define_insn "*muls" 1473169689Skan [(set (match_operand:SI 0 "register_operand" "=l,d") 1474169689Skan (neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") 1475169689Skan (match_operand:SI 2 "register_operand" "d,d")))) 1476169689Skan (clobber (match_scratch:SI 3 "=h,h")) 1477169689Skan (clobber (match_scratch:SI 4 "=X,l"))] 1478169689Skan "ISA_HAS_MULS" 1479169689Skan "@ 1480169689Skan muls\t$0,%1,%2 1481169689Skan muls\t%0,%1,%2" 1482169689Skan [(set_attr "type" "imul,imul3") 1483169689Skan (set_attr "mode" "SI")]) 1484169689Skan 1485169689Skan;; ??? We could define a mulditi3 pattern when TARGET_64BIT. 1486169689Skan 1487169689Skan(define_expand "<u>mulsidi3" 1488169689Skan [(parallel 1489169689Skan [(set (match_operand:DI 0 "register_operand") 1490169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) 1491169689Skan (any_extend:DI (match_operand:SI 2 "register_operand")))) 1492169689Skan (clobber (scratch:DI)) 1493169689Skan (clobber (scratch:DI)) 1494169689Skan (clobber (scratch:DI))])] 1495169689Skan "!TARGET_64BIT || !TARGET_FIX_R4000" 1496169689Skan{ 1497169689Skan if (!TARGET_64BIT) 1498169689Skan { 1499169689Skan if (!TARGET_FIX_R4000) 1500169689Skan emit_insn (gen_<u>mulsidi3_32bit_internal (operands[0], operands[1], 1501169689Skan operands[2])); 1502169689Skan else 1503169689Skan emit_insn (gen_<u>mulsidi3_32bit_r4000 (operands[0], operands[1], 1504169689Skan operands[2])); 1505169689Skan DONE; 1506169689Skan } 1507169689Skan}) 1508169689Skan 1509169689Skan(define_insn "<u>mulsidi3_32bit_internal" 1510169689Skan [(set (match_operand:DI 0 "register_operand" "=x") 1511169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1512169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d"))))] 1513169689Skan "!TARGET_64BIT && !TARGET_FIX_R4000" 1514169689Skan "mult<u>\t%1,%2" 1515169689Skan [(set_attr "type" "imul") 1516169689Skan (set_attr "mode" "SI")]) 1517169689Skan 1518169689Skan(define_insn "<u>mulsidi3_32bit_r4000" 1519169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 1520169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1521169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) 1522169689Skan (clobber (match_scratch:DI 3 "=x"))] 1523169689Skan "!TARGET_64BIT && TARGET_FIX_R4000" 1524169689Skan "mult<u>\t%1,%2\;mflo\t%L0;mfhi\t%M0" 1525169689Skan [(set_attr "type" "imul") 1526169689Skan (set_attr "mode" "SI") 1527169689Skan (set_attr "length" "12")]) 1528169689Skan 1529169689Skan(define_insn_and_split "*<u>mulsidi3_64bit" 1530169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 1531169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1532169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) 1533169689Skan (clobber (match_scratch:DI 3 "=l")) 1534169689Skan (clobber (match_scratch:DI 4 "=h")) 1535169689Skan (clobber (match_scratch:DI 5 "=d"))] 1536169689Skan "TARGET_64BIT && !TARGET_FIX_R4000" 1537169689Skan "#" 1538169689Skan "&& reload_completed" 1539169689Skan [(parallel 1540169689Skan [(set (match_dup 3) 1541169689Skan (sign_extend:DI 1542169689Skan (mult:SI (match_dup 1) 1543169689Skan (match_dup 2)))) 1544169689Skan (set (match_dup 4) 1545169689Skan (ashiftrt:DI 1546169689Skan (mult:DI (any_extend:DI (match_dup 1)) 1547169689Skan (any_extend:DI (match_dup 2))) 1548169689Skan (const_int 32)))]) 1549169689Skan 1550169689Skan ;; OP5 <- LO, OP0 <- HI 1551169689Skan (set (match_dup 5) (unspec:DI [(match_dup 3) (match_dup 4)] UNSPEC_MFHILO)) 1552169689Skan (set (match_dup 0) (unspec:DI [(match_dup 4) (match_dup 3)] UNSPEC_MFHILO)) 1553169689Skan 1554169689Skan ;; Zero-extend OP5. 1555169689Skan (set (match_dup 5) 1556169689Skan (ashift:DI (match_dup 5) 1557169689Skan (const_int 32))) 1558169689Skan (set (match_dup 5) 1559169689Skan (lshiftrt:DI (match_dup 5) 1560169689Skan (const_int 32))) 1561169689Skan 1562169689Skan ;; Shift OP0 into place. 1563169689Skan (set (match_dup 0) 1564169689Skan (ashift:DI (match_dup 0) 1565169689Skan (const_int 32))) 1566169689Skan 1567169689Skan ;; OR the two halves together 1568169689Skan (set (match_dup 0) 1569169689Skan (ior:DI (match_dup 0) 1570169689Skan (match_dup 5)))] 1571169689Skan "" 1572169689Skan [(set_attr "type" "imul") 1573169689Skan (set_attr "mode" "SI") 1574169689Skan (set_attr "length" "24")]) 1575169689Skan 1576169689Skan(define_insn "*<u>mulsidi3_64bit_parts" 1577169689Skan [(set (match_operand:DI 0 "register_operand" "=l") 1578169689Skan (sign_extend:DI 1579169689Skan (mult:SI (match_operand:SI 2 "register_operand" "d") 1580169689Skan (match_operand:SI 3 "register_operand" "d")))) 1581169689Skan (set (match_operand:DI 1 "register_operand" "=h") 1582169689Skan (ashiftrt:DI 1583169689Skan (mult:DI (any_extend:DI (match_dup 2)) 1584169689Skan (any_extend:DI (match_dup 3))) 1585169689Skan (const_int 32)))] 1586169689Skan "TARGET_64BIT && !TARGET_FIX_R4000" 1587169689Skan "mult<u>\t%2,%3" 1588169689Skan [(set_attr "type" "imul") 1589169689Skan (set_attr "mode" "SI")]) 1590169689Skan 1591169689Skan;; Widening multiply with negation. 1592169689Skan(define_insn "*muls<u>_di" 1593169689Skan [(set (match_operand:DI 0 "register_operand" "=x") 1594169689Skan (neg:DI 1595169689Skan (mult:DI 1596169689Skan (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1597169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d")))))] 1598169689Skan "!TARGET_64BIT && ISA_HAS_MULS" 1599169689Skan "muls<u>\t$0,%1,%2" 1600169689Skan [(set_attr "type" "imul") 1601169689Skan (set_attr "mode" "SI")]) 1602169689Skan 1603169689Skan(define_insn "*msac<u>_di" 1604169689Skan [(set (match_operand:DI 0 "register_operand" "=x") 1605169689Skan (minus:DI 1606169689Skan (match_operand:DI 3 "register_operand" "0") 1607169689Skan (mult:DI 1608169689Skan (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1609169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d")))))] 1610169689Skan "!TARGET_64BIT && ISA_HAS_MSAC" 1611169689Skan{ 1612169689Skan if (TARGET_MIPS5500) 1613169689Skan return "msub<u>\t%1,%2"; 1614169689Skan else 1615169689Skan return "msac<u>\t$0,%1,%2"; 1616169689Skan} 1617169689Skan [(set_attr "type" "imadd") 1618169689Skan (set_attr "mode" "SI")]) 1619169689Skan 1620169689Skan;; _highpart patterns 1621169689Skan 1622169689Skan(define_expand "<su>mulsi3_highpart" 1623169689Skan [(set (match_operand:SI 0 "register_operand") 1624169689Skan (truncate:SI 1625169689Skan (lshiftrt:DI 1626169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) 1627169689Skan (any_extend:DI (match_operand:SI 2 "register_operand"))) 1628169689Skan (const_int 32))))] 1629169689Skan "ISA_HAS_MULHI || !TARGET_FIX_R4000" 1630169689Skan{ 1631169689Skan if (ISA_HAS_MULHI) 1632169689Skan emit_insn (gen_<su>mulsi3_highpart_mulhi_internal (operands[0], 1633169689Skan operands[1], 1634169689Skan operands[2])); 1635169689Skan else 1636169689Skan emit_insn (gen_<su>mulsi3_highpart_internal (operands[0], operands[1], 1637169689Skan operands[2])); 1638169689Skan DONE; 1639169689Skan}) 1640169689Skan 1641169689Skan(define_insn "<su>mulsi3_highpart_internal" 1642169689Skan [(set (match_operand:SI 0 "register_operand" "=h") 1643169689Skan (truncate:SI 1644169689Skan (lshiftrt:DI 1645169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1646169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) 1647169689Skan (const_int 32)))) 1648169689Skan (clobber (match_scratch:SI 3 "=l"))] 1649169689Skan "!ISA_HAS_MULHI && !TARGET_FIX_R4000" 1650169689Skan "mult<u>\t%1,%2" 1651169689Skan [(set_attr "type" "imul") 1652169689Skan (set_attr "mode" "SI")]) 1653169689Skan 1654169689Skan(define_insn "<su>mulsi3_highpart_mulhi_internal" 1655169689Skan [(set (match_operand:SI 0 "register_operand" "=h,d") 1656169689Skan (truncate:SI 1657169689Skan (lshiftrt:DI 1658169689Skan (mult:DI 1659169689Skan (any_extend:DI (match_operand:SI 1 "register_operand" "d,d")) 1660169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d,d"))) 1661169689Skan (const_int 32)))) 1662169689Skan (clobber (match_scratch:SI 3 "=l,l")) 1663169689Skan (clobber (match_scratch:SI 4 "=X,h"))] 1664169689Skan "ISA_HAS_MULHI" 1665169689Skan "@ 1666169689Skan mult<u>\t%1,%2 1667169689Skan mulhi<u>\t%0,%1,%2" 1668169689Skan [(set_attr "type" "imul,imul3") 1669169689Skan (set_attr "mode" "SI")]) 1670169689Skan 1671169689Skan(define_insn "*<su>mulsi3_highpart_neg_mulhi_internal" 1672169689Skan [(set (match_operand:SI 0 "register_operand" "=h,d") 1673169689Skan (truncate:SI 1674169689Skan (lshiftrt:DI 1675169689Skan (neg:DI 1676169689Skan (mult:DI 1677169689Skan (any_extend:DI (match_operand:SI 1 "register_operand" "d,d")) 1678169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d,d")))) 1679169689Skan (const_int 32)))) 1680169689Skan (clobber (match_scratch:SI 3 "=l,l")) 1681169689Skan (clobber (match_scratch:SI 4 "=X,h"))] 1682169689Skan "ISA_HAS_MULHI" 1683169689Skan "@ 1684169689Skan mulshi<u>\t%.,%1,%2 1685169689Skan mulshi<u>\t%0,%1,%2" 1686169689Skan [(set_attr "type" "imul,imul3") 1687169689Skan (set_attr "mode" "SI")]) 1688169689Skan 1689169689Skan;; Disable unsigned multiplication for -mfix-vr4120. This is for VR4120 1690169689Skan;; errata MD(0), which says that dmultu does not always produce the 1691169689Skan;; correct result. 1692169689Skan(define_insn "<su>muldi3_highpart" 1693169689Skan [(set (match_operand:DI 0 "register_operand" "=h") 1694169689Skan (truncate:DI 1695169689Skan (lshiftrt:TI 1696169689Skan (mult:TI 1697169689Skan (any_extend:TI (match_operand:DI 1 "register_operand" "d")) 1698169689Skan (any_extend:TI (match_operand:DI 2 "register_operand" "d"))) 1699169689Skan (const_int 64)))) 1700169689Skan (clobber (match_scratch:DI 3 "=l"))] 1701169689Skan "TARGET_64BIT && !TARGET_FIX_R4000 1702169689Skan && !(<CODE> == ZERO_EXTEND && TARGET_FIX_VR4120)" 1703169689Skan "dmult<u>\t%1,%2" 1704169689Skan [(set_attr "type" "imul") 1705169689Skan (set_attr "mode" "DI")]) 1706169689Skan 1707169689Skan;; The R4650 supports a 32 bit multiply/ 64 bit accumulate 1708169689Skan;; instruction. The HI/LO registers are used as a 64 bit accumulator. 1709169689Skan 1710169689Skan(define_insn "madsi" 1711169689Skan [(set (match_operand:SI 0 "register_operand" "+l") 1712169689Skan (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d") 1713169689Skan (match_operand:SI 2 "register_operand" "d")) 1714169689Skan (match_dup 0))) 1715169689Skan (clobber (match_scratch:SI 3 "=h"))] 1716169689Skan "TARGET_MAD" 1717169689Skan "mad\t%1,%2" 1718169689Skan [(set_attr "type" "imadd") 1719169689Skan (set_attr "mode" "SI")]) 1720169689Skan 1721169689Skan(define_insn "*<su>mul_acc_di" 1722169689Skan [(set (match_operand:DI 0 "register_operand" "=x") 1723169689Skan (plus:DI 1724169689Skan (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) 1725169689Skan (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) 1726169689Skan (match_operand:DI 3 "register_operand" "0")))] 1727169689Skan "(TARGET_MAD || ISA_HAS_MACC) 1728169689Skan && !TARGET_64BIT" 1729169689Skan{ 1730169689Skan if (TARGET_MAD) 1731169689Skan return "mad<u>\t%1,%2"; 1732169689Skan else if (TARGET_MIPS5500) 1733169689Skan return "madd<u>\t%1,%2"; 1734169689Skan else 1735169689Skan /* See comment in *macc. */ 1736169689Skan return "%[macc<u>\t%@,%1,%2%]"; 1737169689Skan} 1738169689Skan [(set_attr "type" "imadd") 1739169689Skan (set_attr "mode" "SI")]) 1740169689Skan 1741169689Skan;; Floating point multiply accumulate instructions. 1742169689Skan 1743169689Skan(define_insn "*madd<mode>" 1744169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1745169689Skan (plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") 1746169689Skan (match_operand:ANYF 2 "register_operand" "f")) 1747169689Skan (match_operand:ANYF 3 "register_operand" "f")))] 1748169689Skan "ISA_HAS_FP4 && TARGET_FUSED_MADD" 1749169689Skan "madd.<fmt>\t%0,%3,%1,%2" 1750169689Skan [(set_attr "type" "fmadd") 1751169689Skan (set_attr "mode" "<UNITMODE>")]) 1752169689Skan 1753169689Skan(define_insn "*msub<mode>" 1754169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1755169689Skan (minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") 1756169689Skan (match_operand:ANYF 2 "register_operand" "f")) 1757169689Skan (match_operand:ANYF 3 "register_operand" "f")))] 1758169689Skan "ISA_HAS_FP4 && TARGET_FUSED_MADD" 1759169689Skan "msub.<fmt>\t%0,%3,%1,%2" 1760169689Skan [(set_attr "type" "fmadd") 1761169689Skan (set_attr "mode" "<UNITMODE>")]) 1762169689Skan 1763169689Skan(define_insn "*nmadd<mode>" 1764169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1765169689Skan (neg:ANYF (plus:ANYF 1766169689Skan (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") 1767169689Skan (match_operand:ANYF 2 "register_operand" "f")) 1768169689Skan (match_operand:ANYF 3 "register_operand" "f"))))] 1769169689Skan "ISA_HAS_NMADD_NMSUB && TARGET_FUSED_MADD 1770169689Skan && HONOR_SIGNED_ZEROS (<MODE>mode) 1771169689Skan && !HONOR_NANS (<MODE>mode)" 1772169689Skan "nmadd.<fmt>\t%0,%3,%1,%2" 1773169689Skan [(set_attr "type" "fmadd") 1774169689Skan (set_attr "mode" "<UNITMODE>")]) 1775169689Skan 1776169689Skan(define_insn "*nmadd<mode>_fastmath" 1777169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1778169689Skan (minus:ANYF 1779169689Skan (mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")) 1780169689Skan (match_operand:ANYF 2 "register_operand" "f")) 1781169689Skan (match_operand:ANYF 3 "register_operand" "f")))] 1782169689Skan "ISA_HAS_NMADD_NMSUB && TARGET_FUSED_MADD 1783169689Skan && !HONOR_SIGNED_ZEROS (<MODE>mode) 1784169689Skan && !HONOR_NANS (<MODE>mode)" 1785169689Skan "nmadd.<fmt>\t%0,%3,%1,%2" 1786169689Skan [(set_attr "type" "fmadd") 1787169689Skan (set_attr "mode" "<UNITMODE>")]) 1788169689Skan 1789169689Skan(define_insn "*nmsub<mode>" 1790169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1791169689Skan (neg:ANYF (minus:ANYF 1792169689Skan (mult:ANYF (match_operand:ANYF 2 "register_operand" "f") 1793169689Skan (match_operand:ANYF 3 "register_operand" "f")) 1794169689Skan (match_operand:ANYF 1 "register_operand" "f"))))] 1795169689Skan "ISA_HAS_NMADD_NMSUB && TARGET_FUSED_MADD 1796169689Skan && HONOR_SIGNED_ZEROS (<MODE>mode) 1797169689Skan && !HONOR_NANS (<MODE>mode)" 1798169689Skan "nmsub.<fmt>\t%0,%1,%2,%3" 1799169689Skan [(set_attr "type" "fmadd") 1800169689Skan (set_attr "mode" "<UNITMODE>")]) 1801169689Skan 1802169689Skan(define_insn "*nmsub<mode>_fastmath" 1803169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1804169689Skan (minus:ANYF 1805169689Skan (match_operand:ANYF 1 "register_operand" "f") 1806169689Skan (mult:ANYF (match_operand:ANYF 2 "register_operand" "f") 1807169689Skan (match_operand:ANYF 3 "register_operand" "f"))))] 1808169689Skan "ISA_HAS_NMADD_NMSUB && TARGET_FUSED_MADD 1809169689Skan && !HONOR_SIGNED_ZEROS (<MODE>mode) 1810169689Skan && !HONOR_NANS (<MODE>mode)" 1811169689Skan "nmsub.<fmt>\t%0,%1,%2,%3" 1812169689Skan [(set_attr "type" "fmadd") 1813169689Skan (set_attr "mode" "<UNITMODE>")]) 1814169689Skan 1815169689Skan;; 1816169689Skan;; .................... 1817169689Skan;; 1818169689Skan;; DIVISION and REMAINDER 1819169689Skan;; 1820169689Skan;; .................... 1821169689Skan;; 1822169689Skan 1823169689Skan(define_expand "div<mode>3" 1824169689Skan [(set (match_operand:ANYF 0 "register_operand") 1825169689Skan (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand") 1826169689Skan (match_operand:ANYF 2 "register_operand")))] 1827169689Skan "<divide_condition>" 1828169689Skan{ 1829169689Skan if (const_1_operand (operands[1], <MODE>mode)) 1830169689Skan if (!(ISA_HAS_FP4 && flag_unsafe_math_optimizations)) 1831169689Skan operands[1] = force_reg (<MODE>mode, operands[1]); 1832169689Skan}) 1833169689Skan 1834169689Skan;; These patterns work around the early SB-1 rev2 core "F1" erratum: 1835169689Skan;; 1836169689Skan;; If an mfc1 or dmfc1 happens to access the floating point register 1837169689Skan;; file at the same time a long latency operation (div, sqrt, recip, 1838169689Skan;; sqrt) iterates an intermediate result back through the floating 1839169689Skan;; point register file bypass, then instead returning the correct 1840169689Skan;; register value the mfc1 or dmfc1 operation returns the intermediate 1841169689Skan;; result of the long latency operation. 1842169689Skan;; 1843169689Skan;; The workaround is to insert an unconditional 'mov' from/to the 1844169689Skan;; long latency op destination register. 1845169689Skan 1846169689Skan(define_insn "*div<mode>3" 1847169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1848169689Skan (div:ANYF (match_operand:ANYF 1 "register_operand" "f") 1849169689Skan (match_operand:ANYF 2 "register_operand" "f")))] 1850169689Skan "<divide_condition>" 1851169689Skan{ 1852169689Skan if (TARGET_FIX_SB1) 1853169689Skan return "div.<fmt>\t%0,%1,%2\;mov.<fmt>\t%0,%0"; 1854169689Skan else 1855169689Skan return "div.<fmt>\t%0,%1,%2"; 1856169689Skan} 1857169689Skan [(set_attr "type" "fdiv") 1858169689Skan (set_attr "mode" "<UNITMODE>") 1859169689Skan (set (attr "length") 1860169689Skan (if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0)) 1861169689Skan (const_int 8) 1862169689Skan (const_int 4)))]) 1863169689Skan 1864169689Skan(define_insn "*recip<mode>3" 1865169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1866169689Skan (div:ANYF (match_operand:ANYF 1 "const_1_operand" "") 1867169689Skan (match_operand:ANYF 2 "register_operand" "f")))] 1868169689Skan "<recip_condition> && flag_unsafe_math_optimizations" 1869169689Skan{ 1870169689Skan if (TARGET_FIX_SB1) 1871169689Skan return "recip.<fmt>\t%0,%2\;mov.<fmt>\t%0,%0"; 1872169689Skan else 1873169689Skan return "recip.<fmt>\t%0,%2"; 1874169689Skan} 1875169689Skan [(set_attr "type" "frdiv") 1876169689Skan (set_attr "mode" "<UNITMODE>") 1877169689Skan (set (attr "length") 1878169689Skan (if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0)) 1879169689Skan (const_int 8) 1880169689Skan (const_int 4)))]) 1881169689Skan 1882169689Skan;; VR4120 errata MD(A1): signed division instructions do not work correctly 1883169689Skan;; with negative operands. We use special libgcc functions instead. 1884169689Skan(define_insn "divmod<mode>4" 1885169689Skan [(set (match_operand:GPR 0 "register_operand" "=l") 1886169689Skan (div:GPR (match_operand:GPR 1 "register_operand" "d") 1887169689Skan (match_operand:GPR 2 "register_operand" "d"))) 1888169689Skan (set (match_operand:GPR 3 "register_operand" "=h") 1889169689Skan (mod:GPR (match_dup 1) 1890169689Skan (match_dup 2)))] 1891169689Skan "!TARGET_FIX_VR4120" 1892169689Skan { return mips_output_division ("<d>div\t$0,%1,%2", operands); } 1893169689Skan [(set_attr "type" "idiv") 1894169689Skan (set_attr "mode" "<MODE>")]) 1895169689Skan 1896169689Skan(define_insn "udivmod<mode>4" 1897169689Skan [(set (match_operand:GPR 0 "register_operand" "=l") 1898169689Skan (udiv:GPR (match_operand:GPR 1 "register_operand" "d") 1899169689Skan (match_operand:GPR 2 "register_operand" "d"))) 1900169689Skan (set (match_operand:GPR 3 "register_operand" "=h") 1901169689Skan (umod:GPR (match_dup 1) 1902169689Skan (match_dup 2)))] 1903169689Skan "" 1904169689Skan { return mips_output_division ("<d>divu\t$0,%1,%2", operands); } 1905169689Skan [(set_attr "type" "idiv") 1906169689Skan (set_attr "mode" "<MODE>")]) 1907169689Skan 1908169689Skan;; 1909169689Skan;; .................... 1910169689Skan;; 1911169689Skan;; SQUARE ROOT 1912169689Skan;; 1913169689Skan;; .................... 1914169689Skan 1915169689Skan;; These patterns work around the early SB-1 rev2 core "F1" erratum (see 1916169689Skan;; "*div[sd]f3" comment for details). 1917169689Skan 1918169689Skan(define_insn "sqrt<mode>2" 1919169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1920169689Skan (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))] 1921169689Skan "<sqrt_condition>" 1922169689Skan{ 1923169689Skan if (TARGET_FIX_SB1) 1924169689Skan return "sqrt.<fmt>\t%0,%1\;mov.<fmt>\t%0,%0"; 1925169689Skan else 1926169689Skan return "sqrt.<fmt>\t%0,%1"; 1927169689Skan} 1928169689Skan [(set_attr "type" "fsqrt") 1929169689Skan (set_attr "mode" "<UNITMODE>") 1930169689Skan (set (attr "length") 1931169689Skan (if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0)) 1932169689Skan (const_int 8) 1933169689Skan (const_int 4)))]) 1934169689Skan 1935169689Skan(define_insn "*rsqrt<mode>a" 1936169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1937169689Skan (div:ANYF (match_operand:ANYF 1 "const_1_operand" "") 1938169689Skan (sqrt:ANYF (match_operand:ANYF 2 "register_operand" "f"))))] 1939169689Skan "<recip_condition> && flag_unsafe_math_optimizations" 1940169689Skan{ 1941169689Skan if (TARGET_FIX_SB1) 1942169689Skan return "rsqrt.<fmt>\t%0,%2\;mov.<fmt>\t%0,%0"; 1943169689Skan else 1944169689Skan return "rsqrt.<fmt>\t%0,%2"; 1945169689Skan} 1946169689Skan [(set_attr "type" "frsqrt") 1947169689Skan (set_attr "mode" "<UNITMODE>") 1948169689Skan (set (attr "length") 1949169689Skan (if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0)) 1950169689Skan (const_int 8) 1951169689Skan (const_int 4)))]) 1952169689Skan 1953169689Skan(define_insn "*rsqrt<mode>b" 1954169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1955169689Skan (sqrt:ANYF (div:ANYF (match_operand:ANYF 1 "const_1_operand" "") 1956169689Skan (match_operand:ANYF 2 "register_operand" "f"))))] 1957169689Skan "<recip_condition> && flag_unsafe_math_optimizations" 1958169689Skan{ 1959169689Skan if (TARGET_FIX_SB1) 1960169689Skan return "rsqrt.<fmt>\t%0,%2\;mov.<fmt>\t%0,%0"; 1961169689Skan else 1962169689Skan return "rsqrt.<fmt>\t%0,%2"; 1963169689Skan} 1964169689Skan [(set_attr "type" "frsqrt") 1965169689Skan (set_attr "mode" "<UNITMODE>") 1966169689Skan (set (attr "length") 1967169689Skan (if_then_else (ne (symbol_ref "TARGET_FIX_SB1") (const_int 0)) 1968169689Skan (const_int 8) 1969169689Skan (const_int 4)))]) 1970169689Skan 1971169689Skan;; 1972169689Skan;; .................... 1973169689Skan;; 1974169689Skan;; ABSOLUTE VALUE 1975169689Skan;; 1976169689Skan;; .................... 1977169689Skan 1978169689Skan;; Do not use the integer abs macro instruction, since that signals an 1979169689Skan;; exception on -2147483648 (sigh). 1980169689Skan 1981169689Skan;; abs.fmt is an arithmetic instruction and treats all NaN inputs as 1982169689Skan;; invalid; it does not clear their sign bits. We therefore can't use 1983169689Skan;; abs.fmt if the signs of NaNs matter. 1984169689Skan 1985169689Skan(define_insn "abs<mode>2" 1986169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 1987169689Skan (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))] 1988169689Skan "!HONOR_NANS (<MODE>mode)" 1989169689Skan "abs.<fmt>\t%0,%1" 1990169689Skan [(set_attr "type" "fabs") 1991169689Skan (set_attr "mode" "<UNITMODE>")]) 1992169689Skan 1993169689Skan;; 1994169689Skan;; ................... 1995169689Skan;; 1996169689Skan;; Count leading zeroes. 1997169689Skan;; 1998169689Skan;; ................... 1999169689Skan;; 2000169689Skan 2001169689Skan(define_insn "clz<mode>2" 2002169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2003169689Skan (clz:GPR (match_operand:GPR 1 "register_operand" "d")))] 2004169689Skan "ISA_HAS_CLZ_CLO" 2005169689Skan "<d>clz\t%0,%1" 2006169689Skan [(set_attr "type" "clz") 2007169689Skan (set_attr "mode" "<MODE>")]) 2008169689Skan 2009169689Skan;; 2010169689Skan;; .................... 2011169689Skan;; 2012169689Skan;; NEGATION and ONE'S COMPLEMENT 2013169689Skan;; 2014169689Skan;; .................... 2015169689Skan 2016169689Skan(define_insn "negsi2" 2017169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2018169689Skan (neg:SI (match_operand:SI 1 "register_operand" "d")))] 2019169689Skan "" 2020169689Skan{ 2021169689Skan if (TARGET_MIPS16) 2022169689Skan return "neg\t%0,%1"; 2023169689Skan else 2024169689Skan return "subu\t%0,%.,%1"; 2025169689Skan} 2026169689Skan [(set_attr "type" "arith") 2027169689Skan (set_attr "mode" "SI")]) 2028169689Skan 2029169689Skan(define_insn "negdi2" 2030169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 2031169689Skan (neg:DI (match_operand:DI 1 "register_operand" "d")))] 2032169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2033169689Skan "dsubu\t%0,%.,%1" 2034169689Skan [(set_attr "type" "arith") 2035169689Skan (set_attr "mode" "DI")]) 2036169689Skan 2037169689Skan;; neg.fmt is an arithmetic instruction and treats all NaN inputs as 2038169689Skan;; invalid; it does not flip their sign bit. We therefore can't use 2039169689Skan;; neg.fmt if the signs of NaNs matter. 2040169689Skan 2041169689Skan(define_insn "neg<mode>2" 2042169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 2043169689Skan (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))] 2044169689Skan "!HONOR_NANS (<MODE>mode)" 2045169689Skan "neg.<fmt>\t%0,%1" 2046169689Skan [(set_attr "type" "fneg") 2047169689Skan (set_attr "mode" "<UNITMODE>")]) 2048169689Skan 2049169689Skan(define_insn "one_cmpl<mode>2" 2050169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2051169689Skan (not:GPR (match_operand:GPR 1 "register_operand" "d")))] 2052169689Skan "" 2053169689Skan{ 2054169689Skan if (TARGET_MIPS16) 2055169689Skan return "not\t%0,%1"; 2056169689Skan else 2057169689Skan return "nor\t%0,%.,%1"; 2058169689Skan} 2059169689Skan [(set_attr "type" "arith") 2060169689Skan (set_attr "mode" "<MODE>")]) 2061169689Skan 2062169689Skan;; 2063169689Skan;; .................... 2064169689Skan;; 2065169689Skan;; LOGICAL 2066169689Skan;; 2067169689Skan;; .................... 2068169689Skan;; 2069169689Skan 2070169689Skan;; Many of these instructions use trivial define_expands, because we 2071169689Skan;; want to use a different set of constraints when TARGET_MIPS16. 2072169689Skan 2073169689Skan(define_expand "and<mode>3" 2074169689Skan [(set (match_operand:GPR 0 "register_operand") 2075169689Skan (and:GPR (match_operand:GPR 1 "register_operand") 2076169689Skan (match_operand:GPR 2 "uns_arith_operand")))] 2077169689Skan "" 2078169689Skan{ 2079169689Skan if (TARGET_MIPS16) 2080169689Skan operands[2] = force_reg (<MODE>mode, operands[2]); 2081169689Skan}) 2082169689Skan 2083169689Skan(define_insn "*and<mode>3" 2084169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2085169689Skan (and:GPR (match_operand:GPR 1 "register_operand" "%d,d") 2086169689Skan (match_operand:GPR 2 "uns_arith_operand" "d,K")))] 2087169689Skan "!TARGET_MIPS16" 2088169689Skan "@ 2089169689Skan and\t%0,%1,%2 2090169689Skan andi\t%0,%1,%x2" 2091169689Skan [(set_attr "type" "arith") 2092169689Skan (set_attr "mode" "<MODE>")]) 2093169689Skan 2094169689Skan(define_insn "*and<mode>3_mips16" 2095169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2096169689Skan (and:GPR (match_operand:GPR 1 "register_operand" "%0") 2097169689Skan (match_operand:GPR 2 "register_operand" "d")))] 2098169689Skan "TARGET_MIPS16" 2099169689Skan "and\t%0,%2" 2100169689Skan [(set_attr "type" "arith") 2101169689Skan (set_attr "mode" "<MODE>")]) 2102169689Skan 2103169689Skan(define_expand "ior<mode>3" 2104169689Skan [(set (match_operand:GPR 0 "register_operand") 2105169689Skan (ior:GPR (match_operand:GPR 1 "register_operand") 2106169689Skan (match_operand:GPR 2 "uns_arith_operand")))] 2107169689Skan "" 2108169689Skan{ 2109169689Skan if (TARGET_MIPS16) 2110169689Skan operands[2] = force_reg (<MODE>mode, operands[2]); 2111169689Skan}) 2112169689Skan 2113169689Skan(define_insn "*ior<mode>3" 2114169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2115169689Skan (ior:GPR (match_operand:GPR 1 "register_operand" "%d,d") 2116169689Skan (match_operand:GPR 2 "uns_arith_operand" "d,K")))] 2117169689Skan "!TARGET_MIPS16" 2118169689Skan "@ 2119169689Skan or\t%0,%1,%2 2120169689Skan ori\t%0,%1,%x2" 2121169689Skan [(set_attr "type" "arith") 2122169689Skan (set_attr "mode" "<MODE>")]) 2123169689Skan 2124169689Skan(define_insn "*ior<mode>3_mips16" 2125169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2126169689Skan (ior:GPR (match_operand:GPR 1 "register_operand" "%0") 2127169689Skan (match_operand:GPR 2 "register_operand" "d")))] 2128169689Skan "TARGET_MIPS16" 2129169689Skan "or\t%0,%2" 2130169689Skan [(set_attr "type" "arith") 2131169689Skan (set_attr "mode" "<MODE>")]) 2132169689Skan 2133169689Skan(define_expand "xor<mode>3" 2134169689Skan [(set (match_operand:GPR 0 "register_operand") 2135169689Skan (xor:GPR (match_operand:GPR 1 "register_operand") 2136169689Skan (match_operand:GPR 2 "uns_arith_operand")))] 2137169689Skan "" 2138169689Skan "") 2139169689Skan 2140169689Skan(define_insn "" 2141169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2142169689Skan (xor:GPR (match_operand:GPR 1 "register_operand" "%d,d") 2143169689Skan (match_operand:GPR 2 "uns_arith_operand" "d,K")))] 2144169689Skan "!TARGET_MIPS16" 2145169689Skan "@ 2146169689Skan xor\t%0,%1,%2 2147169689Skan xori\t%0,%1,%x2" 2148169689Skan [(set_attr "type" "arith") 2149169689Skan (set_attr "mode" "<MODE>")]) 2150169689Skan 2151169689Skan(define_insn "" 2152169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,t,t") 2153169689Skan (xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d") 2154169689Skan (match_operand:GPR 2 "uns_arith_operand" "d,K,d")))] 2155169689Skan "TARGET_MIPS16" 2156169689Skan "@ 2157169689Skan xor\t%0,%2 2158169689Skan cmpi\t%1,%2 2159169689Skan cmp\t%1,%2" 2160169689Skan [(set_attr "type" "arith") 2161169689Skan (set_attr "mode" "<MODE>") 2162169689Skan (set_attr_alternative "length" 2163169689Skan [(const_int 4) 2164169689Skan (if_then_else (match_operand:VOID 2 "m16_uimm8_1") 2165169689Skan (const_int 4) 2166169689Skan (const_int 8)) 2167169689Skan (const_int 4)])]) 2168169689Skan 2169169689Skan(define_insn "*nor<mode>3" 2170169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2171169689Skan (and:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d")) 2172169689Skan (not:GPR (match_operand:GPR 2 "register_operand" "d"))))] 2173169689Skan "!TARGET_MIPS16" 2174169689Skan "nor\t%0,%1,%2" 2175169689Skan [(set_attr "type" "arith") 2176169689Skan (set_attr "mode" "<MODE>")]) 2177169689Skan 2178169689Skan;; 2179169689Skan;; .................... 2180169689Skan;; 2181169689Skan;; TRUNCATION 2182169689Skan;; 2183169689Skan;; .................... 2184169689Skan 2185169689Skan 2186169689Skan 2187169689Skan(define_insn "truncdfsf2" 2188169689Skan [(set (match_operand:SF 0 "register_operand" "=f") 2189169689Skan (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] 2190169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" 2191169689Skan "cvt.s.d\t%0,%1" 2192169689Skan [(set_attr "type" "fcvt") 2193169689Skan (set_attr "cnv_mode" "D2S") 2194169689Skan (set_attr "mode" "SF")]) 2195169689Skan 2196169689Skan;; Integer truncation patterns. Truncating SImode values to smaller 2197169689Skan;; modes is a no-op, as it is for most other GCC ports. Truncating 2198169689Skan;; DImode values to SImode is not a no-op for TARGET_64BIT since we 2199169689Skan;; need to make sure that the lower 32 bits are properly sign-extended 2200169689Skan;; (see TRULY_NOOP_TRUNCATION). Truncating DImode values into modes 2201169689Skan;; smaller than SImode is equivalent to two separate truncations: 2202169689Skan;; 2203169689Skan;; A B 2204169689Skan;; DI ---> HI == DI ---> SI ---> HI 2205169689Skan;; DI ---> QI == DI ---> SI ---> QI 2206169689Skan;; 2207169689Skan;; Step A needs a real instruction but step B does not. 2208169689Skan 2209169689Skan(define_insn "truncdisi2" 2210169689Skan [(set (match_operand:SI 0 "nonimmediate_operand" "=d,m") 2211169689Skan (truncate:SI (match_operand:DI 1 "register_operand" "d,d")))] 2212169689Skan "TARGET_64BIT" 2213169689Skan "@ 2214169689Skan sll\t%0,%1,0 2215169689Skan sw\t%1,%0" 2216169689Skan [(set_attr "type" "shift,store") 2217169689Skan (set_attr "mode" "SI") 2218169689Skan (set_attr "extended_mips16" "yes,*")]) 2219169689Skan 2220169689Skan(define_insn "truncdihi2" 2221169689Skan [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m") 2222169689Skan (truncate:HI (match_operand:DI 1 "register_operand" "d,d")))] 2223169689Skan "TARGET_64BIT" 2224169689Skan "@ 2225169689Skan sll\t%0,%1,0 2226169689Skan sh\t%1,%0" 2227169689Skan [(set_attr "type" "shift,store") 2228169689Skan (set_attr "mode" "SI") 2229169689Skan (set_attr "extended_mips16" "yes,*")]) 2230169689Skan 2231169689Skan(define_insn "truncdiqi2" 2232169689Skan [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m") 2233169689Skan (truncate:QI (match_operand:DI 1 "register_operand" "d,d")))] 2234169689Skan "TARGET_64BIT" 2235169689Skan "@ 2236169689Skan sll\t%0,%1,0 2237169689Skan sb\t%1,%0" 2238169689Skan [(set_attr "type" "shift,store") 2239169689Skan (set_attr "mode" "SI") 2240169689Skan (set_attr "extended_mips16" "yes,*")]) 2241169689Skan 2242169689Skan;; Combiner patterns to optimize shift/truncate combinations. 2243169689Skan 2244169689Skan(define_insn "" 2245169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2246169689Skan (truncate:SI 2247169689Skan (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") 2248169689Skan (match_operand:DI 2 "const_arith_operand" ""))))] 2249169689Skan "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) >= 32" 2250169689Skan "dsra\t%0,%1,%2" 2251169689Skan [(set_attr "type" "shift") 2252169689Skan (set_attr "mode" "SI")]) 2253169689Skan 2254169689Skan(define_insn "" 2255169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2256169689Skan (truncate:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") 2257169689Skan (const_int 32))))] 2258169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2259169689Skan "dsra\t%0,%1,32" 2260169689Skan [(set_attr "type" "shift") 2261169689Skan (set_attr "mode" "SI")]) 2262169689Skan 2263169689Skan 2264169689Skan;; Combiner patterns for truncate/sign_extend combinations. They use 2265169689Skan;; the shift/truncate patterns above. 2266169689Skan 2267169689Skan(define_insn_and_split "" 2268169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2269169689Skan (sign_extend:SI 2270169689Skan (truncate:HI (match_operand:DI 1 "register_operand" "d"))))] 2271169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2272169689Skan "#" 2273169689Skan "&& reload_completed" 2274169689Skan [(set (match_dup 2) 2275169689Skan (ashift:DI (match_dup 1) 2276169689Skan (const_int 48))) 2277169689Skan (set (match_dup 0) 2278169689Skan (truncate:SI (ashiftrt:DI (match_dup 2) 2279169689Skan (const_int 48))))] 2280169689Skan { operands[2] = gen_lowpart (DImode, operands[0]); }) 2281169689Skan 2282169689Skan(define_insn_and_split "" 2283169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2284169689Skan (sign_extend:SI 2285169689Skan (truncate:QI (match_operand:DI 1 "register_operand" "d"))))] 2286169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2287169689Skan "#" 2288169689Skan "&& reload_completed" 2289169689Skan [(set (match_dup 2) 2290169689Skan (ashift:DI (match_dup 1) 2291169689Skan (const_int 56))) 2292169689Skan (set (match_dup 0) 2293169689Skan (truncate:SI (ashiftrt:DI (match_dup 2) 2294169689Skan (const_int 56))))] 2295169689Skan { operands[2] = gen_lowpart (DImode, operands[0]); }) 2296169689Skan 2297169689Skan 2298169689Skan;; Combiner patterns to optimize truncate/zero_extend combinations. 2299169689Skan 2300169689Skan(define_insn "" 2301169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2302169689Skan (zero_extend:SI (truncate:HI 2303169689Skan (match_operand:DI 1 "register_operand" "d"))))] 2304169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2305169689Skan "andi\t%0,%1,0xffff" 2306169689Skan [(set_attr "type" "arith") 2307169689Skan (set_attr "mode" "SI")]) 2308169689Skan 2309169689Skan(define_insn "" 2310169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 2311169689Skan (zero_extend:SI (truncate:QI 2312169689Skan (match_operand:DI 1 "register_operand" "d"))))] 2313169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2314169689Skan "andi\t%0,%1,0xff" 2315169689Skan [(set_attr "type" "arith") 2316169689Skan (set_attr "mode" "SI")]) 2317169689Skan 2318169689Skan(define_insn "" 2319169689Skan [(set (match_operand:HI 0 "register_operand" "=d") 2320169689Skan (zero_extend:HI (truncate:QI 2321169689Skan (match_operand:DI 1 "register_operand" "d"))))] 2322169689Skan "TARGET_64BIT && !TARGET_MIPS16" 2323169689Skan "andi\t%0,%1,0xff" 2324169689Skan [(set_attr "type" "arith") 2325169689Skan (set_attr "mode" "HI")]) 2326169689Skan 2327169689Skan;; 2328169689Skan;; .................... 2329169689Skan;; 2330169689Skan;; ZERO EXTENSION 2331169689Skan;; 2332169689Skan;; .................... 2333169689Skan 2334169689Skan;; Extension insns. 2335169689Skan 2336169689Skan(define_insn_and_split "zero_extendsidi2" 2337169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 2338169689Skan (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))] 2339169689Skan "TARGET_64BIT" 2340169689Skan "@ 2341169689Skan # 2342169689Skan lwu\t%0,%1" 2343169689Skan "&& reload_completed && REG_P (operands[1])" 2344169689Skan [(set (match_dup 0) 2345169689Skan (ashift:DI (match_dup 1) (const_int 32))) 2346169689Skan (set (match_dup 0) 2347169689Skan (lshiftrt:DI (match_dup 0) (const_int 32)))] 2348169689Skan { operands[1] = gen_lowpart (DImode, operands[1]); } 2349169689Skan [(set_attr "type" "multi,load") 2350169689Skan (set_attr "mode" "DI") 2351169689Skan (set_attr "length" "8,*")]) 2352169689Skan 2353169689Skan;; Combine is not allowed to convert this insn into a zero_extendsidi2 2354169689Skan;; because of TRULY_NOOP_TRUNCATION. 2355169689Skan 2356169689Skan(define_insn_and_split "*clear_upper32" 2357169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 2358169689Skan (and:DI (match_operand:DI 1 "nonimmediate_operand" "d,o") 2359169689Skan (const_int 4294967295)))] 2360169689Skan "TARGET_64BIT" 2361169689Skan{ 2362169689Skan if (which_alternative == 0) 2363169689Skan return "#"; 2364169689Skan 2365169689Skan operands[1] = gen_lowpart (SImode, operands[1]); 2366169689Skan return "lwu\t%0,%1"; 2367169689Skan} 2368169689Skan "&& reload_completed && REG_P (operands[1])" 2369169689Skan [(set (match_dup 0) 2370169689Skan (ashift:DI (match_dup 1) (const_int 32))) 2371169689Skan (set (match_dup 0) 2372169689Skan (lshiftrt:DI (match_dup 0) (const_int 32)))] 2373169689Skan "" 2374169689Skan [(set_attr "type" "multi,load") 2375169689Skan (set_attr "mode" "DI") 2376169689Skan (set_attr "length" "8,*")]) 2377169689Skan 2378169689Skan(define_expand "zero_extend<SHORT:mode><GPR:mode>2" 2379169689Skan [(set (match_operand:GPR 0 "register_operand") 2380169689Skan (zero_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))] 2381169689Skan "" 2382169689Skan{ 2383169689Skan if (TARGET_MIPS16 && !GENERATE_MIPS16E 2384169689Skan && !memory_operand (operands[1], <SHORT:MODE>mode)) 2385169689Skan { 2386169689Skan emit_insn (gen_and<GPR:mode>3 (operands[0], 2387169689Skan gen_lowpart (<GPR:MODE>mode, operands[1]), 2388169689Skan force_reg (<GPR:MODE>mode, 2389169689Skan GEN_INT (<SHORT:mask>)))); 2390169689Skan DONE; 2391169689Skan } 2392169689Skan}) 2393169689Skan 2394169689Skan(define_insn "*zero_extend<SHORT:mode><GPR:mode>2" 2395169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2396169689Skan (zero_extend:GPR 2397169689Skan (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))] 2398169689Skan "!TARGET_MIPS16" 2399169689Skan "@ 2400169689Skan andi\t%0,%1,<SHORT:mask> 2401169689Skan l<SHORT:size>u\t%0,%1" 2402169689Skan [(set_attr "type" "arith,load") 2403169689Skan (set_attr "mode" "<GPR:MODE>")]) 2404169689Skan 2405169689Skan(define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e" 2406169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2407169689Skan (zero_extend:GPR (match_operand:SHORT 1 "register_operand" "0")))] 2408169689Skan "GENERATE_MIPS16E" 2409169689Skan "ze<SHORT:size>\t%0" 2410169689Skan [(set_attr "type" "arith") 2411169689Skan (set_attr "mode" "<GPR:MODE>")]) 2412169689Skan 2413169689Skan(define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16" 2414169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2415169689Skan (zero_extend:GPR (match_operand:SHORT 1 "memory_operand" "m")))] 2416169689Skan "TARGET_MIPS16" 2417169689Skan "l<SHORT:size>u\t%0,%1" 2418169689Skan [(set_attr "type" "load") 2419169689Skan (set_attr "mode" "<GPR:MODE>")]) 2420169689Skan 2421169689Skan(define_expand "zero_extendqihi2" 2422169689Skan [(set (match_operand:HI 0 "register_operand") 2423169689Skan (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand")))] 2424169689Skan "" 2425169689Skan{ 2426169689Skan if (TARGET_MIPS16 && !memory_operand (operands[1], QImode)) 2427169689Skan { 2428169689Skan emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]), 2429169689Skan operands[1])); 2430169689Skan DONE; 2431169689Skan } 2432169689Skan}) 2433169689Skan 2434169689Skan(define_insn "*zero_extendqihi2" 2435169689Skan [(set (match_operand:HI 0 "register_operand" "=d,d") 2436169689Skan (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] 2437169689Skan "!TARGET_MIPS16" 2438169689Skan "@ 2439169689Skan andi\t%0,%1,0x00ff 2440169689Skan lbu\t%0,%1" 2441169689Skan [(set_attr "type" "arith,load") 2442169689Skan (set_attr "mode" "HI")]) 2443169689Skan 2444169689Skan(define_insn "*zero_extendqihi2_mips16" 2445169689Skan [(set (match_operand:HI 0 "register_operand" "=d") 2446169689Skan (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))] 2447169689Skan "TARGET_MIPS16" 2448169689Skan "lbu\t%0,%1" 2449169689Skan [(set_attr "type" "load") 2450169689Skan (set_attr "mode" "HI")]) 2451169689Skan 2452169689Skan;; 2453169689Skan;; .................... 2454169689Skan;; 2455169689Skan;; SIGN EXTENSION 2456169689Skan;; 2457169689Skan;; .................... 2458169689Skan 2459169689Skan;; Extension insns. 2460169689Skan;; Those for integer source operand are ordered widest source type first. 2461169689Skan 2462169689Skan;; When TARGET_64BIT, all SImode integer registers should already be in 2463169689Skan;; sign-extended form (see TRULY_NOOP_TRUNCATION and truncdisi2). We can 2464169689Skan;; therefore get rid of register->register instructions if we constrain 2465169689Skan;; the source to be in the same register as the destination. 2466169689Skan;; 2467169689Skan;; The register alternative has type "arith" so that the pre-reload 2468169689Skan;; scheduler will treat it as a move. This reflects what happens if 2469169689Skan;; the register alternative needs a reload. 2470169689Skan(define_insn_and_split "extendsidi2" 2471169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 2472169689Skan (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,m")))] 2473169689Skan "TARGET_64BIT" 2474169689Skan "@ 2475169689Skan # 2476169689Skan lw\t%0,%1" 2477169689Skan "&& reload_completed && register_operand (operands[1], VOIDmode)" 2478169689Skan [(const_int 0)] 2479169689Skan{ 2480169689Skan emit_note (NOTE_INSN_DELETED); 2481169689Skan DONE; 2482169689Skan} 2483169689Skan [(set_attr "type" "arith,load") 2484169689Skan (set_attr "mode" "DI")]) 2485169689Skan 2486169689Skan(define_expand "extend<SHORT:mode><GPR:mode>2" 2487169689Skan [(set (match_operand:GPR 0 "register_operand") 2488169689Skan (sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))] 2489169689Skan "") 2490169689Skan 2491169689Skan(define_insn "*extend<SHORT:mode><GPR:mode>2_mips16e" 2492169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2493169689Skan (sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand" "0,m")))] 2494169689Skan "GENERATE_MIPS16E" 2495169689Skan "@ 2496169689Skan se<SHORT:size>\t%0 2497169689Skan l<SHORT:size>\t%0,%1" 2498169689Skan [(set_attr "type" "arith,load") 2499169689Skan (set_attr "mode" "<GPR:MODE>")]) 2500169689Skan 2501169689Skan(define_insn_and_split "*extend<SHORT:mode><GPR:mode>2" 2502169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2503169689Skan (sign_extend:GPR 2504169689Skan (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))] 2505169689Skan "!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E" 2506169689Skan "@ 2507169689Skan # 2508169689Skan l<SHORT:size>\t%0,%1" 2509169689Skan "&& reload_completed && REG_P (operands[1])" 2510169689Skan [(set (match_dup 0) (ashift:GPR (match_dup 1) (match_dup 2))) 2511169689Skan (set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))] 2512169689Skan{ 2513169689Skan operands[1] = gen_lowpart (<GPR:MODE>mode, operands[1]); 2514169689Skan operands[2] = GEN_INT (GET_MODE_BITSIZE (<GPR:MODE>mode) 2515169689Skan - GET_MODE_BITSIZE (<SHORT:MODE>mode)); 2516169689Skan} 2517169689Skan [(set_attr "type" "arith,load") 2518169689Skan (set_attr "mode" "<GPR:MODE>") 2519169689Skan (set_attr "length" "8,*")]) 2520169689Skan 2521169689Skan(define_insn "*extend<SHORT:mode><GPR:mode>2_se<SHORT:size>" 2522169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 2523169689Skan (sign_extend:GPR 2524169689Skan (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))] 2525169689Skan "ISA_HAS_SEB_SEH" 2526169689Skan "@ 2527169689Skan se<SHORT:size>\t%0,%1 2528169689Skan l<SHORT:size>\t%0,%1" 2529169689Skan [(set_attr "type" "arith,load") 2530169689Skan (set_attr "mode" "<GPR:MODE>")]) 2531169689Skan 2532169689Skan;; This pattern generates the same code as extendqisi2; split it into 2533169689Skan;; that form after reload. 2534169689Skan(define_insn_and_split "extendqihi2" 2535169689Skan [(set (match_operand:HI 0 "register_operand" "=d,d") 2536169689Skan (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] 2537169689Skan "" 2538169689Skan "#" 2539169689Skan "reload_completed" 2540169689Skan [(set (match_dup 0) (sign_extend:SI (match_dup 1)))] 2541169689Skan { operands[0] = gen_lowpart (SImode, operands[0]); } 2542169689Skan [(set_attr "type" "arith,load") 2543169689Skan (set_attr "mode" "SI") 2544169689Skan (set_attr "length" "8,*")]) 2545169689Skan 2546169689Skan(define_insn "extendsfdf2" 2547169689Skan [(set (match_operand:DF 0 "register_operand" "=f") 2548169689Skan (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] 2549169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" 2550169689Skan "cvt.d.s\t%0,%1" 2551169689Skan [(set_attr "type" "fcvt") 2552169689Skan (set_attr "cnv_mode" "S2D") 2553169689Skan (set_attr "mode" "DF")]) 2554169689Skan 2555169689Skan;; 2556169689Skan;; .................... 2557169689Skan;; 2558169689Skan;; CONVERSIONS 2559169689Skan;; 2560169689Skan;; .................... 2561169689Skan 2562169689Skan(define_expand "fix_truncdfsi2" 2563169689Skan [(set (match_operand:SI 0 "register_operand") 2564169689Skan (fix:SI (match_operand:DF 1 "register_operand")))] 2565169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" 2566169689Skan{ 2567169689Skan if (!ISA_HAS_TRUNC_W) 2568169689Skan { 2569169689Skan emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1])); 2570169689Skan DONE; 2571169689Skan } 2572169689Skan}) 2573169689Skan 2574169689Skan(define_insn "fix_truncdfsi2_insn" 2575169689Skan [(set (match_operand:SI 0 "register_operand" "=f") 2576169689Skan (fix:SI (match_operand:DF 1 "register_operand" "f")))] 2577169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W" 2578169689Skan "trunc.w.d %0,%1" 2579169689Skan [(set_attr "type" "fcvt") 2580169689Skan (set_attr "mode" "DF") 2581169689Skan (set_attr "cnv_mode" "D2I") 2582169689Skan (set_attr "length" "4")]) 2583169689Skan 2584169689Skan(define_insn "fix_truncdfsi2_macro" 2585169689Skan [(set (match_operand:SI 0 "register_operand" "=f") 2586169689Skan (fix:SI (match_operand:DF 1 "register_operand" "f"))) 2587169689Skan (clobber (match_scratch:DF 2 "=d"))] 2588169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W" 2589169689Skan{ 2590169689Skan if (set_nomacro) 2591169689Skan return ".set\tmacro\;trunc.w.d %0,%1,%2\;.set\tnomacro"; 2592169689Skan else 2593169689Skan return "trunc.w.d %0,%1,%2"; 2594169689Skan} 2595169689Skan [(set_attr "type" "fcvt") 2596169689Skan (set_attr "mode" "DF") 2597169689Skan (set_attr "cnv_mode" "D2I") 2598169689Skan (set_attr "length" "36")]) 2599169689Skan 2600169689Skan(define_expand "fix_truncsfsi2" 2601169689Skan [(set (match_operand:SI 0 "register_operand") 2602169689Skan (fix:SI (match_operand:SF 1 "register_operand")))] 2603169689Skan "TARGET_HARD_FLOAT" 2604169689Skan{ 2605169689Skan if (!ISA_HAS_TRUNC_W) 2606169689Skan { 2607169689Skan emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1])); 2608169689Skan DONE; 2609169689Skan } 2610169689Skan}) 2611169689Skan 2612169689Skan(define_insn "fix_truncsfsi2_insn" 2613169689Skan [(set (match_operand:SI 0 "register_operand" "=f") 2614169689Skan (fix:SI (match_operand:SF 1 "register_operand" "f")))] 2615169689Skan "TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W" 2616169689Skan "trunc.w.s %0,%1" 2617169689Skan [(set_attr "type" "fcvt") 2618169689Skan (set_attr "mode" "SF") 2619169689Skan (set_attr "cnv_mode" "S2I") 2620169689Skan (set_attr "length" "4")]) 2621169689Skan 2622169689Skan(define_insn "fix_truncsfsi2_macro" 2623169689Skan [(set (match_operand:SI 0 "register_operand" "=f") 2624169689Skan (fix:SI (match_operand:SF 1 "register_operand" "f"))) 2625169689Skan (clobber (match_scratch:SF 2 "=d"))] 2626169689Skan "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W" 2627169689Skan{ 2628169689Skan if (set_nomacro) 2629169689Skan return ".set\tmacro\;trunc.w.s %0,%1,%2\;.set\tnomacro"; 2630169689Skan else 2631169689Skan return "trunc.w.s %0,%1,%2"; 2632169689Skan} 2633169689Skan [(set_attr "type" "fcvt") 2634169689Skan (set_attr "mode" "SF") 2635169689Skan (set_attr "cnv_mode" "S2I") 2636169689Skan (set_attr "length" "36")]) 2637169689Skan 2638169689Skan 2639169689Skan(define_insn "fix_truncdfdi2" 2640169689Skan [(set (match_operand:DI 0 "register_operand" "=f") 2641169689Skan (fix:DI (match_operand:DF 1 "register_operand" "f")))] 2642169689Skan "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" 2643169689Skan "trunc.l.d %0,%1" 2644169689Skan [(set_attr "type" "fcvt") 2645169689Skan (set_attr "mode" "DF") 2646169689Skan (set_attr "cnv_mode" "D2I") 2647169689Skan (set_attr "length" "4")]) 2648169689Skan 2649169689Skan 2650169689Skan(define_insn "fix_truncsfdi2" 2651169689Skan [(set (match_operand:DI 0 "register_operand" "=f") 2652169689Skan (fix:DI (match_operand:SF 1 "register_operand" "f")))] 2653169689Skan "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" 2654169689Skan "trunc.l.s %0,%1" 2655169689Skan [(set_attr "type" "fcvt") 2656169689Skan (set_attr "mode" "SF") 2657169689Skan (set_attr "cnv_mode" "S2I") 2658169689Skan (set_attr "length" "4")]) 2659169689Skan 2660169689Skan 2661169689Skan(define_insn "floatsidf2" 2662169689Skan [(set (match_operand:DF 0 "register_operand" "=f") 2663169689Skan (float:DF (match_operand:SI 1 "register_operand" "f")))] 2664169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" 2665169689Skan "cvt.d.w\t%0,%1" 2666169689Skan [(set_attr "type" "fcvt") 2667169689Skan (set_attr "mode" "DF") 2668169689Skan (set_attr "cnv_mode" "I2D") 2669169689Skan (set_attr "length" "4")]) 2670169689Skan 2671169689Skan 2672169689Skan(define_insn "floatdidf2" 2673169689Skan [(set (match_operand:DF 0 "register_operand" "=f") 2674169689Skan (float:DF (match_operand:DI 1 "register_operand" "f")))] 2675169689Skan "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" 2676169689Skan "cvt.d.l\t%0,%1" 2677169689Skan [(set_attr "type" "fcvt") 2678169689Skan (set_attr "mode" "DF") 2679169689Skan (set_attr "cnv_mode" "I2D") 2680169689Skan (set_attr "length" "4")]) 2681169689Skan 2682169689Skan 2683169689Skan(define_insn "floatsisf2" 2684169689Skan [(set (match_operand:SF 0 "register_operand" "=f") 2685169689Skan (float:SF (match_operand:SI 1 "register_operand" "f")))] 2686169689Skan "TARGET_HARD_FLOAT" 2687169689Skan "cvt.s.w\t%0,%1" 2688169689Skan [(set_attr "type" "fcvt") 2689169689Skan (set_attr "mode" "SF") 2690169689Skan (set_attr "cnv_mode" "I2S") 2691169689Skan (set_attr "length" "4")]) 2692169689Skan 2693169689Skan 2694169689Skan(define_insn "floatdisf2" 2695169689Skan [(set (match_operand:SF 0 "register_operand" "=f") 2696169689Skan (float:SF (match_operand:DI 1 "register_operand" "f")))] 2697169689Skan "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" 2698169689Skan "cvt.s.l\t%0,%1" 2699169689Skan [(set_attr "type" "fcvt") 2700169689Skan (set_attr "mode" "SF") 2701169689Skan (set_attr "cnv_mode" "I2S") 2702169689Skan (set_attr "length" "4")]) 2703169689Skan 2704169689Skan 2705169689Skan(define_expand "fixuns_truncdfsi2" 2706169689Skan [(set (match_operand:SI 0 "register_operand") 2707169689Skan (unsigned_fix:SI (match_operand:DF 1 "register_operand")))] 2708169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" 2709169689Skan{ 2710169689Skan rtx reg1 = gen_reg_rtx (DFmode); 2711169689Skan rtx reg2 = gen_reg_rtx (DFmode); 2712169689Skan rtx reg3 = gen_reg_rtx (SImode); 2713169689Skan rtx label1 = gen_label_rtx (); 2714169689Skan rtx label2 = gen_label_rtx (); 2715169689Skan REAL_VALUE_TYPE offset; 2716169689Skan 2717169689Skan real_2expN (&offset, 31); 2718169689Skan 2719169689Skan if (reg1) /* Turn off complaints about unreached code. */ 2720169689Skan { 2721169689Skan emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode)); 2722169689Skan do_pending_stack_adjust (); 2723169689Skan 2724169689Skan emit_insn (gen_cmpdf (operands[1], reg1)); 2725169689Skan emit_jump_insn (gen_bge (label1)); 2726169689Skan 2727169689Skan emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1])); 2728169689Skan emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, 2729169689Skan gen_rtx_LABEL_REF (VOIDmode, label2))); 2730169689Skan emit_barrier (); 2731169689Skan 2732169689Skan emit_label (label1); 2733169689Skan emit_move_insn (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1)); 2734169689Skan emit_move_insn (reg3, GEN_INT (trunc_int_for_mode 2735169689Skan (BITMASK_HIGH, SImode))); 2736169689Skan 2737169689Skan emit_insn (gen_fix_truncdfsi2 (operands[0], reg2)); 2738169689Skan emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); 2739169689Skan 2740169689Skan emit_label (label2); 2741169689Skan 2742169689Skan /* Allow REG_NOTES to be set on last insn (labels don't have enough 2743169689Skan fields, and can't be used for REG_NOTES anyway). */ 2744169689Skan emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); 2745169689Skan DONE; 2746169689Skan } 2747169689Skan}) 2748169689Skan 2749169689Skan 2750169689Skan(define_expand "fixuns_truncdfdi2" 2751169689Skan [(set (match_operand:DI 0 "register_operand") 2752169689Skan (unsigned_fix:DI (match_operand:DF 1 "register_operand")))] 2753169689Skan "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" 2754169689Skan{ 2755169689Skan rtx reg1 = gen_reg_rtx (DFmode); 2756169689Skan rtx reg2 = gen_reg_rtx (DFmode); 2757169689Skan rtx reg3 = gen_reg_rtx (DImode); 2758169689Skan rtx label1 = gen_label_rtx (); 2759169689Skan rtx label2 = gen_label_rtx (); 2760169689Skan REAL_VALUE_TYPE offset; 2761169689Skan 2762169689Skan real_2expN (&offset, 63); 2763169689Skan 2764169689Skan emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode)); 2765169689Skan do_pending_stack_adjust (); 2766169689Skan 2767169689Skan emit_insn (gen_cmpdf (operands[1], reg1)); 2768169689Skan emit_jump_insn (gen_bge (label1)); 2769169689Skan 2770169689Skan emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1])); 2771169689Skan emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, 2772169689Skan gen_rtx_LABEL_REF (VOIDmode, label2))); 2773169689Skan emit_barrier (); 2774169689Skan 2775169689Skan emit_label (label1); 2776169689Skan emit_move_insn (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1)); 2777169689Skan emit_move_insn (reg3, GEN_INT (BITMASK_HIGH)); 2778169689Skan emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32))); 2779169689Skan 2780169689Skan emit_insn (gen_fix_truncdfdi2 (operands[0], reg2)); 2781169689Skan emit_insn (gen_iordi3 (operands[0], operands[0], reg3)); 2782169689Skan 2783169689Skan emit_label (label2); 2784169689Skan 2785169689Skan /* Allow REG_NOTES to be set on last insn (labels don't have enough 2786169689Skan fields, and can't be used for REG_NOTES anyway). */ 2787169689Skan emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); 2788169689Skan DONE; 2789169689Skan}) 2790169689Skan 2791169689Skan 2792169689Skan(define_expand "fixuns_truncsfsi2" 2793169689Skan [(set (match_operand:SI 0 "register_operand") 2794169689Skan (unsigned_fix:SI (match_operand:SF 1 "register_operand")))] 2795169689Skan "TARGET_HARD_FLOAT" 2796169689Skan{ 2797169689Skan rtx reg1 = gen_reg_rtx (SFmode); 2798169689Skan rtx reg2 = gen_reg_rtx (SFmode); 2799169689Skan rtx reg3 = gen_reg_rtx (SImode); 2800169689Skan rtx label1 = gen_label_rtx (); 2801169689Skan rtx label2 = gen_label_rtx (); 2802169689Skan REAL_VALUE_TYPE offset; 2803169689Skan 2804169689Skan real_2expN (&offset, 31); 2805169689Skan 2806169689Skan emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode)); 2807169689Skan do_pending_stack_adjust (); 2808169689Skan 2809169689Skan emit_insn (gen_cmpsf (operands[1], reg1)); 2810169689Skan emit_jump_insn (gen_bge (label1)); 2811169689Skan 2812169689Skan emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1])); 2813169689Skan emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, 2814169689Skan gen_rtx_LABEL_REF (VOIDmode, label2))); 2815169689Skan emit_barrier (); 2816169689Skan 2817169689Skan emit_label (label1); 2818169689Skan emit_move_insn (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1)); 2819169689Skan emit_move_insn (reg3, GEN_INT (trunc_int_for_mode 2820169689Skan (BITMASK_HIGH, SImode))); 2821169689Skan 2822169689Skan emit_insn (gen_fix_truncsfsi2 (operands[0], reg2)); 2823169689Skan emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); 2824169689Skan 2825169689Skan emit_label (label2); 2826169689Skan 2827169689Skan /* Allow REG_NOTES to be set on last insn (labels don't have enough 2828169689Skan fields, and can't be used for REG_NOTES anyway). */ 2829169689Skan emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); 2830169689Skan DONE; 2831169689Skan}) 2832169689Skan 2833169689Skan 2834169689Skan(define_expand "fixuns_truncsfdi2" 2835169689Skan [(set (match_operand:DI 0 "register_operand") 2836169689Skan (unsigned_fix:DI (match_operand:SF 1 "register_operand")))] 2837169689Skan "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" 2838169689Skan{ 2839169689Skan rtx reg1 = gen_reg_rtx (SFmode); 2840169689Skan rtx reg2 = gen_reg_rtx (SFmode); 2841169689Skan rtx reg3 = gen_reg_rtx (DImode); 2842169689Skan rtx label1 = gen_label_rtx (); 2843169689Skan rtx label2 = gen_label_rtx (); 2844169689Skan REAL_VALUE_TYPE offset; 2845169689Skan 2846169689Skan real_2expN (&offset, 63); 2847169689Skan 2848169689Skan emit_move_insn (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode)); 2849169689Skan do_pending_stack_adjust (); 2850169689Skan 2851169689Skan emit_insn (gen_cmpsf (operands[1], reg1)); 2852169689Skan emit_jump_insn (gen_bge (label1)); 2853169689Skan 2854169689Skan emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1])); 2855169689Skan emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, 2856169689Skan gen_rtx_LABEL_REF (VOIDmode, label2))); 2857169689Skan emit_barrier (); 2858169689Skan 2859169689Skan emit_label (label1); 2860169689Skan emit_move_insn (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1)); 2861169689Skan emit_move_insn (reg3, GEN_INT (BITMASK_HIGH)); 2862169689Skan emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32))); 2863169689Skan 2864169689Skan emit_insn (gen_fix_truncsfdi2 (operands[0], reg2)); 2865169689Skan emit_insn (gen_iordi3 (operands[0], operands[0], reg3)); 2866169689Skan 2867169689Skan emit_label (label2); 2868169689Skan 2869169689Skan /* Allow REG_NOTES to be set on last insn (labels don't have enough 2870169689Skan fields, and can't be used for REG_NOTES anyway). */ 2871169689Skan emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); 2872169689Skan DONE; 2873169689Skan}) 2874169689Skan 2875169689Skan;; 2876169689Skan;; .................... 2877169689Skan;; 2878169689Skan;; DATA MOVEMENT 2879169689Skan;; 2880169689Skan;; .................... 2881169689Skan 2882169689Skan;; Bit field extract patterns which use lwl/lwr or ldl/ldr. 2883169689Skan 2884169689Skan(define_expand "extv" 2885169689Skan [(set (match_operand 0 "register_operand") 2886169689Skan (sign_extract (match_operand:QI 1 "memory_operand") 2887169689Skan (match_operand 2 "immediate_operand") 2888169689Skan (match_operand 3 "immediate_operand")))] 2889169689Skan "!TARGET_MIPS16" 2890169689Skan{ 2891169689Skan if (mips_expand_unaligned_load (operands[0], operands[1], 2892169689Skan INTVAL (operands[2]), 2893169689Skan INTVAL (operands[3]))) 2894169689Skan DONE; 2895169689Skan else 2896169689Skan FAIL; 2897169689Skan}) 2898169689Skan 2899169689Skan(define_expand "extzv" 2900169689Skan [(set (match_operand 0 "register_operand") 2901169689Skan (zero_extract (match_operand 1 "nonimmediate_operand") 2902169689Skan (match_operand 2 "immediate_operand") 2903169689Skan (match_operand 3 "immediate_operand")))] 2904169689Skan "!TARGET_MIPS16" 2905169689Skan{ 2906169689Skan if (mips_expand_unaligned_load (operands[0], operands[1], 2907169689Skan INTVAL (operands[2]), 2908169689Skan INTVAL (operands[3]))) 2909169689Skan DONE; 2910169689Skan else if (mips_use_ins_ext_p (operands[1], operands[2], operands[3])) 2911169689Skan { 2912169689Skan if (GET_MODE (operands[0]) == DImode) 2913169689Skan emit_insn (gen_extzvdi (operands[0], operands[1], operands[2], 2914169689Skan operands[3])); 2915169689Skan else 2916169689Skan emit_insn (gen_extzvsi (operands[0], operands[1], operands[2], 2917169689Skan operands[3])); 2918169689Skan DONE; 2919169689Skan } 2920169689Skan else 2921169689Skan FAIL; 2922169689Skan}) 2923169689Skan 2924169689Skan(define_insn "extzv<mode>" 2925169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2926169689Skan (zero_extract:GPR (match_operand:GPR 1 "register_operand" "d") 2927169689Skan (match_operand:SI 2 "immediate_operand" "I") 2928169689Skan (match_operand:SI 3 "immediate_operand" "I")))] 2929169689Skan "mips_use_ins_ext_p (operands[1], operands[2], operands[3])" 2930169689Skan "<d>ext\t%0,%1,%3,%2" 2931169689Skan [(set_attr "type" "arith") 2932169689Skan (set_attr "mode" "<MODE>")]) 2933169689Skan 2934169689Skan 2935169689Skan(define_expand "insv" 2936169689Skan [(set (zero_extract (match_operand 0 "nonimmediate_operand") 2937169689Skan (match_operand 1 "immediate_operand") 2938169689Skan (match_operand 2 "immediate_operand")) 2939169689Skan (match_operand 3 "reg_or_0_operand"))] 2940169689Skan "!TARGET_MIPS16" 2941169689Skan{ 2942169689Skan if (mips_expand_unaligned_store (operands[0], operands[3], 2943169689Skan INTVAL (operands[1]), 2944169689Skan INTVAL (operands[2]))) 2945169689Skan DONE; 2946169689Skan else if (mips_use_ins_ext_p (operands[0], operands[1], operands[2])) 2947169689Skan { 2948169689Skan if (GET_MODE (operands[0]) == DImode) 2949169689Skan emit_insn (gen_insvdi (operands[0], operands[1], operands[2], 2950169689Skan operands[3])); 2951169689Skan else 2952169689Skan emit_insn (gen_insvsi (operands[0], operands[1], operands[2], 2953169689Skan operands[3])); 2954169689Skan DONE; 2955169689Skan } 2956169689Skan else 2957169689Skan FAIL; 2958169689Skan}) 2959169689Skan 2960169689Skan(define_insn "insv<mode>" 2961169689Skan [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+d") 2962169689Skan (match_operand:SI 1 "immediate_operand" "I") 2963169689Skan (match_operand:SI 2 "immediate_operand" "I")) 2964169689Skan (match_operand:GPR 3 "reg_or_0_operand" "dJ"))] 2965169689Skan "mips_use_ins_ext_p (operands[0], operands[1], operands[2])" 2966169689Skan "<d>ins\t%0,%z3,%2,%1" 2967169689Skan [(set_attr "type" "arith") 2968169689Skan (set_attr "mode" "<MODE>")]) 2969169689Skan 2970169689Skan;; Unaligned word moves generated by the bit field patterns. 2971169689Skan;; 2972169689Skan;; As far as the rtl is concerned, both the left-part and right-part 2973169689Skan;; instructions can access the whole field. However, the real operand 2974169689Skan;; refers to just the first or the last byte (depending on endianness). 2975169689Skan;; We therefore use two memory operands to each instruction, one to 2976169689Skan;; describe the rtl effect and one to use in the assembly output. 2977169689Skan;; 2978169689Skan;; Operands 0 and 1 are the rtl-level target and source respectively. 2979169689Skan;; This allows us to use the standard length calculations for the "load" 2980169689Skan;; and "store" type attributes. 2981169689Skan 2982169689Skan(define_insn "mov_<load>l" 2983169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2984169689Skan (unspec:GPR [(match_operand:BLK 1 "memory_operand" "m") 2985169689Skan (match_operand:QI 2 "memory_operand" "m")] 2986169689Skan UNSPEC_LOAD_LEFT))] 2987169689Skan "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])" 2988169689Skan "<load>l\t%0,%2" 2989169689Skan [(set_attr "type" "load") 2990169689Skan (set_attr "mode" "<MODE>")]) 2991169689Skan 2992169689Skan(define_insn "mov_<load>r" 2993169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 2994169689Skan (unspec:GPR [(match_operand:BLK 1 "memory_operand" "m") 2995169689Skan (match_operand:QI 2 "memory_operand" "m") 2996169689Skan (match_operand:GPR 3 "register_operand" "0")] 2997169689Skan UNSPEC_LOAD_RIGHT))] 2998169689Skan "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])" 2999169689Skan "<load>r\t%0,%2" 3000169689Skan [(set_attr "type" "load") 3001169689Skan (set_attr "mode" "<MODE>")]) 3002169689Skan 3003169689Skan(define_insn "mov_<store>l" 3004169689Skan [(set (match_operand:BLK 0 "memory_operand" "=m") 3005169689Skan (unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ") 3006169689Skan (match_operand:QI 2 "memory_operand" "m")] 3007169689Skan UNSPEC_STORE_LEFT))] 3008169689Skan "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])" 3009169689Skan "<store>l\t%z1,%2" 3010169689Skan [(set_attr "type" "store") 3011169689Skan (set_attr "mode" "<MODE>")]) 3012169689Skan 3013169689Skan(define_insn "mov_<store>r" 3014169689Skan [(set (match_operand:BLK 0 "memory_operand" "+m") 3015169689Skan (unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ") 3016169689Skan (match_operand:QI 2 "memory_operand" "m") 3017169689Skan (match_dup 0)] 3018169689Skan UNSPEC_STORE_RIGHT))] 3019169689Skan "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])" 3020169689Skan "<store>r\t%z1,%2" 3021169689Skan [(set_attr "type" "store") 3022169689Skan (set_attr "mode" "<MODE>")]) 3023169689Skan 3024169689Skan;; An instruction to calculate the high part of a 64-bit SYMBOL_GENERAL. 3025169689Skan;; The required value is: 3026169689Skan;; 3027169689Skan;; (%highest(op1) << 48) + (%higher(op1) << 32) + (%hi(op1) << 16) 3028169689Skan;; 3029169689Skan;; which translates to: 3030169689Skan;; 3031169689Skan;; lui op0,%highest(op1) 3032169689Skan;; daddiu op0,op0,%higher(op1) 3033169689Skan;; dsll op0,op0,16 3034169689Skan;; daddiu op0,op0,%hi(op1) 3035169689Skan;; dsll op0,op0,16 3036169689Skan;; 3037169689Skan;; The split is deferred until after flow2 to allow the peephole2 below 3038169689Skan;; to take effect. 3039169689Skan(define_insn_and_split "*lea_high64" 3040169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 3041169689Skan (high:DI (match_operand:DI 1 "general_symbolic_operand" "")))] 3042169689Skan "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS" 3043169689Skan "#" 3044169689Skan "&& flow2_completed" 3045169689Skan [(set (match_dup 0) (high:DI (match_dup 2))) 3046169689Skan (set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 2))) 3047169689Skan (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16))) 3048169689Skan (set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3))) 3049169689Skan (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16)))] 3050169689Skan{ 3051169689Skan operands[2] = mips_unspec_address (operands[1], SYMBOL_64_HIGH); 3052169689Skan operands[3] = mips_unspec_address (operands[1], SYMBOL_64_MID); 3053169689Skan} 3054169689Skan [(set_attr "length" "20")]) 3055169689Skan 3056169689Skan;; Use a scratch register to reduce the latency of the above pattern 3057169689Skan;; on superscalar machines. The optimized sequence is: 3058169689Skan;; 3059169689Skan;; lui op1,%highest(op2) 3060169689Skan;; lui op0,%hi(op2) 3061169689Skan;; daddiu op1,op1,%higher(op2) 3062169689Skan;; dsll32 op1,op1,0 3063169689Skan;; daddu op1,op1,op0 3064169689Skan(define_peephole2 3065169689Skan [(set (match_operand:DI 1 "register_operand") 3066169689Skan (high:DI (match_operand:DI 2 "general_symbolic_operand"))) 3067169689Skan (match_scratch:DI 0 "d")] 3068169689Skan "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS" 3069169689Skan [(set (match_dup 1) (high:DI (match_dup 3))) 3070169689Skan (set (match_dup 0) (high:DI (match_dup 4))) 3071169689Skan (set (match_dup 1) (lo_sum:DI (match_dup 1) (match_dup 3))) 3072169689Skan (set (match_dup 1) (ashift:DI (match_dup 1) (const_int 32))) 3073169689Skan (set (match_dup 1) (plus:DI (match_dup 1) (match_dup 0)))] 3074169689Skan{ 3075169689Skan operands[3] = mips_unspec_address (operands[2], SYMBOL_64_HIGH); 3076169689Skan operands[4] = mips_unspec_address (operands[2], SYMBOL_64_LOW); 3077169689Skan}) 3078169689Skan 3079169689Skan;; On most targets, the expansion of (lo_sum (high X) X) for a 64-bit 3080169689Skan;; SYMBOL_GENERAL X will take 6 cycles. This next pattern allows combine 3081169689Skan;; to merge the HIGH and LO_SUM parts of a move if the HIGH part is only 3082169689Skan;; used once. We can then use the sequence: 3083169689Skan;; 3084169689Skan;; lui op0,%highest(op1) 3085169689Skan;; lui op2,%hi(op1) 3086169689Skan;; daddiu op0,op0,%higher(op1) 3087169689Skan;; daddiu op2,op2,%lo(op1) 3088169689Skan;; dsll32 op0,op0,0 3089169689Skan;; daddu op0,op0,op2 3090169689Skan;; 3091169689Skan;; which takes 4 cycles on most superscalar targets. 3092169689Skan(define_insn_and_split "*lea64" 3093169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 3094169689Skan (match_operand:DI 1 "general_symbolic_operand" "")) 3095169689Skan (clobber (match_scratch:DI 2 "=&d"))] 3096169689Skan "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS && cse_not_expected" 3097169689Skan "#" 3098169689Skan "&& reload_completed" 3099169689Skan [(set (match_dup 0) (high:DI (match_dup 3))) 3100169689Skan (set (match_dup 2) (high:DI (match_dup 4))) 3101169689Skan (set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3))) 3102169689Skan (set (match_dup 2) (lo_sum:DI (match_dup 2) (match_dup 4))) 3103169689Skan (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32))) 3104169689Skan (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))] 3105169689Skan{ 3106169689Skan operands[3] = mips_unspec_address (operands[1], SYMBOL_64_HIGH); 3107169689Skan operands[4] = mips_unspec_address (operands[1], SYMBOL_64_LOW); 3108169689Skan} 3109169689Skan [(set_attr "length" "24")]) 3110169689Skan 3111169689Skan;; Insns to fetch a global symbol from a big GOT. 3112169689Skan 3113169689Skan(define_insn_and_split "*xgot_hi<mode>" 3114169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3115169689Skan (high:P (match_operand:P 1 "global_got_operand" "")))] 3116169689Skan "TARGET_EXPLICIT_RELOCS && TARGET_XGOT" 3117169689Skan "#" 3118169689Skan "&& reload_completed" 3119169689Skan [(set (match_dup 0) (high:P (match_dup 2))) 3120169689Skan (set (match_dup 0) (plus:P (match_dup 0) (match_dup 3)))] 3121169689Skan{ 3122169689Skan operands[2] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_GLOBAL); 3123169689Skan operands[3] = pic_offset_table_rtx; 3124169689Skan} 3125169689Skan [(set_attr "got" "xgot_high") 3126169689Skan (set_attr "mode" "<MODE>")]) 3127169689Skan 3128169689Skan(define_insn_and_split "*xgot_lo<mode>" 3129169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3130169689Skan (lo_sum:P (match_operand:P 1 "register_operand" "d") 3131169689Skan (match_operand:P 2 "global_got_operand" "")))] 3132169689Skan "TARGET_EXPLICIT_RELOCS && TARGET_XGOT" 3133169689Skan "#" 3134169689Skan "&& reload_completed" 3135169689Skan [(set (match_dup 0) 3136169689Skan (unspec:P [(match_dup 1) (match_dup 3)] UNSPEC_LOAD_GOT))] 3137169689Skan { operands[3] = mips_unspec_address (operands[2], SYMBOL_GOTOFF_GLOBAL); } 3138169689Skan [(set_attr "got" "load") 3139169689Skan (set_attr "mode" "<MODE>")]) 3140169689Skan 3141169689Skan;; Insns to fetch a global symbol from a normal GOT. 3142169689Skan 3143169689Skan(define_insn_and_split "*got_disp<mode>" 3144169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3145169689Skan (match_operand:P 1 "global_got_operand" ""))] 3146169689Skan "TARGET_EXPLICIT_RELOCS && !TARGET_XGOT" 3147169689Skan "#" 3148169689Skan "&& reload_completed" 3149169689Skan [(set (match_dup 0) 3150169689Skan (unspec:P [(match_dup 2) (match_dup 3)] UNSPEC_LOAD_GOT))] 3151169689Skan{ 3152169689Skan operands[2] = pic_offset_table_rtx; 3153169689Skan operands[3] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_GLOBAL); 3154169689Skan} 3155169689Skan [(set_attr "got" "load") 3156169689Skan (set_attr "mode" "<MODE>")]) 3157169689Skan 3158169689Skan;; Insns for loading the high part of a local symbol. 3159169689Skan 3160169689Skan(define_insn_and_split "*got_page<mode>" 3161169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3162169689Skan (high:P (match_operand:P 1 "local_got_operand" "")))] 3163169689Skan "TARGET_EXPLICIT_RELOCS" 3164169689Skan "#" 3165169689Skan "&& reload_completed" 3166169689Skan [(set (match_dup 0) 3167169689Skan (unspec:P [(match_dup 2) (match_dup 3)] UNSPEC_LOAD_GOT))] 3168169689Skan{ 3169169689Skan operands[2] = pic_offset_table_rtx; 3170169689Skan operands[3] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_PAGE); 3171169689Skan} 3172169689Skan [(set_attr "got" "load") 3173169689Skan (set_attr "mode" "<MODE>")]) 3174169689Skan 3175169689Skan;; Lower-level instructions for loading an address from the GOT. 3176169689Skan;; We could use MEMs, but an unspec gives more optimization 3177169689Skan;; opportunities. 3178169689Skan 3179169689Skan(define_insn "load_got<mode>" 3180169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3181169689Skan (unspec:P [(match_operand:P 1 "register_operand" "d") 3182169689Skan (match_operand:P 2 "immediate_operand" "")] 3183169689Skan UNSPEC_LOAD_GOT))] 3184169689Skan "" 3185169689Skan "<load>\t%0,%R2(%1)" 3186169689Skan [(set_attr "type" "load") 3187169689Skan (set_attr "mode" "<MODE>") 3188169689Skan (set_attr "length" "4")]) 3189169689Skan 3190169689Skan;; Instructions for adding the low 16 bits of an address to a register. 3191169689Skan;; Operand 2 is the address: print_operand works out which relocation 3192169689Skan;; should be applied. 3193169689Skan 3194169689Skan(define_insn "*low<mode>" 3195169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3196169689Skan (lo_sum:P (match_operand:P 1 "register_operand" "d") 3197169689Skan (match_operand:P 2 "immediate_operand" "")))] 3198169689Skan "!TARGET_MIPS16" 3199169689Skan "<d>addiu\t%0,%1,%R2" 3200169689Skan [(set_attr "type" "arith") 3201169689Skan (set_attr "mode" "<MODE>")]) 3202169689Skan 3203169689Skan(define_insn "*low<mode>_mips16" 3204169689Skan [(set (match_operand:P 0 "register_operand" "=d") 3205169689Skan (lo_sum:P (match_operand:P 1 "register_operand" "0") 3206169689Skan (match_operand:P 2 "immediate_operand" "")))] 3207169689Skan "TARGET_MIPS16" 3208169689Skan "<d>addiu\t%0,%R2" 3209169689Skan [(set_attr "type" "arith") 3210169689Skan (set_attr "mode" "<MODE>") 3211169689Skan (set_attr "length" "8")]) 3212169689Skan 3213169689Skan;; Allow combine to split complex const_int load sequences, using operand 2 3214169689Skan;; to store the intermediate results. See move_operand for details. 3215169689Skan(define_split 3216169689Skan [(set (match_operand:GPR 0 "register_operand") 3217169689Skan (match_operand:GPR 1 "splittable_const_int_operand")) 3218169689Skan (clobber (match_operand:GPR 2 "register_operand"))] 3219169689Skan "" 3220169689Skan [(const_int 0)] 3221169689Skan{ 3222169689Skan mips_move_integer (operands[0], operands[2], INTVAL (operands[1])); 3223169689Skan DONE; 3224169689Skan}) 3225169689Skan 3226169689Skan;; Likewise, for symbolic operands. 3227169689Skan(define_split 3228169689Skan [(set (match_operand:P 0 "register_operand") 3229169689Skan (match_operand:P 1 "splittable_symbolic_operand")) 3230169689Skan (clobber (match_operand:P 2 "register_operand"))] 3231169689Skan "" 3232169689Skan [(set (match_dup 0) (match_dup 1))] 3233169689Skan { operands[1] = mips_split_symbol (operands[2], operands[1]); }) 3234169689Skan 3235169689Skan;; 64-bit integer moves 3236169689Skan 3237169689Skan;; Unlike most other insns, the move insns can't be split with 3238169689Skan;; different predicates, because register spilling and other parts of 3239169689Skan;; the compiler, have memoized the insn number already. 3240169689Skan 3241169689Skan(define_expand "movdi" 3242169689Skan [(set (match_operand:DI 0 "") 3243169689Skan (match_operand:DI 1 ""))] 3244169689Skan "" 3245169689Skan{ 3246169689Skan if (mips_legitimize_move (DImode, operands[0], operands[1])) 3247169689Skan DONE; 3248169689Skan}) 3249169689Skan 3250169689Skan;; For mips16, we need a special case to handle storing $31 into 3251169689Skan;; memory, since we don't have a constraint to match $31. This 3252169689Skan;; instruction can be generated by save_restore_insns. 3253169689Skan 3254169689Skan(define_insn "*mov<mode>_ra" 3255169689Skan [(set (match_operand:GPR 0 "stack_operand" "=m") 3256169689Skan (reg:GPR 31))] 3257169689Skan "TARGET_MIPS16" 3258169689Skan "<store>\t$31,%0" 3259169689Skan [(set_attr "type" "store") 3260169689Skan (set_attr "mode" "<MODE>")]) 3261169689Skan 3262169689Skan(define_insn "*movdi_32bit" 3263169689Skan [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*B*C*D,*B*C*D,*d,*m") 3264169689Skan (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))] 3265169689Skan "!TARGET_64BIT && !TARGET_MIPS16 3266169689Skan && (register_operand (operands[0], DImode) 3267169689Skan || reg_or_0_operand (operands[1], DImode))" 3268169689Skan { return mips_output_move (operands[0], operands[1]); } 3269169689Skan [(set_attr "type" "arith,arith,load,store,mthilo,mfhilo,xfer,load,xfer,store") 3270169689Skan (set_attr "mode" "DI") 3271169689Skan (set_attr "length" "8,16,*,*,8,8,8,*,8,*")]) 3272169689Skan 3273169689Skan(define_insn "*movdi_32bit_mips16" 3274169689Skan [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") 3275169689Skan (match_operand:DI 1 "move_operand" "d,d,y,K,N,m,d,*x"))] 3276169689Skan "!TARGET_64BIT && TARGET_MIPS16 3277169689Skan && (register_operand (operands[0], DImode) 3278169689Skan || register_operand (operands[1], DImode))" 3279169689Skan { return mips_output_move (operands[0], operands[1]); } 3280169689Skan [(set_attr "type" "arith,arith,arith,arith,arith,load,store,mfhilo") 3281169689Skan (set_attr "mode" "DI") 3282169689Skan (set_attr "length" "8,8,8,8,12,*,*,8")]) 3283169689Skan 3284169689Skan(define_insn "*movdi_64bit" 3285169689Skan [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*x,*B*C*D,*B*C*D,*d,*m") 3286169689Skan (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*J*d,*d,*m,*B*C*D,*B*C*D"))] 3287169689Skan "TARGET_64BIT && !TARGET_MIPS16 3288169689Skan && (register_operand (operands[0], DImode) 3289169689Skan || reg_or_0_operand (operands[1], DImode))" 3290169689Skan { return mips_output_move (operands[0], operands[1]); } 3291169689Skan [(set_attr "type" "arith,const,const,load,store,fmove,xfer,fpload,xfer,fpstore,mthilo,xfer,load,xfer,store") 3292169689Skan (set_attr "mode" "DI") 3293169689Skan (set_attr "length" "4,*,*,*,*,4,4,*,4,*,4,8,*,8,*")]) 3294169689Skan 3295169689Skan(define_insn "*movdi_64bit_mips16" 3296169689Skan [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,m") 3297169689Skan (match_operand:DI 1 "move_operand" "d,d,y,K,N,U,m,d"))] 3298169689Skan "TARGET_64BIT && TARGET_MIPS16 3299169689Skan && (register_operand (operands[0], DImode) 3300169689Skan || register_operand (operands[1], DImode))" 3301169689Skan { return mips_output_move (operands[0], operands[1]); } 3302169689Skan [(set_attr "type" "arith,arith,arith,arith,arith,const,load,store") 3303169689Skan (set_attr "mode" "DI") 3304169689Skan (set_attr_alternative "length" 3305169689Skan [(const_int 4) 3306169689Skan (const_int 4) 3307169689Skan (const_int 4) 3308169689Skan (if_then_else (match_operand:VOID 1 "m16_uimm8_1") 3309169689Skan (const_int 4) 3310169689Skan (const_int 8)) 3311169689Skan (if_then_else (match_operand:VOID 1 "m16_nuimm8_1") 3312169689Skan (const_int 8) 3313169689Skan (const_int 12)) 3314169689Skan (const_string "*") 3315169689Skan (const_string "*") 3316169689Skan (const_string "*")])]) 3317169689Skan 3318169689Skan 3319169689Skan;; On the mips16, we can split ld $r,N($r) into an add and a load, 3320169689Skan;; when the original load is a 4 byte instruction but the add and the 3321169689Skan;; load are 2 2 byte instructions. 3322169689Skan 3323169689Skan(define_split 3324169689Skan [(set (match_operand:DI 0 "register_operand") 3325169689Skan (mem:DI (plus:DI (match_dup 0) 3326169689Skan (match_operand:DI 1 "const_int_operand"))))] 3327169689Skan "TARGET_64BIT && TARGET_MIPS16 && reload_completed 3328169689Skan && !TARGET_DEBUG_D_MODE 3329169689Skan && REG_P (operands[0]) 3330169689Skan && M16_REG_P (REGNO (operands[0])) 3331169689Skan && GET_CODE (operands[1]) == CONST_INT 3332169689Skan && ((INTVAL (operands[1]) < 0 3333169689Skan && INTVAL (operands[1]) >= -0x10) 3334169689Skan || (INTVAL (operands[1]) >= 32 * 8 3335169689Skan && INTVAL (operands[1]) <= 31 * 8 + 0x8) 3336169689Skan || (INTVAL (operands[1]) >= 0 3337169689Skan && INTVAL (operands[1]) < 32 * 8 3338169689Skan && (INTVAL (operands[1]) & 7) != 0))" 3339169689Skan [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) 3340169689Skan (set (match_dup 0) (mem:DI (plus:DI (match_dup 0) (match_dup 2))))] 3341169689Skan{ 3342169689Skan HOST_WIDE_INT val = INTVAL (operands[1]); 3343169689Skan 3344169689Skan if (val < 0) 3345169689Skan operands[2] = const0_rtx; 3346169689Skan else if (val >= 32 * 8) 3347169689Skan { 3348169689Skan int off = val & 7; 3349169689Skan 3350169689Skan operands[1] = GEN_INT (0x8 + off); 3351169689Skan operands[2] = GEN_INT (val - off - 0x8); 3352169689Skan } 3353169689Skan else 3354169689Skan { 3355169689Skan int off = val & 7; 3356169689Skan 3357169689Skan operands[1] = GEN_INT (off); 3358169689Skan operands[2] = GEN_INT (val - off); 3359169689Skan } 3360169689Skan}) 3361169689Skan 3362169689Skan;; 32-bit Integer moves 3363169689Skan 3364169689Skan;; Unlike most other insns, the move insns can't be split with 3365169689Skan;; different predicates, because register spilling and other parts of 3366169689Skan;; the compiler, have memoized the insn number already. 3367169689Skan 3368169689Skan(define_expand "movsi" 3369169689Skan [(set (match_operand:SI 0 "") 3370169689Skan (match_operand:SI 1 ""))] 3371169689Skan "" 3372169689Skan{ 3373169689Skan if (mips_legitimize_move (SImode, operands[0], operands[1])) 3374169689Skan DONE; 3375169689Skan}) 3376169689Skan 3377169689Skan;; The difference between these two is whether or not ints are allowed 3378169689Skan;; in FP registers (off by default, use -mdebugh to enable). 3379169689Skan 3380169689Skan(define_insn "*movsi_internal" 3381169689Skan [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m") 3382169689Skan (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*z,*d,*J*d,*A,*d,*m,*B*C*D,*B*C*D"))] 3383169689Skan "!TARGET_MIPS16 3384169689Skan && (register_operand (operands[0], SImode) 3385169689Skan || reg_or_0_operand (operands[1], SImode))" 3386169689Skan { return mips_output_move (operands[0], operands[1]); } 3387169689Skan [(set_attr "type" "arith,const,const,load,store,fmove,xfer,fpload,xfer,fpstore,xfer,xfer,mthilo,mfhilo,xfer,load,xfer,store") 3388169689Skan (set_attr "mode" "SI") 3389169689Skan (set_attr "length" "4,*,*,*,*,4,4,*,4,*,4,4,4,4,4,*,4,*")]) 3390169689Skan 3391169689Skan(define_insn "*movsi_mips16" 3392169689Skan [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,m") 3393169689Skan (match_operand:SI 1 "move_operand" "d,d,y,K,N,U,m,d"))] 3394169689Skan "TARGET_MIPS16 3395169689Skan && (register_operand (operands[0], SImode) 3396169689Skan || register_operand (operands[1], SImode))" 3397169689Skan { return mips_output_move (operands[0], operands[1]); } 3398169689Skan [(set_attr "type" "arith,arith,arith,arith,arith,const,load,store") 3399169689Skan (set_attr "mode" "SI") 3400169689Skan (set_attr_alternative "length" 3401169689Skan [(const_int 4) 3402169689Skan (const_int 4) 3403169689Skan (const_int 4) 3404169689Skan (if_then_else (match_operand:VOID 1 "m16_uimm8_1") 3405169689Skan (const_int 4) 3406169689Skan (const_int 8)) 3407169689Skan (if_then_else (match_operand:VOID 1 "m16_nuimm8_1") 3408169689Skan (const_int 8) 3409169689Skan (const_int 12)) 3410169689Skan (const_string "*") 3411169689Skan (const_string "*") 3412169689Skan (const_string "*")])]) 3413169689Skan 3414169689Skan;; On the mips16, we can split lw $r,N($r) into an add and a load, 3415169689Skan;; when the original load is a 4 byte instruction but the add and the 3416169689Skan;; load are 2 2 byte instructions. 3417169689Skan 3418169689Skan(define_split 3419169689Skan [(set (match_operand:SI 0 "register_operand") 3420169689Skan (mem:SI (plus:SI (match_dup 0) 3421169689Skan (match_operand:SI 1 "const_int_operand"))))] 3422169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 3423169689Skan && REG_P (operands[0]) 3424169689Skan && M16_REG_P (REGNO (operands[0])) 3425169689Skan && GET_CODE (operands[1]) == CONST_INT 3426169689Skan && ((INTVAL (operands[1]) < 0 3427169689Skan && INTVAL (operands[1]) >= -0x80) 3428169689Skan || (INTVAL (operands[1]) >= 32 * 4 3429169689Skan && INTVAL (operands[1]) <= 31 * 4 + 0x7c) 3430169689Skan || (INTVAL (operands[1]) >= 0 3431169689Skan && INTVAL (operands[1]) < 32 * 4 3432169689Skan && (INTVAL (operands[1]) & 3) != 0))" 3433169689Skan [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) 3434169689Skan (set (match_dup 0) (mem:SI (plus:SI (match_dup 0) (match_dup 2))))] 3435169689Skan{ 3436169689Skan HOST_WIDE_INT val = INTVAL (operands[1]); 3437169689Skan 3438169689Skan if (val < 0) 3439169689Skan operands[2] = const0_rtx; 3440169689Skan else if (val >= 32 * 4) 3441169689Skan { 3442169689Skan int off = val & 3; 3443169689Skan 3444169689Skan operands[1] = GEN_INT (0x7c + off); 3445169689Skan operands[2] = GEN_INT (val - off - 0x7c); 3446169689Skan } 3447169689Skan else 3448169689Skan { 3449169689Skan int off = val & 3; 3450169689Skan 3451169689Skan operands[1] = GEN_INT (off); 3452169689Skan operands[2] = GEN_INT (val - off); 3453169689Skan } 3454169689Skan}) 3455169689Skan 3456169689Skan;; On the mips16, we can split a load of certain constants into a load 3457169689Skan;; and an add. This turns a 4 byte instruction into 2 2 byte 3458169689Skan;; instructions. 3459169689Skan 3460169689Skan(define_split 3461169689Skan [(set (match_operand:SI 0 "register_operand") 3462169689Skan (match_operand:SI 1 "const_int_operand"))] 3463169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 3464169689Skan && REG_P (operands[0]) 3465169689Skan && M16_REG_P (REGNO (operands[0])) 3466169689Skan && GET_CODE (operands[1]) == CONST_INT 3467169689Skan && INTVAL (operands[1]) >= 0x100 3468169689Skan && INTVAL (operands[1]) <= 0xff + 0x7f" 3469169689Skan [(set (match_dup 0) (match_dup 1)) 3470169689Skan (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] 3471169689Skan{ 3472169689Skan int val = INTVAL (operands[1]); 3473169689Skan 3474169689Skan operands[1] = GEN_INT (0xff); 3475169689Skan operands[2] = GEN_INT (val - 0xff); 3476169689Skan}) 3477169689Skan 3478169689Skan;; This insn handles moving CCmode values. It's really just a 3479169689Skan;; slightly simplified copy of movsi_internal2, with additional cases 3480169689Skan;; to move a condition register to a general register and to move 3481169689Skan;; between the general registers and the floating point registers. 3482169689Skan 3483169689Skan(define_insn "movcc" 3484169689Skan [(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*m,*d,*f,*f,*f,*m") 3485169689Skan (match_operand:CC 1 "general_operand" "z,*d,*m,*d,*f,*d,*f,*m,*f"))] 3486169689Skan "ISA_HAS_8CC && TARGET_HARD_FLOAT" 3487169689Skan { return mips_output_move (operands[0], operands[1]); } 3488169689Skan [(set_attr "type" "xfer,arith,load,store,xfer,xfer,fmove,fpload,fpstore") 3489169689Skan (set_attr "mode" "SI") 3490169689Skan (set_attr "length" "8,4,*,*,4,4,4,*,*")]) 3491169689Skan 3492169689Skan;; Reload condition code registers. reload_incc and reload_outcc 3493169689Skan;; both handle moves from arbitrary operands into condition code 3494169689Skan;; registers. reload_incc handles the more common case in which 3495169689Skan;; a source operand is constrained to be in a condition-code 3496169689Skan;; register, but has not been allocated to one. 3497169689Skan;; 3498169689Skan;; Sometimes, such as in movcc, we have a CCmode destination whose 3499169689Skan;; constraints do not include 'z'. reload_outcc handles the case 3500169689Skan;; when such an operand is allocated to a condition-code register. 3501169689Skan;; 3502169689Skan;; Note that reloads from a condition code register to some 3503169689Skan;; other location can be done using ordinary moves. Moving 3504169689Skan;; into a GPR takes a single movcc, moving elsewhere takes 3505169689Skan;; two. We can leave these cases to the generic reload code. 3506169689Skan(define_expand "reload_incc" 3507169689Skan [(set (match_operand:CC 0 "fcc_reload_operand" "=z") 3508169689Skan (match_operand:CC 1 "general_operand" "")) 3509169689Skan (clobber (match_operand:TF 2 "register_operand" "=&f"))] 3510169689Skan "ISA_HAS_8CC && TARGET_HARD_FLOAT" 3511169689Skan{ 3512169689Skan mips_emit_fcc_reload (operands[0], operands[1], operands[2]); 3513169689Skan DONE; 3514169689Skan}) 3515169689Skan 3516169689Skan(define_expand "reload_outcc" 3517169689Skan [(set (match_operand:CC 0 "fcc_reload_operand" "=z") 3518169689Skan (match_operand:CC 1 "register_operand" "")) 3519169689Skan (clobber (match_operand:TF 2 "register_operand" "=&f"))] 3520169689Skan "ISA_HAS_8CC && TARGET_HARD_FLOAT" 3521169689Skan{ 3522169689Skan mips_emit_fcc_reload (operands[0], operands[1], operands[2]); 3523169689Skan DONE; 3524169689Skan}) 3525169689Skan 3526169689Skan;; MIPS4 supports loading and storing a floating point register from 3527169689Skan;; the sum of two general registers. We use two versions for each of 3528169689Skan;; these four instructions: one where the two general registers are 3529169689Skan;; SImode, and one where they are DImode. This is because general 3530169689Skan;; registers will be in SImode when they hold 32 bit values, but, 3531169689Skan;; since the 32 bit values are always sign extended, the [ls][wd]xc1 3532169689Skan;; instructions will still work correctly. 3533169689Skan 3534169689Skan;; ??? Perhaps it would be better to support these instructions by 3535169689Skan;; modifying GO_IF_LEGITIMATE_ADDRESS and friends. However, since 3536169689Skan;; these instructions can only be used to load and store floating 3537169689Skan;; point registers, that would probably cause trouble in reload. 3538169689Skan 3539169689Skan(define_insn "*<ANYF:loadx>_<P:mode>" 3540169689Skan [(set (match_operand:ANYF 0 "register_operand" "=f") 3541169689Skan (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d") 3542169689Skan (match_operand:P 2 "register_operand" "d"))))] 3543169689Skan "ISA_HAS_FP4" 3544169689Skan "<ANYF:loadx>\t%0,%1(%2)" 3545169689Skan [(set_attr "type" "fpidxload") 3546169689Skan (set_attr "mode" "<ANYF:UNITMODE>")]) 3547169689Skan 3548169689Skan(define_insn "*<ANYF:storex>_<P:mode>" 3549169689Skan [(set (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d") 3550169689Skan (match_operand:P 2 "register_operand" "d"))) 3551169689Skan (match_operand:ANYF 0 "register_operand" "f"))] 3552169689Skan "ISA_HAS_FP4" 3553169689Skan "<ANYF:storex>\t%0,%1(%2)" 3554169689Skan [(set_attr "type" "fpidxstore") 3555169689Skan (set_attr "mode" "<ANYF:UNITMODE>")]) 3556169689Skan 3557169689Skan;; 16-bit Integer moves 3558169689Skan 3559169689Skan;; Unlike most other insns, the move insns can't be split with 3560169689Skan;; different predicates, because register spilling and other parts of 3561169689Skan;; the compiler, have memoized the insn number already. 3562169689Skan;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND. 3563169689Skan 3564169689Skan(define_expand "movhi" 3565169689Skan [(set (match_operand:HI 0 "") 3566169689Skan (match_operand:HI 1 ""))] 3567169689Skan "" 3568169689Skan{ 3569169689Skan if (mips_legitimize_move (HImode, operands[0], operands[1])) 3570169689Skan DONE; 3571169689Skan}) 3572169689Skan 3573169689Skan(define_insn "*movhi_internal" 3574169689Skan [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x") 3575169689Skan (match_operand:HI 1 "move_operand" "d,I,m,dJ,*f,*d,*f,*d"))] 3576169689Skan "!TARGET_MIPS16 3577169689Skan && (register_operand (operands[0], HImode) 3578169689Skan || reg_or_0_operand (operands[1], HImode))" 3579169689Skan "@ 3580169689Skan move\t%0,%1 3581169689Skan li\t%0,%1 3582169689Skan lhu\t%0,%1 3583169689Skan sh\t%z1,%0 3584169689Skan mfc1\t%0,%1 3585169689Skan mtc1\t%1,%0 3586169689Skan mov.s\t%0,%1 3587169689Skan mt%0\t%1" 3588169689Skan [(set_attr "type" "arith,arith,load,store,xfer,xfer,fmove,mthilo") 3589169689Skan (set_attr "mode" "HI") 3590169689Skan (set_attr "length" "4,4,*,*,4,4,4,4")]) 3591169689Skan 3592169689Skan(define_insn "*movhi_mips16" 3593169689Skan [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m") 3594169689Skan (match_operand:HI 1 "move_operand" "d,d,y,K,N,m,d"))] 3595169689Skan "TARGET_MIPS16 3596169689Skan && (register_operand (operands[0], HImode) 3597169689Skan || register_operand (operands[1], HImode))" 3598169689Skan "@ 3599169689Skan move\t%0,%1 3600169689Skan move\t%0,%1 3601169689Skan move\t%0,%1 3602169689Skan li\t%0,%1 3603169689Skan # 3604169689Skan lhu\t%0,%1 3605169689Skan sh\t%1,%0" 3606169689Skan [(set_attr "type" "arith,arith,arith,arith,arith,load,store") 3607169689Skan (set_attr "mode" "HI") 3608169689Skan (set_attr_alternative "length" 3609169689Skan [(const_int 4) 3610169689Skan (const_int 4) 3611169689Skan (const_int 4) 3612169689Skan (if_then_else (match_operand:VOID 1 "m16_uimm8_1") 3613169689Skan (const_int 4) 3614169689Skan (const_int 8)) 3615169689Skan (if_then_else (match_operand:VOID 1 "m16_nuimm8_1") 3616169689Skan (const_int 8) 3617169689Skan (const_int 12)) 3618169689Skan (const_string "*") 3619169689Skan (const_string "*")])]) 3620169689Skan 3621169689Skan 3622169689Skan;; On the mips16, we can split lh $r,N($r) into an add and a load, 3623169689Skan;; when the original load is a 4 byte instruction but the add and the 3624169689Skan;; load are 2 2 byte instructions. 3625169689Skan 3626169689Skan(define_split 3627169689Skan [(set (match_operand:HI 0 "register_operand") 3628169689Skan (mem:HI (plus:SI (match_dup 0) 3629169689Skan (match_operand:SI 1 "const_int_operand"))))] 3630169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 3631169689Skan && REG_P (operands[0]) 3632169689Skan && M16_REG_P (REGNO (operands[0])) 3633169689Skan && GET_CODE (operands[1]) == CONST_INT 3634169689Skan && ((INTVAL (operands[1]) < 0 3635169689Skan && INTVAL (operands[1]) >= -0x80) 3636169689Skan || (INTVAL (operands[1]) >= 32 * 2 3637169689Skan && INTVAL (operands[1]) <= 31 * 2 + 0x7e) 3638169689Skan || (INTVAL (operands[1]) >= 0 3639169689Skan && INTVAL (operands[1]) < 32 * 2 3640169689Skan && (INTVAL (operands[1]) & 1) != 0))" 3641169689Skan [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) 3642169689Skan (set (match_dup 0) (mem:HI (plus:SI (match_dup 0) (match_dup 2))))] 3643169689Skan{ 3644169689Skan HOST_WIDE_INT val = INTVAL (operands[1]); 3645169689Skan 3646169689Skan if (val < 0) 3647169689Skan operands[2] = const0_rtx; 3648169689Skan else if (val >= 32 * 2) 3649169689Skan { 3650169689Skan int off = val & 1; 3651169689Skan 3652169689Skan operands[1] = GEN_INT (0x7e + off); 3653169689Skan operands[2] = GEN_INT (val - off - 0x7e); 3654169689Skan } 3655169689Skan else 3656169689Skan { 3657169689Skan int off = val & 1; 3658169689Skan 3659169689Skan operands[1] = GEN_INT (off); 3660169689Skan operands[2] = GEN_INT (val - off); 3661169689Skan } 3662169689Skan}) 3663169689Skan 3664169689Skan;; 8-bit Integer moves 3665169689Skan 3666169689Skan;; Unlike most other insns, the move insns can't be split with 3667169689Skan;; different predicates, because register spilling and other parts of 3668169689Skan;; the compiler, have memoized the insn number already. 3669169689Skan;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND. 3670169689Skan 3671169689Skan(define_expand "movqi" 3672169689Skan [(set (match_operand:QI 0 "") 3673169689Skan (match_operand:QI 1 ""))] 3674169689Skan "" 3675169689Skan{ 3676169689Skan if (mips_legitimize_move (QImode, operands[0], operands[1])) 3677169689Skan DONE; 3678169689Skan}) 3679169689Skan 3680169689Skan(define_insn "*movqi_internal" 3681169689Skan [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x") 3682169689Skan (match_operand:QI 1 "move_operand" "d,I,m,dJ,*f,*d,*f,*d"))] 3683169689Skan "!TARGET_MIPS16 3684169689Skan && (register_operand (operands[0], QImode) 3685169689Skan || reg_or_0_operand (operands[1], QImode))" 3686169689Skan "@ 3687169689Skan move\t%0,%1 3688169689Skan li\t%0,%1 3689169689Skan lbu\t%0,%1 3690169689Skan sb\t%z1,%0 3691169689Skan mfc1\t%0,%1 3692169689Skan mtc1\t%1,%0 3693169689Skan mov.s\t%0,%1 3694169689Skan mt%0\t%1" 3695169689Skan [(set_attr "type" "arith,arith,load,store,xfer,xfer,fmove,mthilo") 3696169689Skan (set_attr "mode" "QI") 3697169689Skan (set_attr "length" "4,4,*,*,4,4,4,4")]) 3698169689Skan 3699169689Skan(define_insn "*movqi_mips16" 3700169689Skan [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m") 3701169689Skan (match_operand:QI 1 "move_operand" "d,d,y,K,N,m,d"))] 3702169689Skan "TARGET_MIPS16 3703169689Skan && (register_operand (operands[0], QImode) 3704169689Skan || register_operand (operands[1], QImode))" 3705169689Skan "@ 3706169689Skan move\t%0,%1 3707169689Skan move\t%0,%1 3708169689Skan move\t%0,%1 3709169689Skan li\t%0,%1 3710169689Skan # 3711169689Skan lbu\t%0,%1 3712169689Skan sb\t%1,%0" 3713169689Skan [(set_attr "type" "arith,arith,arith,arith,arith,load,store") 3714169689Skan (set_attr "mode" "QI") 3715169689Skan (set_attr "length" "4,4,4,4,8,*,*")]) 3716169689Skan 3717169689Skan;; On the mips16, we can split lb $r,N($r) into an add and a load, 3718169689Skan;; when the original load is a 4 byte instruction but the add and the 3719169689Skan;; load are 2 2 byte instructions. 3720169689Skan 3721169689Skan(define_split 3722169689Skan [(set (match_operand:QI 0 "register_operand") 3723169689Skan (mem:QI (plus:SI (match_dup 0) 3724169689Skan (match_operand:SI 1 "const_int_operand"))))] 3725169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 3726169689Skan && REG_P (operands[0]) 3727169689Skan && M16_REG_P (REGNO (operands[0])) 3728169689Skan && GET_CODE (operands[1]) == CONST_INT 3729169689Skan && ((INTVAL (operands[1]) < 0 3730169689Skan && INTVAL (operands[1]) >= -0x80) 3731169689Skan || (INTVAL (operands[1]) >= 32 3732169689Skan && INTVAL (operands[1]) <= 31 + 0x7f))" 3733169689Skan [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) 3734169689Skan (set (match_dup 0) (mem:QI (plus:SI (match_dup 0) (match_dup 2))))] 3735169689Skan{ 3736169689Skan HOST_WIDE_INT val = INTVAL (operands[1]); 3737169689Skan 3738169689Skan if (val < 0) 3739169689Skan operands[2] = const0_rtx; 3740169689Skan else 3741169689Skan { 3742169689Skan operands[1] = GEN_INT (0x7f); 3743169689Skan operands[2] = GEN_INT (val - 0x7f); 3744169689Skan } 3745169689Skan}) 3746169689Skan 3747169689Skan;; 32-bit floating point moves 3748169689Skan 3749169689Skan(define_expand "movsf" 3750169689Skan [(set (match_operand:SF 0 "") 3751169689Skan (match_operand:SF 1 ""))] 3752169689Skan "" 3753169689Skan{ 3754169689Skan if (mips_legitimize_move (SFmode, operands[0], operands[1])) 3755169689Skan DONE; 3756169689Skan}) 3757169689Skan 3758169689Skan(define_insn "*movsf_hardfloat" 3759169689Skan [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") 3760169689Skan (match_operand:SF 1 "move_operand" "f,G,m,f,G,*d,*f,*G*d,*m,*d"))] 3761169689Skan "TARGET_HARD_FLOAT 3762169689Skan && (register_operand (operands[0], SFmode) 3763169689Skan || reg_or_0_operand (operands[1], SFmode))" 3764169689Skan { return mips_output_move (operands[0], operands[1]); } 3765169689Skan [(set_attr "type" "fmove,xfer,fpload,fpstore,store,xfer,xfer,arith,load,store") 3766169689Skan (set_attr "mode" "SF") 3767169689Skan (set_attr "length" "4,4,*,*,*,4,4,4,*,*")]) 3768169689Skan 3769169689Skan(define_insn "*movsf_softfloat" 3770169689Skan [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,m") 3771169689Skan (match_operand:SF 1 "move_operand" "Gd,m,d"))] 3772169689Skan "TARGET_SOFT_FLOAT && !TARGET_MIPS16 3773169689Skan && (register_operand (operands[0], SFmode) 3774169689Skan || reg_or_0_operand (operands[1], SFmode))" 3775169689Skan { return mips_output_move (operands[0], operands[1]); } 3776169689Skan [(set_attr "type" "arith,load,store") 3777169689Skan (set_attr "mode" "SF") 3778169689Skan (set_attr "length" "4,*,*")]) 3779169689Skan 3780169689Skan(define_insn "*movsf_mips16" 3781169689Skan [(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,m") 3782169689Skan (match_operand:SF 1 "move_operand" "d,d,y,m,d"))] 3783169689Skan "TARGET_MIPS16 3784169689Skan && (register_operand (operands[0], SFmode) 3785169689Skan || register_operand (operands[1], SFmode))" 3786169689Skan { return mips_output_move (operands[0], operands[1]); } 3787169689Skan [(set_attr "type" "arith,arith,arith,load,store") 3788169689Skan (set_attr "mode" "SF") 3789169689Skan (set_attr "length" "4,4,4,*,*")]) 3790169689Skan 3791169689Skan 3792169689Skan;; 64-bit floating point moves 3793169689Skan 3794169689Skan(define_expand "movdf" 3795169689Skan [(set (match_operand:DF 0 "") 3796169689Skan (match_operand:DF 1 ""))] 3797169689Skan "" 3798169689Skan{ 3799169689Skan if (mips_legitimize_move (DFmode, operands[0], operands[1])) 3800169689Skan DONE; 3801169689Skan}) 3802169689Skan 3803169689Skan(define_insn "*movdf_hardfloat_64bit" 3804169689Skan [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") 3805169689Skan (match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))] 3806169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_64BIT 3807169689Skan && (register_operand (operands[0], DFmode) 3808169689Skan || reg_or_0_operand (operands[1], DFmode))" 3809169689Skan { return mips_output_move (operands[0], operands[1]); } 3810169689Skan [(set_attr "type" "fmove,xfer,fpload,fpstore,store,xfer,xfer,arith,load,store") 3811169689Skan (set_attr "mode" "DF") 3812169689Skan (set_attr "length" "4,4,*,*,*,4,4,4,*,*")]) 3813169689Skan 3814169689Skan(define_insn "*movdf_hardfloat_32bit" 3815169689Skan [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") 3816169689Skan (match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))] 3817169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT 3818169689Skan && (register_operand (operands[0], DFmode) 3819169689Skan || reg_or_0_operand (operands[1], DFmode))" 3820169689Skan { return mips_output_move (operands[0], operands[1]); } 3821169689Skan [(set_attr "type" "fmove,xfer,fpload,fpstore,store,xfer,xfer,arith,load,store") 3822169689Skan (set_attr "mode" "DF") 3823169689Skan (set_attr "length" "4,8,*,*,*,8,8,8,*,*")]) 3824169689Skan 3825169689Skan(define_insn "*movdf_softfloat" 3826169689Skan [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m,d,f,f") 3827169689Skan (match_operand:DF 1 "move_operand" "dG,m,dG,f,d,f"))] 3828169689Skan "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16 3829169689Skan && (register_operand (operands[0], DFmode) 3830169689Skan || reg_or_0_operand (operands[1], DFmode))" 3831169689Skan { return mips_output_move (operands[0], operands[1]); } 3832169689Skan [(set_attr "type" "arith,load,store,xfer,xfer,fmove") 3833169689Skan (set_attr "mode" "DF") 3834169689Skan (set_attr "length" "8,*,*,4,4,4")]) 3835169689Skan 3836169689Skan(define_insn "*movdf_mips16" 3837169689Skan [(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m") 3838169689Skan (match_operand:DF 1 "move_operand" "d,d,y,m,d"))] 3839169689Skan "TARGET_MIPS16 3840169689Skan && (register_operand (operands[0], DFmode) 3841169689Skan || register_operand (operands[1], DFmode))" 3842169689Skan { return mips_output_move (operands[0], operands[1]); } 3843169689Skan [(set_attr "type" "arith,arith,arith,load,store") 3844169689Skan (set_attr "mode" "DF") 3845169689Skan (set_attr "length" "8,8,8,*,*")]) 3846169689Skan 3847169689Skan(define_split 3848169689Skan [(set (match_operand:DI 0 "nonimmediate_operand") 3849169689Skan (match_operand:DI 1 "move_operand"))] 3850169689Skan "reload_completed && !TARGET_64BIT 3851169689Skan && mips_split_64bit_move_p (operands[0], operands[1])" 3852169689Skan [(const_int 0)] 3853169689Skan{ 3854169689Skan mips_split_64bit_move (operands[0], operands[1]); 3855169689Skan DONE; 3856169689Skan}) 3857169689Skan 3858169689Skan(define_split 3859169689Skan [(set (match_operand:DF 0 "nonimmediate_operand") 3860169689Skan (match_operand:DF 1 "move_operand"))] 3861169689Skan "reload_completed && !TARGET_64BIT 3862169689Skan && mips_split_64bit_move_p (operands[0], operands[1])" 3863169689Skan [(const_int 0)] 3864169689Skan{ 3865169689Skan mips_split_64bit_move (operands[0], operands[1]); 3866169689Skan DONE; 3867169689Skan}) 3868169689Skan 3869169689Skan;; When generating mips16 code, split moves of negative constants into 3870169689Skan;; a positive "li" followed by a negation. 3871169689Skan(define_split 3872169689Skan [(set (match_operand 0 "register_operand") 3873169689Skan (match_operand 1 "const_int_operand"))] 3874169689Skan "TARGET_MIPS16 && reload_completed && INTVAL (operands[1]) < 0" 3875169689Skan [(set (match_dup 2) 3876169689Skan (match_dup 3)) 3877169689Skan (set (match_dup 2) 3878169689Skan (neg:SI (match_dup 2)))] 3879169689Skan{ 3880169689Skan operands[2] = gen_lowpart (SImode, operands[0]); 3881169689Skan operands[3] = GEN_INT (-INTVAL (operands[1])); 3882169689Skan}) 3883169689Skan 3884169689Skan;; 64-bit paired-single floating point moves 3885169689Skan 3886169689Skan(define_expand "movv2sf" 3887169689Skan [(set (match_operand:V2SF 0) 3888169689Skan (match_operand:V2SF 1))] 3889169689Skan "TARGET_PAIRED_SINGLE_FLOAT" 3890169689Skan{ 3891169689Skan if (mips_legitimize_move (V2SFmode, operands[0], operands[1])) 3892169689Skan DONE; 3893169689Skan}) 3894169689Skan 3895169689Skan(define_insn "movv2sf_hardfloat_64bit" 3896169689Skan [(set (match_operand:V2SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") 3897169689Skan (match_operand:V2SF 1 "move_operand" "f,YG,m,f,YG,*d,*f,*d*YG,*m,*d"))] 3898169689Skan "TARGET_PAIRED_SINGLE_FLOAT 3899169689Skan && TARGET_64BIT 3900169689Skan && (register_operand (operands[0], V2SFmode) 3901169689Skan || reg_or_0_operand (operands[1], V2SFmode))" 3902169689Skan { return mips_output_move (operands[0], operands[1]); } 3903169689Skan [(set_attr "type" "fmove,xfer,fpload,fpstore,store,xfer,xfer,arith,load,store") 3904169689Skan (set_attr "mode" "SF") 3905169689Skan (set_attr "length" "4,4,*,*,*,4,4,4,*,*")]) 3906169689Skan 3907169689Skan;; The HI and LO registers are not truly independent. If we move an mthi 3908169689Skan;; instruction before an mflo instruction, it will make the result of the 3909169689Skan;; mflo unpredictable. The same goes for mtlo and mfhi. 3910169689Skan;; 3911169689Skan;; We cope with this by making the mflo and mfhi patterns use both HI and LO. 3912169689Skan;; Operand 1 is the register we want, operand 2 is the other one. 3913169689Skan;; 3914169689Skan;; When generating VR4120 or VR4130 code, we use macc{,hi} and 3915169689Skan;; dmacc{,hi} instead of mfhi and mflo. This avoids both the normal 3916169689Skan;; MIPS III hi/lo hazards and the errata related to -mfix-vr4130. 3917169689Skan 3918169689Skan(define_expand "mfhilo_<mode>" 3919169689Skan [(set (match_operand:GPR 0 "register_operand") 3920169689Skan (unspec:GPR [(match_operand:GPR 1 "register_operand") 3921169689Skan (match_operand:GPR 2 "register_operand")] 3922169689Skan UNSPEC_MFHILO))]) 3923169689Skan 3924169689Skan(define_insn "*mfhilo_<mode>" 3925169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 3926169689Skan (unspec:GPR [(match_operand:GPR 1 "register_operand" "h,l") 3927169689Skan (match_operand:GPR 2 "register_operand" "l,h")] 3928169689Skan UNSPEC_MFHILO))] 3929169689Skan "!ISA_HAS_MACCHI" 3930169689Skan "mf%1\t%0" 3931169689Skan [(set_attr "type" "mfhilo") 3932169689Skan (set_attr "mode" "<MODE>")]) 3933169689Skan 3934169689Skan(define_insn "*mfhilo_<mode>_macc" 3935169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 3936169689Skan (unspec:GPR [(match_operand:GPR 1 "register_operand" "h,l") 3937169689Skan (match_operand:GPR 2 "register_operand" "l,h")] 3938169689Skan UNSPEC_MFHILO))] 3939169689Skan "ISA_HAS_MACCHI" 3940169689Skan{ 3941169689Skan if (REGNO (operands[1]) == HI_REGNUM) 3942169689Skan return "<d>macchi\t%0,%.,%."; 3943169689Skan else 3944169689Skan return "<d>macc\t%0,%.,%."; 3945169689Skan} 3946169689Skan [(set_attr "type" "mfhilo") 3947169689Skan (set_attr "mode" "<MODE>")]) 3948169689Skan 3949169689Skan;; Patterns for loading or storing part of a paired floating point 3950169689Skan;; register. We need them because odd-numbered floating-point registers 3951169689Skan;; are not fully independent: see mips_split_64bit_move. 3952169689Skan 3953169689Skan;; Load the low word of operand 0 with operand 1. 3954169689Skan(define_insn "load_df_low" 3955169689Skan [(set (match_operand:DF 0 "register_operand" "=f,f") 3956169689Skan (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")] 3957169689Skan UNSPEC_LOAD_DF_LOW))] 3958169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT" 3959169689Skan{ 3960169689Skan operands[0] = mips_subword (operands[0], 0); 3961169689Skan return mips_output_move (operands[0], operands[1]); 3962169689Skan} 3963169689Skan [(set_attr "type" "xfer,fpload") 3964169689Skan (set_attr "mode" "SF")]) 3965169689Skan 3966169689Skan;; Load the high word of operand 0 from operand 1, preserving the value 3967169689Skan;; in the low word. 3968169689Skan(define_insn "load_df_high" 3969169689Skan [(set (match_operand:DF 0 "register_operand" "=f,f") 3970169689Skan (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m") 3971169689Skan (match_operand:DF 2 "register_operand" "0,0")] 3972169689Skan UNSPEC_LOAD_DF_HIGH))] 3973169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT" 3974169689Skan{ 3975169689Skan operands[0] = mips_subword (operands[0], 1); 3976169689Skan return mips_output_move (operands[0], operands[1]); 3977169689Skan} 3978169689Skan [(set_attr "type" "xfer,fpload") 3979169689Skan (set_attr "mode" "SF")]) 3980169689Skan 3981169689Skan;; Store the high word of operand 1 in operand 0. The corresponding 3982169689Skan;; low-word move is done in the normal way. 3983169689Skan(define_insn "store_df_high" 3984169689Skan [(set (match_operand:SI 0 "nonimmediate_operand" "=d,m") 3985169689Skan (unspec:SI [(match_operand:DF 1 "register_operand" "f,f")] 3986169689Skan UNSPEC_STORE_DF_HIGH))] 3987169689Skan "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT" 3988169689Skan{ 3989169689Skan operands[1] = mips_subword (operands[1], 1); 3990169689Skan return mips_output_move (operands[0], operands[1]); 3991169689Skan} 3992169689Skan [(set_attr "type" "xfer,fpstore") 3993169689Skan (set_attr "mode" "SF")]) 3994169689Skan 3995169689Skan;; Insn to initialize $gp for n32/n64 abicalls. Operand 0 is the offset 3996169689Skan;; of _gp from the start of this function. Operand 1 is the incoming 3997169689Skan;; function address. 3998169689Skan(define_insn_and_split "loadgp" 3999169689Skan [(unspec_volatile [(match_operand 0 "" "") 4000169689Skan (match_operand 1 "register_operand" "")] UNSPEC_LOADGP)] 4001169689Skan "mips_current_loadgp_style () == LOADGP_NEWABI" 4002169689Skan "#" 4003169689Skan "" 4004169689Skan [(set (match_dup 2) (match_dup 3)) 4005169689Skan (set (match_dup 2) (match_dup 4)) 4006169689Skan (set (match_dup 2) (match_dup 5))] 4007169689Skan{ 4008169689Skan operands[2] = pic_offset_table_rtx; 4009169689Skan operands[3] = gen_rtx_HIGH (Pmode, operands[0]); 4010169689Skan operands[4] = gen_rtx_PLUS (Pmode, operands[2], operands[1]); 4011169689Skan operands[5] = gen_rtx_LO_SUM (Pmode, operands[2], operands[0]); 4012169689Skan} 4013169689Skan [(set_attr "length" "12")]) 4014169689Skan 4015169689Skan;; Likewise, for -mno-shared code. Operand 0 is the __gnu_local_gp symbol. 4016169689Skan(define_insn_and_split "loadgp_noshared" 4017169689Skan [(unspec_volatile [(match_operand 0 "" "")] UNSPEC_LOADGP)] 4018169689Skan "mips_current_loadgp_style () == LOADGP_ABSOLUTE" 4019169689Skan "#" 4020169689Skan "" 4021169689Skan [(const_int 0)] 4022169689Skan{ 4023169689Skan emit_move_insn (pic_offset_table_rtx, operands[0]); 4024169689Skan DONE; 4025169689Skan} 4026169689Skan [(set_attr "length" "8")]) 4027169689Skan 4028169689Skan;; The use of gp is hidden when not using explicit relocations. 4029169689Skan;; This blockage instruction prevents the gp load from being 4030169689Skan;; scheduled after an implicit use of gp. It also prevents 4031169689Skan;; the load from being deleted as dead. 4032169689Skan(define_insn "loadgp_blockage" 4033169689Skan [(unspec_volatile [(reg:DI 28)] UNSPEC_BLOCKAGE)] 4034169689Skan "" 4035169689Skan "" 4036169689Skan [(set_attr "type" "unknown") 4037169689Skan (set_attr "mode" "none") 4038169689Skan (set_attr "length" "0")]) 4039169689Skan 4040169689Skan;; Emit a .cprestore directive, which normally expands to a single store 4041169689Skan;; instruction. Note that we continue to use .cprestore for explicit reloc 4042169689Skan;; code so that jals inside inline asms will work correctly. 4043169689Skan(define_insn "cprestore" 4044169689Skan [(unspec_volatile [(match_operand 0 "const_int_operand" "I,i")] 4045169689Skan UNSPEC_CPRESTORE)] 4046169689Skan "" 4047169689Skan{ 4048169689Skan if (set_nomacro && which_alternative == 1) 4049169689Skan return ".set\tmacro\;.cprestore\t%0\;.set\tnomacro"; 4050169689Skan else 4051169689Skan return ".cprestore\t%0"; 4052169689Skan} 4053169689Skan [(set_attr "type" "store") 4054169689Skan (set_attr "length" "4,12")]) 4055169689Skan 4056169689Skan;; Block moves, see mips.c for more details. 4057169689Skan;; Argument 0 is the destination 4058169689Skan;; Argument 1 is the source 4059169689Skan;; Argument 2 is the length 4060169689Skan;; Argument 3 is the alignment 4061169689Skan 4062169689Skan(define_expand "movmemsi" 4063169689Skan [(parallel [(set (match_operand:BLK 0 "general_operand") 4064169689Skan (match_operand:BLK 1 "general_operand")) 4065169689Skan (use (match_operand:SI 2 "")) 4066169689Skan (use (match_operand:SI 3 "const_int_operand"))])] 4067169689Skan "!TARGET_MIPS16 && !TARGET_MEMCPY" 4068169689Skan{ 4069169689Skan if (mips_expand_block_move (operands[0], operands[1], operands[2])) 4070169689Skan DONE; 4071169689Skan else 4072169689Skan FAIL; 4073169689Skan}) 4074169689Skan 4075169689Skan;; 4076169689Skan;; .................... 4077169689Skan;; 4078169689Skan;; SHIFTS 4079169689Skan;; 4080169689Skan;; .................... 4081169689Skan 4082169689Skan(define_expand "<optab><mode>3" 4083169689Skan [(set (match_operand:GPR 0 "register_operand") 4084169689Skan (any_shift:GPR (match_operand:GPR 1 "register_operand") 4085169689Skan (match_operand:SI 2 "arith_operand")))] 4086169689Skan "" 4087169689Skan{ 4088169689Skan /* On the mips16, a shift of more than 8 is a four byte instruction, 4089169689Skan so, for a shift between 8 and 16, it is just as fast to do two 4090169689Skan shifts of 8 or less. If there is a lot of shifting going on, we 4091169689Skan may win in CSE. Otherwise combine will put the shifts back 4092169689Skan together again. This can be called by function_arg, so we must 4093169689Skan be careful not to allocate a new register if we've reached the 4094169689Skan reload pass. */ 4095169689Skan if (TARGET_MIPS16 4096169689Skan && optimize 4097169689Skan && GET_CODE (operands[2]) == CONST_INT 4098169689Skan && INTVAL (operands[2]) > 8 4099169689Skan && INTVAL (operands[2]) <= 16 4100169689Skan && !reload_in_progress 4101169689Skan && !reload_completed) 4102169689Skan { 4103169689Skan rtx temp = gen_reg_rtx (<MODE>mode); 4104169689Skan 4105169689Skan emit_insn (gen_<optab><mode>3 (temp, operands[1], GEN_INT (8))); 4106169689Skan emit_insn (gen_<optab><mode>3 (operands[0], temp, 4107169689Skan GEN_INT (INTVAL (operands[2]) - 8))); 4108169689Skan DONE; 4109169689Skan } 4110169689Skan}) 4111169689Skan 4112169689Skan(define_insn "*<optab><mode>3" 4113169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4114169689Skan (any_shift:GPR (match_operand:GPR 1 "register_operand" "d") 4115169689Skan (match_operand:SI 2 "arith_operand" "dI")))] 4116169689Skan "!TARGET_MIPS16" 4117169689Skan{ 4118169689Skan if (GET_CODE (operands[2]) == CONST_INT) 4119169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) 4120169689Skan & (GET_MODE_BITSIZE (<MODE>mode) - 1)); 4121169689Skan 4122169689Skan return "<d><insn>\t%0,%1,%2"; 4123169689Skan} 4124169689Skan [(set_attr "type" "shift") 4125169689Skan (set_attr "mode" "<MODE>")]) 4126169689Skan 4127169689Skan(define_insn "*<optab>si3_extend" 4128169689Skan [(set (match_operand:DI 0 "register_operand" "=d") 4129169689Skan (sign_extend:DI 4130169689Skan (any_shift:SI (match_operand:SI 1 "register_operand" "d") 4131169689Skan (match_operand:SI 2 "arith_operand" "dI"))))] 4132169689Skan "TARGET_64BIT && !TARGET_MIPS16" 4133169689Skan{ 4134169689Skan if (GET_CODE (operands[2]) == CONST_INT) 4135169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); 4136169689Skan 4137169689Skan return "<insn>\t%0,%1,%2"; 4138169689Skan} 4139169689Skan [(set_attr "type" "shift") 4140169689Skan (set_attr "mode" "SI")]) 4141169689Skan 4142169689Skan(define_insn "*<optab>si3_mips16" 4143169689Skan [(set (match_operand:SI 0 "register_operand" "=d,d") 4144169689Skan (any_shift:SI (match_operand:SI 1 "register_operand" "0,d") 4145169689Skan (match_operand:SI 2 "arith_operand" "d,I")))] 4146169689Skan "TARGET_MIPS16" 4147169689Skan{ 4148169689Skan if (which_alternative == 0) 4149169689Skan return "<insn>\t%0,%2"; 4150169689Skan 4151169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); 4152169689Skan return "<insn>\t%0,%1,%2"; 4153169689Skan} 4154169689Skan [(set_attr "type" "shift") 4155169689Skan (set_attr "mode" "SI") 4156169689Skan (set_attr_alternative "length" 4157169689Skan [(const_int 4) 4158169689Skan (if_then_else (match_operand 2 "m16_uimm3_b") 4159169689Skan (const_int 4) 4160169689Skan (const_int 8))])]) 4161169689Skan 4162169689Skan;; We need separate DImode MIPS16 patterns because of the irregularity 4163169689Skan;; of right shifts. 4164169689Skan(define_insn "*ashldi3_mips16" 4165169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 4166169689Skan (ashift:DI (match_operand:DI 1 "register_operand" "0,d") 4167169689Skan (match_operand:SI 2 "arith_operand" "d,I")))] 4168169689Skan "TARGET_64BIT && TARGET_MIPS16" 4169169689Skan{ 4170169689Skan if (which_alternative == 0) 4171169689Skan return "dsll\t%0,%2"; 4172169689Skan 4173169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); 4174169689Skan return "dsll\t%0,%1,%2"; 4175169689Skan} 4176169689Skan [(set_attr "type" "shift") 4177169689Skan (set_attr "mode" "DI") 4178169689Skan (set_attr_alternative "length" 4179169689Skan [(const_int 4) 4180169689Skan (if_then_else (match_operand 2 "m16_uimm3_b") 4181169689Skan (const_int 4) 4182169689Skan (const_int 8))])]) 4183169689Skan 4184169689Skan(define_insn "*ashrdi3_mips16" 4185169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 4186169689Skan (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0") 4187169689Skan (match_operand:SI 2 "arith_operand" "d,I")))] 4188169689Skan "TARGET_64BIT && TARGET_MIPS16" 4189169689Skan{ 4190169689Skan if (GET_CODE (operands[2]) == CONST_INT) 4191169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); 4192169689Skan 4193169689Skan return "dsra\t%0,%2"; 4194169689Skan} 4195169689Skan [(set_attr "type" "shift") 4196169689Skan (set_attr "mode" "DI") 4197169689Skan (set_attr_alternative "length" 4198169689Skan [(const_int 4) 4199169689Skan (if_then_else (match_operand 2 "m16_uimm3_b") 4200169689Skan (const_int 4) 4201169689Skan (const_int 8))])]) 4202169689Skan 4203169689Skan(define_insn "*lshrdi3_mips16" 4204169689Skan [(set (match_operand:DI 0 "register_operand" "=d,d") 4205169689Skan (lshiftrt:DI (match_operand:DI 1 "register_operand" "0,0") 4206169689Skan (match_operand:SI 2 "arith_operand" "d,I")))] 4207169689Skan "TARGET_64BIT && TARGET_MIPS16" 4208169689Skan{ 4209169689Skan if (GET_CODE (operands[2]) == CONST_INT) 4210169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); 4211169689Skan 4212169689Skan return "dsrl\t%0,%2"; 4213169689Skan} 4214169689Skan [(set_attr "type" "shift") 4215169689Skan (set_attr "mode" "DI") 4216169689Skan (set_attr_alternative "length" 4217169689Skan [(const_int 4) 4218169689Skan (if_then_else (match_operand 2 "m16_uimm3_b") 4219169689Skan (const_int 4) 4220169689Skan (const_int 8))])]) 4221169689Skan 4222169689Skan;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts. 4223169689Skan 4224169689Skan(define_split 4225169689Skan [(set (match_operand:GPR 0 "register_operand") 4226169689Skan (any_shift:GPR (match_operand:GPR 1 "register_operand") 4227169689Skan (match_operand:GPR 2 "const_int_operand")))] 4228169689Skan "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE 4229169689Skan && GET_CODE (operands[2]) == CONST_INT 4230169689Skan && INTVAL (operands[2]) > 8 4231169689Skan && INTVAL (operands[2]) <= 16" 4232169689Skan [(set (match_dup 0) (any_shift:GPR (match_dup 1) (const_int 8))) 4233169689Skan (set (match_dup 0) (any_shift:GPR (match_dup 0) (match_dup 2)))] 4234169689Skan { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }) 4235169689Skan 4236169689Skan;; If we load a byte on the mips16 as a bitfield, the resulting 4237169689Skan;; sequence of instructions is too complicated for combine, because it 4238169689Skan;; involves four instructions: a load, a shift, a constant load into a 4239169689Skan;; register, and an and (the key problem here is that the mips16 does 4240169689Skan;; not have and immediate). We recognize a shift of a load in order 4241169689Skan;; to make it simple enough for combine to understand. 4242169689Skan;; 4243169689Skan;; The length here is the worst case: the length of the split version 4244169689Skan;; will be more accurate. 4245169689Skan(define_insn_and_split "" 4246169689Skan [(set (match_operand:SI 0 "register_operand" "=d") 4247169689Skan (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") 4248169689Skan (match_operand:SI 2 "immediate_operand" "I")))] 4249169689Skan "TARGET_MIPS16" 4250169689Skan "#" 4251169689Skan "" 4252169689Skan [(set (match_dup 0) (match_dup 1)) 4253169689Skan (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] 4254169689Skan "" 4255169689Skan [(set_attr "type" "load") 4256169689Skan (set_attr "mode" "SI") 4257169689Skan (set_attr "length" "16")]) 4258169689Skan 4259169689Skan(define_insn "rotr<mode>3" 4260169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4261169689Skan (rotatert:GPR (match_operand:GPR 1 "register_operand" "d") 4262169689Skan (match_operand:SI 2 "arith_operand" "dI")))] 4263169689Skan "ISA_HAS_ROTR_<MODE>" 4264169689Skan{ 4265169689Skan if (GET_CODE (operands[2]) == CONST_INT) 4266169689Skan gcc_assert (INTVAL (operands[2]) >= 0 4267169689Skan && INTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)); 4268169689Skan 4269169689Skan return "<d>ror\t%0,%1,%2"; 4270169689Skan} 4271169689Skan [(set_attr "type" "shift") 4272169689Skan (set_attr "mode" "<MODE>")]) 4273169689Skan 4274169689Skan;; 4275169689Skan;; .................... 4276169689Skan;; 4277169689Skan;; COMPARISONS 4278169689Skan;; 4279169689Skan;; .................... 4280169689Skan 4281169689Skan;; Flow here is rather complex: 4282169689Skan;; 4283169689Skan;; 1) The cmp{si,di,sf,df} routine is called. It deposits the arguments 4284169689Skan;; into cmp_operands[] but generates no RTL. 4285169689Skan;; 4286169689Skan;; 2) The appropriate branch define_expand is called, which then 4287169689Skan;; creates the appropriate RTL for the comparison and branch. 4288169689Skan;; Different CC modes are used, based on what type of branch is 4289169689Skan;; done, so that we can constrain things appropriately. There 4290169689Skan;; are assumptions in the rest of GCC that break if we fold the 4291169689Skan;; operands into the branches for integer operations, and use cc0 4292169689Skan;; for floating point, so we use the fp status register instead. 4293169689Skan;; If needed, an appropriate temporary is created to hold the 4294169689Skan;; of the integer compare. 4295169689Skan 4296169689Skan(define_expand "cmp<mode>" 4297169689Skan [(set (cc0) 4298169689Skan (compare:CC (match_operand:GPR 0 "register_operand") 4299169689Skan (match_operand:GPR 1 "nonmemory_operand")))] 4300169689Skan "" 4301169689Skan{ 4302169689Skan cmp_operands[0] = operands[0]; 4303169689Skan cmp_operands[1] = operands[1]; 4304169689Skan DONE; 4305169689Skan}) 4306169689Skan 4307169689Skan(define_expand "cmp<mode>" 4308169689Skan [(set (cc0) 4309169689Skan (compare:CC (match_operand:SCALARF 0 "register_operand") 4310169689Skan (match_operand:SCALARF 1 "register_operand")))] 4311169689Skan "" 4312169689Skan{ 4313169689Skan cmp_operands[0] = operands[0]; 4314169689Skan cmp_operands[1] = operands[1]; 4315169689Skan DONE; 4316169689Skan}) 4317169689Skan 4318169689Skan;; 4319169689Skan;; .................... 4320169689Skan;; 4321169689Skan;; CONDITIONAL BRANCHES 4322169689Skan;; 4323169689Skan;; .................... 4324169689Skan 4325169689Skan;; Conditional branches on floating-point equality tests. 4326169689Skan 4327169689Skan(define_insn "*branch_fp" 4328169689Skan [(set (pc) 4329169689Skan (if_then_else 4330169689Skan (match_operator 0 "equality_operator" 4331169689Skan [(match_operand:CC 2 "register_operand" "z") 4332169689Skan (const_int 0)]) 4333169689Skan (label_ref (match_operand 1 "" "")) 4334169689Skan (pc)))] 4335169689Skan "TARGET_HARD_FLOAT" 4336169689Skan{ 4337169689Skan return mips_output_conditional_branch (insn, operands, 4338169689Skan MIPS_BRANCH ("b%F0", "%Z2%1"), 4339169689Skan MIPS_BRANCH ("b%W0", "%Z2%1")); 4340169689Skan} 4341169689Skan [(set_attr "type" "branch") 4342169689Skan (set_attr "mode" "none")]) 4343169689Skan 4344169689Skan(define_insn "*branch_fp_inverted" 4345169689Skan [(set (pc) 4346169689Skan (if_then_else 4347169689Skan (match_operator 0 "equality_operator" 4348169689Skan [(match_operand:CC 2 "register_operand" "z") 4349169689Skan (const_int 0)]) 4350169689Skan (pc) 4351169689Skan (label_ref (match_operand 1 "" ""))))] 4352169689Skan "TARGET_HARD_FLOAT" 4353169689Skan{ 4354169689Skan return mips_output_conditional_branch (insn, operands, 4355169689Skan MIPS_BRANCH ("b%W0", "%Z2%1"), 4356169689Skan MIPS_BRANCH ("b%F0", "%Z2%1")); 4357169689Skan} 4358169689Skan [(set_attr "type" "branch") 4359169689Skan (set_attr "mode" "none")]) 4360169689Skan 4361169689Skan;; Conditional branches on ordered comparisons with zero. 4362169689Skan 4363169689Skan(define_insn "*branch_order<mode>" 4364169689Skan [(set (pc) 4365169689Skan (if_then_else 4366169689Skan (match_operator 0 "order_operator" 4367169689Skan [(match_operand:GPR 2 "register_operand" "d") 4368169689Skan (const_int 0)]) 4369169689Skan (label_ref (match_operand 1 "" "")) 4370169689Skan (pc)))] 4371169689Skan "!TARGET_MIPS16" 4372169689Skan { return mips_output_order_conditional_branch (insn, operands, false); } 4373169689Skan [(set_attr "type" "branch") 4374169689Skan (set_attr "mode" "none")]) 4375169689Skan 4376169689Skan(define_insn "*branch_order<mode>_inverted" 4377169689Skan [(set (pc) 4378169689Skan (if_then_else 4379169689Skan (match_operator 0 "order_operator" 4380169689Skan [(match_operand:GPR 2 "register_operand" "d") 4381169689Skan (const_int 0)]) 4382169689Skan (pc) 4383169689Skan (label_ref (match_operand 1 "" ""))))] 4384169689Skan "!TARGET_MIPS16" 4385169689Skan { return mips_output_order_conditional_branch (insn, operands, true); } 4386169689Skan [(set_attr "type" "branch") 4387169689Skan (set_attr "mode" "none")]) 4388169689Skan 4389169689Skan;; Conditional branch on equality comparison. 4390169689Skan 4391169689Skan(define_insn "*branch_equality<mode>" 4392169689Skan [(set (pc) 4393169689Skan (if_then_else 4394169689Skan (match_operator 0 "equality_operator" 4395169689Skan [(match_operand:GPR 2 "register_operand" "d") 4396169689Skan (match_operand:GPR 3 "reg_or_0_operand" "dJ")]) 4397169689Skan (label_ref (match_operand 1 "" "")) 4398169689Skan (pc)))] 4399169689Skan "!TARGET_MIPS16" 4400169689Skan{ 4401169689Skan return mips_output_conditional_branch (insn, operands, 4402169689Skan MIPS_BRANCH ("b%C0", "%2,%z3,%1"), 4403169689Skan MIPS_BRANCH ("b%N0", "%2,%z3,%1")); 4404169689Skan} 4405169689Skan [(set_attr "type" "branch") 4406169689Skan (set_attr "mode" "none")]) 4407169689Skan 4408169689Skan(define_insn "*branch_equality<mode>_inverted" 4409169689Skan [(set (pc) 4410169689Skan (if_then_else 4411169689Skan (match_operator 0 "equality_operator" 4412169689Skan [(match_operand:GPR 2 "register_operand" "d") 4413169689Skan (match_operand:GPR 3 "reg_or_0_operand" "dJ")]) 4414169689Skan (pc) 4415169689Skan (label_ref (match_operand 1 "" ""))))] 4416169689Skan "!TARGET_MIPS16" 4417169689Skan{ 4418169689Skan return mips_output_conditional_branch (insn, operands, 4419169689Skan MIPS_BRANCH ("b%N0", "%2,%z3,%1"), 4420169689Skan MIPS_BRANCH ("b%C0", "%2,%z3,%1")); 4421169689Skan} 4422169689Skan [(set_attr "type" "branch") 4423169689Skan (set_attr "mode" "none")]) 4424169689Skan 4425169689Skan;; MIPS16 branches 4426169689Skan 4427169689Skan(define_insn "*branch_equality<mode>_mips16" 4428169689Skan [(set (pc) 4429169689Skan (if_then_else 4430169689Skan (match_operator 0 "equality_operator" 4431169689Skan [(match_operand:GPR 1 "register_operand" "d,t") 4432169689Skan (const_int 0)]) 4433169689Skan (match_operand 2 "pc_or_label_operand" "") 4434169689Skan (match_operand 3 "pc_or_label_operand" "")))] 4435169689Skan "TARGET_MIPS16" 4436169689Skan{ 4437169689Skan if (operands[2] != pc_rtx) 4438169689Skan { 4439169689Skan if (which_alternative == 0) 4440169689Skan return "b%C0z\t%1,%2"; 4441169689Skan else 4442169689Skan return "bt%C0z\t%2"; 4443169689Skan } 4444169689Skan else 4445169689Skan { 4446169689Skan if (which_alternative == 0) 4447169689Skan return "b%N0z\t%1,%3"; 4448169689Skan else 4449169689Skan return "bt%N0z\t%3"; 4450169689Skan } 4451169689Skan} 4452169689Skan [(set_attr "type" "branch") 4453169689Skan (set_attr "mode" "none") 4454169689Skan (set_attr "length" "8")]) 4455169689Skan 4456169689Skan(define_expand "b<code>" 4457169689Skan [(set (pc) 4458169689Skan (if_then_else (any_cond:CC (cc0) 4459169689Skan (const_int 0)) 4460169689Skan (label_ref (match_operand 0 "")) 4461169689Skan (pc)))] 4462169689Skan "" 4463169689Skan{ 4464169689Skan gen_conditional_branch (operands, <CODE>); 4465169689Skan DONE; 4466169689Skan}) 4467169689Skan 4468169689Skan;; Used to implement built-in functions. 4469169689Skan(define_expand "condjump" 4470169689Skan [(set (pc) 4471169689Skan (if_then_else (match_operand 0) 4472169689Skan (label_ref (match_operand 1)) 4473169689Skan (pc)))]) 4474169689Skan 4475169689Skan;; 4476169689Skan;; .................... 4477169689Skan;; 4478169689Skan;; SETTING A REGISTER FROM A COMPARISON 4479169689Skan;; 4480169689Skan;; .................... 4481169689Skan 4482169689Skan(define_expand "seq" 4483169689Skan [(set (match_operand:SI 0 "register_operand") 4484169689Skan (eq:SI (match_dup 1) 4485169689Skan (match_dup 2)))] 4486169689Skan "" 4487169689Skan { if (mips_emit_scc (EQ, operands[0])) DONE; else FAIL; }) 4488169689Skan 4489169689Skan(define_insn "*seq_<mode>" 4490169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4491169689Skan (eq:GPR (match_operand:GPR 1 "register_operand" "d") 4492169689Skan (const_int 0)))] 4493169689Skan "!TARGET_MIPS16" 4494169689Skan "sltu\t%0,%1,1" 4495169689Skan [(set_attr "type" "slt") 4496169689Skan (set_attr "mode" "<MODE>")]) 4497169689Skan 4498169689Skan(define_insn "*seq_<mode>_mips16" 4499169689Skan [(set (match_operand:GPR 0 "register_operand" "=t") 4500169689Skan (eq:GPR (match_operand:GPR 1 "register_operand" "d") 4501169689Skan (const_int 0)))] 4502169689Skan "TARGET_MIPS16" 4503169689Skan "sltu\t%1,1" 4504169689Skan [(set_attr "type" "slt") 4505169689Skan (set_attr "mode" "<MODE>")]) 4506169689Skan 4507169689Skan;; "sne" uses sltu instructions in which the first operand is $0. 4508169689Skan;; This isn't possible in mips16 code. 4509169689Skan 4510169689Skan(define_expand "sne" 4511169689Skan [(set (match_operand:SI 0 "register_operand") 4512169689Skan (ne:SI (match_dup 1) 4513169689Skan (match_dup 2)))] 4514169689Skan "!TARGET_MIPS16" 4515169689Skan { if (mips_emit_scc (NE, operands[0])) DONE; else FAIL; }) 4516169689Skan 4517169689Skan(define_insn "*sne_<mode>" 4518169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4519169689Skan (ne:GPR (match_operand:GPR 1 "register_operand" "d") 4520169689Skan (const_int 0)))] 4521169689Skan "!TARGET_MIPS16" 4522169689Skan "sltu\t%0,%.,%1" 4523169689Skan [(set_attr "type" "slt") 4524169689Skan (set_attr "mode" "<MODE>")]) 4525169689Skan 4526169689Skan(define_expand "sgt" 4527169689Skan [(set (match_operand:SI 0 "register_operand") 4528169689Skan (gt:SI (match_dup 1) 4529169689Skan (match_dup 2)))] 4530169689Skan "" 4531169689Skan { if (mips_emit_scc (GT, operands[0])) DONE; else FAIL; }) 4532169689Skan 4533169689Skan(define_insn "*sgt_<mode>" 4534169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4535169689Skan (gt:GPR (match_operand:GPR 1 "register_operand" "d") 4536169689Skan (match_operand:GPR 2 "reg_or_0_operand" "dJ")))] 4537169689Skan "!TARGET_MIPS16" 4538169689Skan "slt\t%0,%z2,%1" 4539169689Skan [(set_attr "type" "slt") 4540169689Skan (set_attr "mode" "<MODE>")]) 4541169689Skan 4542169689Skan(define_insn "*sgt_<mode>_mips16" 4543169689Skan [(set (match_operand:GPR 0 "register_operand" "=t") 4544169689Skan (gt:GPR (match_operand:GPR 1 "register_operand" "d") 4545169689Skan (match_operand:GPR 2 "register_operand" "d")))] 4546169689Skan "TARGET_MIPS16" 4547169689Skan "slt\t%2,%1" 4548169689Skan [(set_attr "type" "slt") 4549169689Skan (set_attr "mode" "<MODE>")]) 4550169689Skan 4551169689Skan(define_expand "sge" 4552169689Skan [(set (match_operand:SI 0 "register_operand") 4553169689Skan (ge:SI (match_dup 1) 4554169689Skan (match_dup 2)))] 4555169689Skan "" 4556169689Skan { if (mips_emit_scc (GE, operands[0])) DONE; else FAIL; }) 4557169689Skan 4558169689Skan(define_insn "*sge_<mode>" 4559169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4560169689Skan (ge:GPR (match_operand:GPR 1 "register_operand" "d") 4561169689Skan (const_int 1)))] 4562169689Skan "!TARGET_MIPS16" 4563169689Skan "slt\t%0,%.,%1" 4564169689Skan [(set_attr "type" "slt") 4565169689Skan (set_attr "mode" "<MODE>")]) 4566169689Skan 4567169689Skan(define_expand "slt" 4568169689Skan [(set (match_operand:SI 0 "register_operand") 4569169689Skan (lt:SI (match_dup 1) 4570169689Skan (match_dup 2)))] 4571169689Skan "" 4572169689Skan { if (mips_emit_scc (LT, operands[0])) DONE; else FAIL; }) 4573169689Skan 4574169689Skan(define_insn "*slt_<mode>" 4575169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4576169689Skan (lt:GPR (match_operand:GPR 1 "register_operand" "d") 4577169689Skan (match_operand:GPR 2 "arith_operand" "dI")))] 4578169689Skan "!TARGET_MIPS16" 4579169689Skan "slt\t%0,%1,%2" 4580169689Skan [(set_attr "type" "slt") 4581169689Skan (set_attr "mode" "<MODE>")]) 4582169689Skan 4583169689Skan(define_insn "*slt_<mode>_mips16" 4584169689Skan [(set (match_operand:GPR 0 "register_operand" "=t,t") 4585169689Skan (lt:GPR (match_operand:GPR 1 "register_operand" "d,d") 4586169689Skan (match_operand:GPR 2 "arith_operand" "d,I")))] 4587169689Skan "TARGET_MIPS16" 4588169689Skan "slt\t%1,%2" 4589169689Skan [(set_attr "type" "slt") 4590169689Skan (set_attr "mode" "<MODE>") 4591169689Skan (set_attr_alternative "length" 4592169689Skan [(const_int 4) 4593169689Skan (if_then_else (match_operand 2 "m16_uimm8_1") 4594169689Skan (const_int 4) 4595169689Skan (const_int 8))])]) 4596169689Skan 4597169689Skan(define_expand "sle" 4598169689Skan [(set (match_operand:SI 0 "register_operand") 4599169689Skan (le:SI (match_dup 1) 4600169689Skan (match_dup 2)))] 4601169689Skan "" 4602169689Skan { if (mips_emit_scc (LE, operands[0])) DONE; else FAIL; }) 4603169689Skan 4604169689Skan(define_insn "*sle_<mode>" 4605169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4606169689Skan (le:GPR (match_operand:GPR 1 "register_operand" "d") 4607169689Skan (match_operand:GPR 2 "sle_operand" "")))] 4608169689Skan "!TARGET_MIPS16" 4609169689Skan{ 4610169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) + 1); 4611169689Skan return "slt\t%0,%1,%2"; 4612169689Skan} 4613169689Skan [(set_attr "type" "slt") 4614169689Skan (set_attr "mode" "<MODE>")]) 4615169689Skan 4616169689Skan(define_insn "*sle_<mode>_mips16" 4617169689Skan [(set (match_operand:GPR 0 "register_operand" "=t") 4618169689Skan (le:GPR (match_operand:GPR 1 "register_operand" "d") 4619169689Skan (match_operand:GPR 2 "sle_operand" "")))] 4620169689Skan "TARGET_MIPS16" 4621169689Skan{ 4622169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) + 1); 4623169689Skan return "slt\t%1,%2"; 4624169689Skan} 4625169689Skan [(set_attr "type" "slt") 4626169689Skan (set_attr "mode" "<MODE>") 4627169689Skan (set (attr "length") (if_then_else (match_operand 2 "m16_uimm8_m1_1") 4628169689Skan (const_int 4) 4629169689Skan (const_int 8)))]) 4630169689Skan 4631169689Skan(define_expand "sgtu" 4632169689Skan [(set (match_operand:SI 0 "register_operand") 4633169689Skan (gtu:SI (match_dup 1) 4634169689Skan (match_dup 2)))] 4635169689Skan "" 4636169689Skan { if (mips_emit_scc (GTU, operands[0])) DONE; else FAIL; }) 4637169689Skan 4638169689Skan(define_insn "*sgtu_<mode>" 4639169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4640169689Skan (gtu:GPR (match_operand:GPR 1 "register_operand" "d") 4641169689Skan (match_operand:GPR 2 "reg_or_0_operand" "dJ")))] 4642169689Skan "!TARGET_MIPS16" 4643169689Skan "sltu\t%0,%z2,%1" 4644169689Skan [(set_attr "type" "slt") 4645169689Skan (set_attr "mode" "<MODE>")]) 4646169689Skan 4647169689Skan(define_insn "*sgtu_<mode>_mips16" 4648169689Skan [(set (match_operand:GPR 0 "register_operand" "=t") 4649169689Skan (gtu:GPR (match_operand:GPR 1 "register_operand" "d") 4650169689Skan (match_operand:GPR 2 "register_operand" "d")))] 4651169689Skan "TARGET_MIPS16" 4652169689Skan "sltu\t%2,%1" 4653169689Skan [(set_attr "type" "slt") 4654169689Skan (set_attr "mode" "<MODE>")]) 4655169689Skan 4656169689Skan(define_expand "sgeu" 4657169689Skan [(set (match_operand:SI 0 "register_operand") 4658169689Skan (geu:SI (match_dup 1) 4659169689Skan (match_dup 2)))] 4660169689Skan "" 4661169689Skan { if (mips_emit_scc (GEU, operands[0])) DONE; else FAIL; }) 4662169689Skan 4663169689Skan(define_insn "*sge_<mode>" 4664169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4665169689Skan (geu:GPR (match_operand:GPR 1 "register_operand" "d") 4666169689Skan (const_int 1)))] 4667169689Skan "!TARGET_MIPS16" 4668169689Skan "sltu\t%0,%.,%1" 4669169689Skan [(set_attr "type" "slt") 4670169689Skan (set_attr "mode" "<MODE>")]) 4671169689Skan 4672169689Skan(define_expand "sltu" 4673169689Skan [(set (match_operand:SI 0 "register_operand") 4674169689Skan (ltu:SI (match_dup 1) 4675169689Skan (match_dup 2)))] 4676169689Skan "" 4677169689Skan { if (mips_emit_scc (LTU, operands[0])) DONE; else FAIL; }) 4678169689Skan 4679169689Skan(define_insn "*sltu_<mode>" 4680169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4681169689Skan (ltu:GPR (match_operand:GPR 1 "register_operand" "d") 4682169689Skan (match_operand:GPR 2 "arith_operand" "dI")))] 4683169689Skan "!TARGET_MIPS16" 4684169689Skan "sltu\t%0,%1,%2" 4685169689Skan [(set_attr "type" "slt") 4686169689Skan (set_attr "mode" "<MODE>")]) 4687169689Skan 4688169689Skan(define_insn "*sltu_<mode>_mips16" 4689169689Skan [(set (match_operand:GPR 0 "register_operand" "=t,t") 4690169689Skan (ltu:GPR (match_operand:GPR 1 "register_operand" "d,d") 4691169689Skan (match_operand:GPR 2 "arith_operand" "d,I")))] 4692169689Skan "TARGET_MIPS16" 4693169689Skan "sltu\t%1,%2" 4694169689Skan [(set_attr "type" "slt") 4695169689Skan (set_attr "mode" "<MODE>") 4696169689Skan (set_attr_alternative "length" 4697169689Skan [(const_int 4) 4698169689Skan (if_then_else (match_operand 2 "m16_uimm8_1") 4699169689Skan (const_int 4) 4700169689Skan (const_int 8))])]) 4701169689Skan 4702169689Skan(define_expand "sleu" 4703169689Skan [(set (match_operand:SI 0 "register_operand") 4704169689Skan (leu:SI (match_dup 1) 4705169689Skan (match_dup 2)))] 4706169689Skan "" 4707169689Skan { if (mips_emit_scc (LEU, operands[0])) DONE; else FAIL; }) 4708169689Skan 4709169689Skan(define_insn "*sleu_<mode>" 4710169689Skan [(set (match_operand:GPR 0 "register_operand" "=d") 4711169689Skan (leu:GPR (match_operand:GPR 1 "register_operand" "d") 4712169689Skan (match_operand:GPR 2 "sleu_operand" "")))] 4713169689Skan "!TARGET_MIPS16" 4714169689Skan{ 4715169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) + 1); 4716169689Skan return "sltu\t%0,%1,%2"; 4717169689Skan} 4718169689Skan [(set_attr "type" "slt") 4719169689Skan (set_attr "mode" "<MODE>")]) 4720169689Skan 4721169689Skan(define_insn "*sleu_<mode>_mips16" 4722169689Skan [(set (match_operand:GPR 0 "register_operand" "=t") 4723169689Skan (leu:GPR (match_operand:GPR 1 "register_operand" "d") 4724169689Skan (match_operand:GPR 2 "sleu_operand" "")))] 4725169689Skan "TARGET_MIPS16" 4726169689Skan{ 4727169689Skan operands[2] = GEN_INT (INTVAL (operands[2]) + 1); 4728169689Skan return "sltu\t%1,%2"; 4729169689Skan} 4730169689Skan [(set_attr "type" "slt") 4731169689Skan (set_attr "mode" "<MODE>") 4732169689Skan (set (attr "length") (if_then_else (match_operand 2 "m16_uimm8_m1_1") 4733169689Skan (const_int 4) 4734169689Skan (const_int 8)))]) 4735169689Skan 4736169689Skan;; 4737169689Skan;; .................... 4738169689Skan;; 4739169689Skan;; FLOATING POINT COMPARISONS 4740169689Skan;; 4741169689Skan;; .................... 4742169689Skan 4743169689Skan(define_insn "s<code>_<mode>" 4744169689Skan [(set (match_operand:CC 0 "register_operand" "=z") 4745169689Skan (fcond:CC (match_operand:SCALARF 1 "register_operand" "f") 4746169689Skan (match_operand:SCALARF 2 "register_operand" "f")))] 4747169689Skan "" 4748169689Skan "c.<fcond>.<fmt>\t%Z0%1,%2" 4749169689Skan [(set_attr "type" "fcmp") 4750169689Skan (set_attr "mode" "FPSW")]) 4751169689Skan 4752169689Skan(define_insn "s<code>_<mode>" 4753169689Skan [(set (match_operand:CC 0 "register_operand" "=z") 4754169689Skan (swapped_fcond:CC (match_operand:SCALARF 1 "register_operand" "f") 4755169689Skan (match_operand:SCALARF 2 "register_operand" "f")))] 4756169689Skan "" 4757169689Skan "c.<swapped_fcond>.<fmt>\t%Z0%2,%1" 4758169689Skan [(set_attr "type" "fcmp") 4759169689Skan (set_attr "mode" "FPSW")]) 4760169689Skan 4761169689Skan;; 4762169689Skan;; .................... 4763169689Skan;; 4764169689Skan;; UNCONDITIONAL BRANCHES 4765169689Skan;; 4766169689Skan;; .................... 4767169689Skan 4768169689Skan;; Unconditional branches. 4769169689Skan 4770169689Skan(define_insn "jump" 4771169689Skan [(set (pc) 4772169689Skan (label_ref (match_operand 0 "" "")))] 4773169689Skan "!TARGET_MIPS16" 4774169689Skan{ 4775169689Skan if (flag_pic) 4776169689Skan { 4777169689Skan if (get_attr_length (insn) <= 8) 4778169689Skan return "%*b\t%l0%/"; 4779169689Skan else 4780169689Skan { 4781169689Skan output_asm_insn (mips_output_load_label (), operands); 4782169689Skan return "%*jr\t%@%/%]"; 4783169689Skan } 4784169689Skan } 4785169689Skan else 4786169689Skan return "%*j\t%l0%/"; 4787169689Skan} 4788169689Skan [(set_attr "type" "jump") 4789169689Skan (set_attr "mode" "none") 4790169689Skan (set (attr "length") 4791169689Skan ;; We can't use `j' when emitting PIC. Emit a branch if it's 4792169689Skan ;; in range, otherwise load the address of the branch target into 4793169689Skan ;; $at and then jump to it. 4794169689Skan (if_then_else 4795169689Skan (ior (eq (symbol_ref "flag_pic") (const_int 0)) 4796169689Skan (lt (abs (minus (match_dup 0) 4797169689Skan (plus (pc) (const_int 4)))) 4798169689Skan (const_int 131072))) 4799169689Skan (const_int 4) (const_int 16)))]) 4800169689Skan 4801169689Skan;; We need a different insn for the mips16, because a mips16 branch 4802169689Skan;; does not have a delay slot. 4803169689Skan 4804169689Skan(define_insn "" 4805169689Skan [(set (pc) 4806169689Skan (label_ref (match_operand 0 "" "")))] 4807169689Skan "TARGET_MIPS16" 4808169689Skan "b\t%l0" 4809169689Skan [(set_attr "type" "branch") 4810169689Skan (set_attr "mode" "none") 4811169689Skan (set_attr "length" "8")]) 4812169689Skan 4813169689Skan(define_expand "indirect_jump" 4814169689Skan [(set (pc) (match_operand 0 "register_operand"))] 4815169689Skan "" 4816169689Skan{ 4817169689Skan operands[0] = force_reg (Pmode, operands[0]); 4818169689Skan if (Pmode == SImode) 4819169689Skan emit_jump_insn (gen_indirect_jumpsi (operands[0])); 4820169689Skan else 4821169689Skan emit_jump_insn (gen_indirect_jumpdi (operands[0])); 4822169689Skan DONE; 4823169689Skan}) 4824169689Skan 4825169689Skan(define_insn "indirect_jump<mode>" 4826169689Skan [(set (pc) (match_operand:P 0 "register_operand" "d"))] 4827169689Skan "" 4828169689Skan "%*j\t%0%/" 4829169689Skan [(set_attr "type" "jump") 4830169689Skan (set_attr "mode" "none")]) 4831169689Skan 4832169689Skan(define_expand "tablejump" 4833169689Skan [(set (pc) 4834169689Skan (match_operand 0 "register_operand")) 4835169689Skan (use (label_ref (match_operand 1 "")))] 4836169689Skan "" 4837169689Skan{ 4838169689Skan if (TARGET_MIPS16) 4839169689Skan operands[0] = expand_binop (Pmode, add_optab, 4840169689Skan convert_to_mode (Pmode, operands[0], false), 4841169689Skan gen_rtx_LABEL_REF (Pmode, operands[1]), 4842169689Skan 0, 0, OPTAB_WIDEN); 4843169689Skan else if (TARGET_GPWORD) 4844169689Skan operands[0] = expand_binop (Pmode, add_optab, operands[0], 4845169689Skan pic_offset_table_rtx, 0, 0, OPTAB_WIDEN); 4846169689Skan 4847169689Skan if (Pmode == SImode) 4848169689Skan emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); 4849169689Skan else 4850169689Skan emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); 4851169689Skan DONE; 4852169689Skan}) 4853169689Skan 4854169689Skan(define_insn "tablejump<mode>" 4855169689Skan [(set (pc) 4856169689Skan (match_operand:P 0 "register_operand" "d")) 4857169689Skan (use (label_ref (match_operand 1 "" "")))] 4858169689Skan "" 4859169689Skan "%*j\t%0%/" 4860169689Skan [(set_attr "type" "jump") 4861169689Skan (set_attr "mode" "none")]) 4862169689Skan 4863169689Skan;; For TARGET_ABICALLS, we save the gp in the jmp_buf as well. 4864169689Skan;; While it is possible to either pull it off the stack (in the 4865169689Skan;; o32 case) or recalculate it given t9 and our target label, 4866169689Skan;; it takes 3 or 4 insns to do so. 4867169689Skan 4868169689Skan(define_expand "builtin_setjmp_setup" 4869169689Skan [(use (match_operand 0 "register_operand"))] 4870169689Skan "TARGET_ABICALLS" 4871169689Skan{ 4872169689Skan rtx addr; 4873169689Skan 4874169689Skan addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3); 4875169689Skan emit_move_insn (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx); 4876169689Skan DONE; 4877169689Skan}) 4878169689Skan 4879169689Skan;; Restore the gp that we saved above. Despite the earlier comment, it seems 4880169689Skan;; that older code did recalculate the gp from $25. Continue to jump through 4881169689Skan;; $25 for compatibility (we lose nothing by doing so). 4882169689Skan 4883169689Skan(define_expand "builtin_longjmp" 4884169689Skan [(use (match_operand 0 "register_operand"))] 4885169689Skan "TARGET_ABICALLS" 4886169689Skan{ 4887169689Skan /* The elements of the buffer are, in order: */ 4888169689Skan int W = GET_MODE_SIZE (Pmode); 4889169689Skan rtx fp = gen_rtx_MEM (Pmode, operands[0]); 4890169689Skan rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W)); 4891169689Skan rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W)); 4892169689Skan rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W)); 4893169689Skan rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM); 4894169689Skan /* Use gen_raw_REG to avoid being given pic_offset_table_rtx. 4895169689Skan The target is bound to be using $28 as the global pointer 4896169689Skan but the current function might not be. */ 4897169689Skan rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM); 4898169689Skan 4899169689Skan /* This bit is similar to expand_builtin_longjmp except that it 4900169689Skan restores $gp as well. */ 4901169689Skan emit_move_insn (hard_frame_pointer_rtx, fp); 4902169689Skan emit_move_insn (pv, lab); 4903169689Skan emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); 4904169689Skan emit_move_insn (gp, gpv); 4905169689Skan emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); 4906169689Skan emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); 4907169689Skan emit_insn (gen_rtx_USE (VOIDmode, gp)); 4908169689Skan emit_indirect_jump (pv); 4909169689Skan DONE; 4910169689Skan}) 4911169689Skan 4912169689Skan;; 4913169689Skan;; .................... 4914169689Skan;; 4915169689Skan;; Function prologue/epilogue 4916169689Skan;; 4917169689Skan;; .................... 4918169689Skan;; 4919169689Skan 4920169689Skan(define_expand "prologue" 4921169689Skan [(const_int 1)] 4922169689Skan "" 4923169689Skan{ 4924169689Skan mips_expand_prologue (); 4925169689Skan DONE; 4926169689Skan}) 4927169689Skan 4928169689Skan;; Block any insns from being moved before this point, since the 4929169689Skan;; profiling call to mcount can use various registers that aren't 4930169689Skan;; saved or used to pass arguments. 4931169689Skan 4932169689Skan(define_insn "blockage" 4933169689Skan [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] 4934169689Skan "" 4935169689Skan "" 4936169689Skan [(set_attr "type" "unknown") 4937169689Skan (set_attr "mode" "none") 4938169689Skan (set_attr "length" "0")]) 4939169689Skan 4940169689Skan(define_expand "epilogue" 4941169689Skan [(const_int 2)] 4942169689Skan "" 4943169689Skan{ 4944169689Skan mips_expand_epilogue (false); 4945169689Skan DONE; 4946169689Skan}) 4947169689Skan 4948169689Skan(define_expand "sibcall_epilogue" 4949169689Skan [(const_int 2)] 4950169689Skan "" 4951169689Skan{ 4952169689Skan mips_expand_epilogue (true); 4953169689Skan DONE; 4954169689Skan}) 4955169689Skan 4956169689Skan;; Trivial return. Make it look like a normal return insn as that 4957169689Skan;; allows jump optimizations to work better. 4958169689Skan 4959169689Skan(define_insn "return" 4960169689Skan [(return)] 4961169689Skan "mips_can_use_return_insn ()" 4962169689Skan "%*j\t$31%/" 4963169689Skan [(set_attr "type" "jump") 4964169689Skan (set_attr "mode" "none")]) 4965169689Skan 4966169689Skan;; Normal return. 4967169689Skan 4968169689Skan(define_insn "return_internal" 4969169689Skan [(return) 4970169689Skan (use (match_operand 0 "pmode_register_operand" ""))] 4971169689Skan "" 4972169689Skan "%*j\t%0%/" 4973169689Skan [(set_attr "type" "jump") 4974169689Skan (set_attr "mode" "none")]) 4975169689Skan 4976169689Skan;; This is used in compiling the unwind routines. 4977169689Skan(define_expand "eh_return" 4978169689Skan [(use (match_operand 0 "general_operand"))] 4979169689Skan "" 4980169689Skan{ 4981169689Skan enum machine_mode gpr_mode = TARGET_64BIT ? DImode : SImode; 4982169689Skan 4983169689Skan if (GET_MODE (operands[0]) != gpr_mode) 4984169689Skan operands[0] = convert_to_mode (gpr_mode, operands[0], 0); 4985169689Skan if (TARGET_64BIT) 4986169689Skan emit_insn (gen_eh_set_lr_di (operands[0])); 4987169689Skan else 4988169689Skan emit_insn (gen_eh_set_lr_si (operands[0])); 4989169689Skan 4990169689Skan DONE; 4991169689Skan}) 4992169689Skan 4993169689Skan;; Clobber the return address on the stack. We can't expand this 4994169689Skan;; until we know where it will be put in the stack frame. 4995169689Skan 4996169689Skan(define_insn "eh_set_lr_si" 4997169689Skan [(unspec [(match_operand:SI 0 "register_operand" "d")] UNSPEC_EH_RETURN) 4998169689Skan (clobber (match_scratch:SI 1 "=&d"))] 4999169689Skan "! TARGET_64BIT" 5000169689Skan "#") 5001169689Skan 5002169689Skan(define_insn "eh_set_lr_di" 5003169689Skan [(unspec [(match_operand:DI 0 "register_operand" "d")] UNSPEC_EH_RETURN) 5004169689Skan (clobber (match_scratch:DI 1 "=&d"))] 5005169689Skan "TARGET_64BIT" 5006169689Skan "#") 5007169689Skan 5008169689Skan(define_split 5009169689Skan [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN) 5010169689Skan (clobber (match_scratch 1))] 5011169689Skan "reload_completed && !TARGET_DEBUG_D_MODE" 5012169689Skan [(const_int 0)] 5013169689Skan{ 5014169689Skan mips_set_return_address (operands[0], operands[1]); 5015169689Skan DONE; 5016169689Skan}) 5017169689Skan 5018169689Skan(define_insn_and_split "exception_receiver" 5019169689Skan [(set (reg:SI 28) 5020169689Skan (unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))] 5021169689Skan "TARGET_ABICALLS && TARGET_OLDABI" 5022169689Skan "#" 5023169689Skan "&& reload_completed" 5024169689Skan [(const_int 0)] 5025169689Skan{ 5026169689Skan mips_restore_gp (); 5027169689Skan DONE; 5028169689Skan} 5029169689Skan [(set_attr "type" "load") 5030169689Skan (set_attr "length" "12")]) 5031169689Skan 5032169689Skan;; 5033169689Skan;; .................... 5034169689Skan;; 5035169689Skan;; FUNCTION CALLS 5036169689Skan;; 5037169689Skan;; .................... 5038169689Skan 5039169689Skan;; Instructions to load a call address from the GOT. The address might 5040169689Skan;; point to a function or to a lazy binding stub. In the latter case, 5041169689Skan;; the stub will use the dynamic linker to resolve the function, which 5042169689Skan;; in turn will change the GOT entry to point to the function's real 5043169689Skan;; address. 5044169689Skan;; 5045169689Skan;; This means that every call, even pure and constant ones, can 5046169689Skan;; potentially modify the GOT entry. And once a stub has been called, 5047169689Skan;; we must not call it again. 5048169689Skan;; 5049169689Skan;; We represent this restriction using an imaginary fixed register that 5050169689Skan;; acts like a GOT version number. By making the register call-clobbered, 5051169689Skan;; we tell the target-independent code that the address could be changed 5052169689Skan;; by any call insn. 5053169689Skan(define_insn "load_call<mode>" 5054169689Skan [(set (match_operand:P 0 "register_operand" "=c") 5055169689Skan (unspec:P [(match_operand:P 1 "register_operand" "r") 5056169689Skan (match_operand:P 2 "immediate_operand" "") 5057169689Skan (reg:P FAKE_CALL_REGNO)] 5058169689Skan UNSPEC_LOAD_CALL))] 5059169689Skan "TARGET_ABICALLS" 5060169689Skan "<load>\t%0,%R2(%1)" 5061169689Skan [(set_attr "type" "load") 5062169689Skan (set_attr "mode" "<MODE>") 5063169689Skan (set_attr "length" "4")]) 5064169689Skan 5065169689Skan;; Sibling calls. All these patterns use jump instructions. 5066169689Skan 5067169689Skan;; If TARGET_SIBCALLS, call_insn_operand will only accept constant 5068169689Skan;; addresses if a direct jump is acceptable. Since the 'S' constraint 5069169689Skan;; is defined in terms of call_insn_operand, the same is true of the 5070169689Skan;; constraints. 5071169689Skan 5072169689Skan;; When we use an indirect jump, we need a register that will be 5073169689Skan;; preserved by the epilogue. Since TARGET_ABICALLS forces us to 5074169689Skan;; use $25 for this purpose -- and $25 is never clobbered by the 5075169689Skan;; epilogue -- we might as well use it for !TARGET_ABICALLS as well. 5076169689Skan 5077169689Skan(define_expand "sibcall" 5078169689Skan [(parallel [(call (match_operand 0 "") 5079169689Skan (match_operand 1 "")) 5080169689Skan (use (match_operand 2 "")) ;; next_arg_reg 5081169689Skan (use (match_operand 3 ""))])] ;; struct_value_size_rtx 5082169689Skan "TARGET_SIBCALLS" 5083169689Skan{ 5084169689Skan mips_expand_call (0, XEXP (operands[0], 0), operands[1], operands[2], true); 5085169689Skan DONE; 5086169689Skan}) 5087169689Skan 5088169689Skan(define_insn "sibcall_internal" 5089169689Skan [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S")) 5090169689Skan (match_operand 1 "" ""))] 5091169689Skan "TARGET_SIBCALLS && SIBLING_CALL_P (insn)" 5092169689Skan { return MIPS_CALL ("j", operands, 0); } 5093169689Skan [(set_attr "type" "call")]) 5094169689Skan 5095169689Skan(define_expand "sibcall_value" 5096169689Skan [(parallel [(set (match_operand 0 "") 5097169689Skan (call (match_operand 1 "") 5098169689Skan (match_operand 2 ""))) 5099169689Skan (use (match_operand 3 ""))])] ;; next_arg_reg 5100169689Skan "TARGET_SIBCALLS" 5101169689Skan{ 5102169689Skan mips_expand_call (operands[0], XEXP (operands[1], 0), 5103169689Skan operands[2], operands[3], true); 5104169689Skan DONE; 5105169689Skan}) 5106169689Skan 5107169689Skan(define_insn "sibcall_value_internal" 5108169689Skan [(set (match_operand 0 "register_operand" "=df,df") 5109169689Skan (call (mem:SI (match_operand 1 "call_insn_operand" "j,S")) 5110169689Skan (match_operand 2 "" "")))] 5111169689Skan "TARGET_SIBCALLS && SIBLING_CALL_P (insn)" 5112169689Skan { return MIPS_CALL ("j", operands, 1); } 5113169689Skan [(set_attr "type" "call")]) 5114169689Skan 5115169689Skan(define_insn "sibcall_value_multiple_internal" 5116169689Skan [(set (match_operand 0 "register_operand" "=df,df") 5117169689Skan (call (mem:SI (match_operand 1 "call_insn_operand" "j,S")) 5118169689Skan (match_operand 2 "" ""))) 5119169689Skan (set (match_operand 3 "register_operand" "=df,df") 5120169689Skan (call (mem:SI (match_dup 1)) 5121169689Skan (match_dup 2)))] 5122169689Skan "TARGET_SIBCALLS && SIBLING_CALL_P (insn)" 5123169689Skan { return MIPS_CALL ("j", operands, 1); } 5124169689Skan [(set_attr "type" "call")]) 5125169689Skan 5126169689Skan(define_expand "call" 5127169689Skan [(parallel [(call (match_operand 0 "") 5128169689Skan (match_operand 1 "")) 5129169689Skan (use (match_operand 2 "")) ;; next_arg_reg 5130169689Skan (use (match_operand 3 ""))])] ;; struct_value_size_rtx 5131169689Skan "" 5132169689Skan{ 5133169689Skan mips_expand_call (0, XEXP (operands[0], 0), operands[1], operands[2], false); 5134169689Skan DONE; 5135169689Skan}) 5136169689Skan 5137169689Skan;; This instruction directly corresponds to an assembly-language "jal". 5138169689Skan;; There are four cases: 5139169689Skan;; 5140169689Skan;; - -mno-abicalls: 5141169689Skan;; Both symbolic and register destinations are OK. The pattern 5142169689Skan;; always expands to a single mips instruction. 5143169689Skan;; 5144169689Skan;; - -mabicalls/-mno-explicit-relocs: 5145169689Skan;; Again, both symbolic and register destinations are OK. 5146169689Skan;; The call is treated as a multi-instruction black box. 5147169689Skan;; 5148169689Skan;; - -mabicalls/-mexplicit-relocs with n32 or n64: 5149169689Skan;; Only "jal $25" is allowed. This expands to a single "jalr $25" 5150169689Skan;; instruction. 5151169689Skan;; 5152169689Skan;; - -mabicalls/-mexplicit-relocs with o32 or o64: 5153169689Skan;; Only "jal $25" is allowed. The call is actually two instructions: 5154169689Skan;; "jalr $25" followed by an insn to reload $gp. 5155169689Skan;; 5156169689Skan;; In the last case, we can generate the individual instructions with 5157169689Skan;; a define_split. There are several things to be wary of: 5158169689Skan;; 5159169689Skan;; - We can't expose the load of $gp before reload. If we did, 5160169689Skan;; it might get removed as dead, but reload can introduce new 5161169689Skan;; uses of $gp by rematerializing constants. 5162169689Skan;; 5163169689Skan;; - We shouldn't restore $gp after calls that never return. 5164169689Skan;; It isn't valid to insert instructions between a noreturn 5165169689Skan;; call and the following barrier. 5166169689Skan;; 5167169689Skan;; - The splitter deliberately changes the liveness of $gp. The unsplit 5168169689Skan;; instruction preserves $gp and so have no effect on its liveness. 5169169689Skan;; But once we generate the separate insns, it becomes obvious that 5170169689Skan;; $gp is not live on entry to the call. 5171169689Skan;; 5172169689Skan;; ??? The operands[2] = insn check is a hack to make the original insn 5173169689Skan;; available to the splitter. 5174169689Skan(define_insn_and_split "call_internal" 5175169689Skan [(call (mem:SI (match_operand 0 "call_insn_operand" "c,S")) 5176169689Skan (match_operand 1 "" "")) 5177169689Skan (clobber (reg:SI 31))] 5178169689Skan "" 5179169689Skan { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0); } 5180169689Skan "reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)" 5181169689Skan [(const_int 0)] 5182169689Skan{ 5183169689Skan emit_call_insn (gen_call_split (operands[0], operands[1])); 5184169689Skan if (!find_reg_note (operands[2], REG_NORETURN, 0)) 5185169689Skan mips_restore_gp (); 5186169689Skan DONE; 5187169689Skan} 5188169689Skan [(set_attr "jal" "indirect,direct") 5189169689Skan (set_attr "extended_mips16" "no,yes")]) 5190169689Skan 5191169689Skan(define_insn "call_split" 5192169689Skan [(call (mem:SI (match_operand 0 "call_insn_operand" "cS")) 5193169689Skan (match_operand 1 "" "")) 5194169689Skan (clobber (reg:SI 31)) 5195169689Skan (clobber (reg:SI 28))] 5196169689Skan "TARGET_SPLIT_CALLS" 5197169689Skan { return MIPS_CALL ("jal", operands, 0); } 5198169689Skan [(set_attr "type" "call")]) 5199169689Skan 5200169689Skan(define_expand "call_value" 5201169689Skan [(parallel [(set (match_operand 0 "") 5202169689Skan (call (match_operand 1 "") 5203169689Skan (match_operand 2 ""))) 5204169689Skan (use (match_operand 3 ""))])] ;; next_arg_reg 5205169689Skan "" 5206169689Skan{ 5207169689Skan mips_expand_call (operands[0], XEXP (operands[1], 0), 5208169689Skan operands[2], operands[3], false); 5209169689Skan DONE; 5210169689Skan}) 5211169689Skan 5212169689Skan;; See comment for call_internal. 5213169689Skan(define_insn_and_split "call_value_internal" 5214169689Skan [(set (match_operand 0 "register_operand" "=df,df") 5215169689Skan (call (mem:SI (match_operand 1 "call_insn_operand" "c,S")) 5216169689Skan (match_operand 2 "" ""))) 5217169689Skan (clobber (reg:SI 31))] 5218169689Skan "" 5219169689Skan { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); } 5220169689Skan "reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)" 5221169689Skan [(const_int 0)] 5222169689Skan{ 5223169689Skan emit_call_insn (gen_call_value_split (operands[0], operands[1], 5224169689Skan operands[2])); 5225169689Skan if (!find_reg_note (operands[3], REG_NORETURN, 0)) 5226169689Skan mips_restore_gp (); 5227169689Skan DONE; 5228169689Skan} 5229169689Skan [(set_attr "jal" "indirect,direct") 5230169689Skan (set_attr "extended_mips16" "no,yes")]) 5231169689Skan 5232169689Skan(define_insn "call_value_split" 5233169689Skan [(set (match_operand 0 "register_operand" "=df") 5234169689Skan (call (mem:SI (match_operand 1 "call_insn_operand" "cS")) 5235169689Skan (match_operand 2 "" ""))) 5236169689Skan (clobber (reg:SI 31)) 5237169689Skan (clobber (reg:SI 28))] 5238169689Skan "TARGET_SPLIT_CALLS" 5239169689Skan { return MIPS_CALL ("jal", operands, 1); } 5240169689Skan [(set_attr "type" "call")]) 5241169689Skan 5242169689Skan;; See comment for call_internal. 5243169689Skan(define_insn_and_split "call_value_multiple_internal" 5244169689Skan [(set (match_operand 0 "register_operand" "=df,df") 5245169689Skan (call (mem:SI (match_operand 1 "call_insn_operand" "c,S")) 5246169689Skan (match_operand 2 "" ""))) 5247169689Skan (set (match_operand 3 "register_operand" "=df,df") 5248169689Skan (call (mem:SI (match_dup 1)) 5249169689Skan (match_dup 2))) 5250169689Skan (clobber (reg:SI 31))] 5251169689Skan "" 5252169689Skan { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); } 5253169689Skan "reload_completed && TARGET_SPLIT_CALLS && (operands[4] = insn)" 5254169689Skan [(const_int 0)] 5255169689Skan{ 5256169689Skan emit_call_insn (gen_call_value_multiple_split (operands[0], operands[1], 5257169689Skan operands[2], operands[3])); 5258169689Skan if (!find_reg_note (operands[4], REG_NORETURN, 0)) 5259169689Skan mips_restore_gp (); 5260169689Skan DONE; 5261169689Skan} 5262169689Skan [(set_attr "jal" "indirect,direct") 5263169689Skan (set_attr "extended_mips16" "no,yes")]) 5264169689Skan 5265169689Skan(define_insn "call_value_multiple_split" 5266169689Skan [(set (match_operand 0 "register_operand" "=df") 5267169689Skan (call (mem:SI (match_operand 1 "call_insn_operand" "cS")) 5268169689Skan (match_operand 2 "" ""))) 5269169689Skan (set (match_operand 3 "register_operand" "=df") 5270169689Skan (call (mem:SI (match_dup 1)) 5271169689Skan (match_dup 2))) 5272169689Skan (clobber (reg:SI 31)) 5273169689Skan (clobber (reg:SI 28))] 5274169689Skan "TARGET_SPLIT_CALLS" 5275169689Skan { return MIPS_CALL ("jal", operands, 1); } 5276169689Skan [(set_attr "type" "call")]) 5277169689Skan 5278169689Skan;; Call subroutine returning any type. 5279169689Skan 5280169689Skan(define_expand "untyped_call" 5281169689Skan [(parallel [(call (match_operand 0 "") 5282169689Skan (const_int 0)) 5283169689Skan (match_operand 1 "") 5284169689Skan (match_operand 2 "")])] 5285169689Skan "" 5286169689Skan{ 5287169689Skan int i; 5288169689Skan 5289169689Skan emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); 5290169689Skan 5291169689Skan for (i = 0; i < XVECLEN (operands[2], 0); i++) 5292169689Skan { 5293169689Skan rtx set = XVECEXP (operands[2], 0, i); 5294169689Skan emit_move_insn (SET_DEST (set), SET_SRC (set)); 5295169689Skan } 5296169689Skan 5297169689Skan emit_insn (gen_blockage ()); 5298169689Skan DONE; 5299169689Skan}) 5300169689Skan 5301169689Skan;; 5302169689Skan;; .................... 5303169689Skan;; 5304169689Skan;; MISC. 5305169689Skan;; 5306169689Skan;; .................... 5307169689Skan;; 5308169689Skan 5309169689Skan 5310169689Skan(define_insn "prefetch" 5311169689Skan [(prefetch (match_operand:QI 0 "address_operand" "p") 5312169689Skan (match_operand 1 "const_int_operand" "n") 5313169689Skan (match_operand 2 "const_int_operand" "n"))] 5314169689Skan "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS" 5315169689Skan{ 5316169689Skan operands[1] = mips_prefetch_cookie (operands[1], operands[2]); 5317169689Skan return "pref\t%1,%a0"; 5318169689Skan} 5319169689Skan [(set_attr "type" "prefetch")]) 5320169689Skan 5321169689Skan(define_insn "*prefetch_indexed_<mode>" 5322169689Skan [(prefetch (plus:P (match_operand:P 0 "register_operand" "d") 5323169689Skan (match_operand:P 1 "register_operand" "d")) 5324169689Skan (match_operand 2 "const_int_operand" "n") 5325169689Skan (match_operand 3 "const_int_operand" "n"))] 5326169689Skan "ISA_HAS_PREFETCHX && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" 5327169689Skan{ 5328169689Skan operands[2] = mips_prefetch_cookie (operands[2], operands[3]); 5329169689Skan return "prefx\t%2,%1(%0)"; 5330169689Skan} 5331169689Skan [(set_attr "type" "prefetchx")]) 5332169689Skan 5333169689Skan(define_insn "nop" 5334169689Skan [(const_int 0)] 5335169689Skan "" 5336169689Skan "%(nop%)" 5337169689Skan [(set_attr "type" "nop") 5338169689Skan (set_attr "mode" "none")]) 5339169689Skan 5340169689Skan;; Like nop, but commented out when outside a .set noreorder block. 5341169689Skan(define_insn "hazard_nop" 5342169689Skan [(const_int 1)] 5343169689Skan "" 5344169689Skan { 5345169689Skan if (set_noreorder) 5346169689Skan return "nop"; 5347169689Skan else 5348169689Skan return "#nop"; 5349169689Skan } 5350169689Skan [(set_attr "type" "nop")]) 5351169689Skan 5352169689Skan;; MIPS4 Conditional move instructions. 5353169689Skan 5354169689Skan(define_insn "*mov<GPR:mode>_on_<MOVECC:mode>" 5355169689Skan [(set (match_operand:GPR 0 "register_operand" "=d,d") 5356169689Skan (if_then_else:GPR 5357169689Skan (match_operator:MOVECC 4 "equality_operator" 5358169689Skan [(match_operand:MOVECC 1 "register_operand" "<MOVECC:reg>,<MOVECC:reg>") 5359169689Skan (const_int 0)]) 5360169689Skan (match_operand:GPR 2 "reg_or_0_operand" "dJ,0") 5361169689Skan (match_operand:GPR 3 "reg_or_0_operand" "0,dJ")))] 5362169689Skan "ISA_HAS_CONDMOVE" 5363169689Skan "@ 5364169689Skan mov%T4\t%0,%z2,%1 5365169689Skan mov%t4\t%0,%z3,%1" 5366169689Skan [(set_attr "type" "condmove") 5367169689Skan (set_attr "mode" "<GPR:MODE>")]) 5368169689Skan 5369169689Skan(define_insn "*mov<SCALARF:mode>_on_<MOVECC:mode>" 5370169689Skan [(set (match_operand:SCALARF 0 "register_operand" "=f,f") 5371169689Skan (if_then_else:SCALARF 5372169689Skan (match_operator:MOVECC 4 "equality_operator" 5373169689Skan [(match_operand:MOVECC 1 "register_operand" "<MOVECC:reg>,<MOVECC:reg>") 5374169689Skan (const_int 0)]) 5375169689Skan (match_operand:SCALARF 2 "register_operand" "f,0") 5376169689Skan (match_operand:SCALARF 3 "register_operand" "0,f")))] 5377169689Skan "ISA_HAS_CONDMOVE" 5378169689Skan "@ 5379169689Skan mov%T4.<fmt>\t%0,%2,%1 5380169689Skan mov%t4.<fmt>\t%0,%3,%1" 5381169689Skan [(set_attr "type" "condmove") 5382169689Skan (set_attr "mode" "<SCALARF:MODE>")]) 5383169689Skan 5384169689Skan;; These are the main define_expand's used to make conditional moves. 5385169689Skan 5386169689Skan(define_expand "mov<mode>cc" 5387169689Skan [(set (match_dup 4) (match_operand 1 "comparison_operator")) 5388169689Skan (set (match_operand:GPR 0 "register_operand") 5389169689Skan (if_then_else:GPR (match_dup 5) 5390169689Skan (match_operand:GPR 2 "reg_or_0_operand") 5391169689Skan (match_operand:GPR 3 "reg_or_0_operand")))] 5392169689Skan "ISA_HAS_CONDMOVE" 5393169689Skan{ 5394169689Skan gen_conditional_move (operands); 5395169689Skan DONE; 5396169689Skan}) 5397169689Skan 5398169689Skan(define_expand "mov<mode>cc" 5399169689Skan [(set (match_dup 4) (match_operand 1 "comparison_operator")) 5400169689Skan (set (match_operand:SCALARF 0 "register_operand") 5401169689Skan (if_then_else:SCALARF (match_dup 5) 5402169689Skan (match_operand:SCALARF 2 "register_operand") 5403169689Skan (match_operand:SCALARF 3 "register_operand")))] 5404169689Skan "ISA_HAS_CONDMOVE" 5405169689Skan{ 5406169689Skan gen_conditional_move (operands); 5407169689Skan DONE; 5408169689Skan}) 5409169689Skan 5410169689Skan;; 5411169689Skan;; .................... 5412169689Skan;; 5413169689Skan;; mips16 inline constant tables 5414169689Skan;; 5415169689Skan;; .................... 5416169689Skan;; 5417169689Skan 5418169689Skan(define_insn "consttable_int" 5419169689Skan [(unspec_volatile [(match_operand 0 "consttable_operand" "") 5420169689Skan (match_operand 1 "const_int_operand" "")] 5421169689Skan UNSPEC_CONSTTABLE_INT)] 5422169689Skan "TARGET_MIPS16" 5423169689Skan{ 5424169689Skan assemble_integer (operands[0], INTVAL (operands[1]), 5425169689Skan BITS_PER_UNIT * INTVAL (operands[1]), 1); 5426169689Skan return ""; 5427169689Skan} 5428169689Skan [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))]) 5429169689Skan 5430169689Skan(define_insn "consttable_float" 5431169689Skan [(unspec_volatile [(match_operand 0 "consttable_operand" "")] 5432169689Skan UNSPEC_CONSTTABLE_FLOAT)] 5433169689Skan "TARGET_MIPS16" 5434169689Skan{ 5435169689Skan REAL_VALUE_TYPE d; 5436169689Skan 5437169689Skan gcc_assert (GET_CODE (operands[0]) == CONST_DOUBLE); 5438169689Skan REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]); 5439169689Skan assemble_real (d, GET_MODE (operands[0]), 5440169689Skan GET_MODE_BITSIZE (GET_MODE (operands[0]))); 5441169689Skan return ""; 5442169689Skan} 5443169689Skan [(set (attr "length") 5444169689Skan (symbol_ref "GET_MODE_SIZE (GET_MODE (operands[0]))"))]) 5445169689Skan 5446169689Skan(define_insn "align" 5447169689Skan [(unspec_volatile [(match_operand 0 "const_int_operand" "")] UNSPEC_ALIGN)] 5448169689Skan "" 5449169689Skan ".align\t%0" 5450169689Skan [(set (attr "length") (symbol_ref "(1 << INTVAL (operands[0])) - 1"))]) 5451169689Skan 5452169689Skan(define_split 5453169689Skan [(match_operand 0 "small_data_pattern")] 5454169689Skan "reload_completed" 5455169689Skan [(match_dup 0)] 5456169689Skan { operands[0] = mips_rewrite_small_data (operands[0]); }) 5457169689Skan 5458169689Skan; Thread-Local Storage 5459169689Skan 5460169689Skan; The TLS base pointer is accessed via "rdhwr $v1, $29". No current 5461169689Skan; MIPS architecture defines this register, and no current 5462169689Skan; implementation provides it; instead, any OS which supports TLS is 5463169689Skan; expected to trap and emulate this instruction. rdhwr is part of the 5464169689Skan; MIPS 32r2 specification, but we use it on any architecture because 5465169689Skan; we expect it to be emulated. Use .set to force the assembler to 5466169689Skan; accept it. 5467169689Skan 5468169689Skan(define_insn "tls_get_tp_<mode>" 5469169689Skan [(set (match_operand:P 0 "register_operand" "=v") 5470169689Skan (unspec:P [(const_int 0)] 5471169689Skan UNSPEC_TLS_GET_TP))] 5472169689Skan "HAVE_AS_TLS && !TARGET_MIPS16" 5473169689Skan ".set\tpush\;.set\tmips32r2\t\;rdhwr\t%0,$29\;.set\tpop" 5474169689Skan [(set_attr "type" "unknown") 5475169689Skan ; Since rdhwr always generates a trap for now, putting it in a delay 5476169689Skan ; slot would make the kernel's emulation of it much slower. 5477169689Skan (set_attr "can_delay" "no") 5478169689Skan (set_attr "mode" "<MODE>")]) 5479169689Skan 5480169689Skan; The MIPS Paired-Single Floating Point and MIPS-3D Instructions. 5481169689Skan 5482169689Skan(include "mips-ps-3d.md") 5483169689Skan 5484169689Skan; The MIPS DSP Instructions. 5485169689Skan 5486169689Skan(include "mips-dsp.md") 5487