diff options
Diffstat (limited to 'gcc-4.8.1/gcc/config/mips/mips.md')
-rw-r--r-- | gcc-4.8.1/gcc/config/mips/mips.md | 6930 |
1 files changed, 0 insertions, 6930 deletions
diff --git a/gcc-4.8.1/gcc/config/mips/mips.md b/gcc-4.8.1/gcc/config/mips/mips.md deleted file mode 100644 index 7aa461dbd..000000000 --- a/gcc-4.8.1/gcc/config/mips/mips.md +++ /dev/null @@ -1,6930 +0,0 @@ -;; Mips.md Machine Description for MIPS based processors -;; Copyright (C) 1989-2013 Free Software Foundation, Inc. -;; Contributed by A. Lichnewsky, lich@inria.inria.fr -;; Changes by Michael Meissner, meissner@osf.org -;; 64-bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and -;; Brendan Eich, brendan@microunity.com. - -;; This file is part of GCC. - -;; GCC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. - -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not see -;; <http://www.gnu.org/licenses/>. - -(define_enum "processor" [ - r3000 - 4kc - 4kp - 5kc - 5kf - 20kc - 24kc - 24kf2_1 - 24kf1_1 - 74kc - 74kf2_1 - 74kf1_1 - 74kf3_2 - loongson_2e - loongson_2f - loongson_3a - m4k - octeon - octeon2 - r3900 - r6000 - r4000 - r4100 - r4111 - r4120 - r4130 - r4300 - r4600 - r4650 - r4700 - r5000 - r5400 - r5500 - r7000 - r8000 - r9000 - r10000 - sb1 - sb1a - sr71000 - xlr - xlp -]) - -(define_c_enum "unspec" [ - ;; Unaligned accesses. - UNSPEC_LOAD_LEFT - UNSPEC_LOAD_RIGHT - UNSPEC_STORE_LEFT - UNSPEC_STORE_RIGHT - - ;; Floating-point moves. - UNSPEC_LOAD_LOW - UNSPEC_LOAD_HIGH - UNSPEC_STORE_WORD - UNSPEC_MFHC1 - UNSPEC_MTHC1 - - ;; HI/LO moves. - UNSPEC_MFHI - UNSPEC_MTHI - UNSPEC_SET_HILO - - ;; GP manipulation. - UNSPEC_LOADGP - UNSPEC_COPYGP - UNSPEC_MOVE_GP - UNSPEC_POTENTIAL_CPRESTORE - UNSPEC_CPRESTORE - UNSPEC_RESTORE_GP - UNSPEC_EH_RETURN - UNSPEC_GP - UNSPEC_SET_GOT_VERSION - UNSPEC_UPDATE_GOT_VERSION - - ;; Symbolic accesses. - UNSPEC_LOAD_CALL - UNSPEC_LOAD_GOT - UNSPEC_TLS_LDM - UNSPEC_TLS_GET_TP - UNSPEC_UNSHIFTED_HIGH - - ;; MIPS16 constant pools. - UNSPEC_ALIGN - UNSPEC_CONSTTABLE_INT - UNSPEC_CONSTTABLE_FLOAT - - ;; Blockage and synchronisation. - UNSPEC_BLOCKAGE - UNSPEC_CLEAR_HAZARD - UNSPEC_RDHWR - UNSPEC_SYNCI - UNSPEC_SYNC - - ;; Cache manipulation. - UNSPEC_MIPS_CACHE - UNSPEC_R10K_CACHE_BARRIER - - ;; Interrupt handling. - UNSPEC_ERET - UNSPEC_DERET - UNSPEC_DI - UNSPEC_EHB - UNSPEC_RDPGPR - UNSPEC_COP0 - - ;; Used in a call expression in place of args_size. It's present for PIC - ;; indirect calls where it contains args_size and the function symbol. - UNSPEC_CALL_ATTR - - ;; MIPS16 casesi jump table dispatch. - UNSPEC_CASESI_DISPATCH - - ;; Stack checking. - UNSPEC_PROBE_STACK_RANGE -]) - -(define_constants - [(TLS_GET_TP_REGNUM 3) - (MIPS16_T_REGNUM 24) - (PIC_FUNCTION_ADDR_REGNUM 25) - (RETURN_ADDR_REGNUM 31) - (CPRESTORE_SLOT_REGNUM 76) - (GOT_VERSION_REGNUM 79) - - ;; PIC long branch sequences are never longer than 100 bytes. - (MAX_PIC_BRANCH_LENGTH 100) - ] -) - -(include "predicates.md") -(include "constraints.md") - -;; .................... -;; -;; Attributes -;; -;; .................... - -(define_attr "got" "unset,xgot_high,load" - (const_string "unset")) - -;; For jal instructions, this attribute is DIRECT when the target address -;; is symbolic and INDIRECT when it is a register. -(define_attr "jal" "unset,direct,indirect" - (const_string "unset")) - -;; This attribute is YES if the instruction is a jal macro (not a -;; real jal instruction). -;; -;; jal is always a macro for TARGET_CALL_CLOBBERED_GP because it includes -;; an instruction to restore $gp. Direct jals are also macros for -;; !TARGET_ABSOLUTE_JUMPS because they first load the target address -;; into a register. -(define_attr "jal_macro" "no,yes" - (cond [(eq_attr "jal" "direct") - (symbol_ref "(TARGET_CALL_CLOBBERED_GP || !TARGET_ABSOLUTE_JUMPS - ? JAL_MACRO_YES : JAL_MACRO_NO)") - (eq_attr "jal" "indirect") - (symbol_ref "(TARGET_CALL_CLOBBERED_GP - ? JAL_MACRO_YES : JAL_MACRO_NO)")] - (const_string "no"))) - -;; Classification of moves, extensions and truncations. Most values -;; are as for "type" (see below) but there are also the following -;; move-specific values: -;; -;; constN move an N-constraint integer into a MIPS16 register -;; sll0 "sll DEST,SRC,0", which on 64-bit targets is guaranteed -;; to produce a sign-extended DEST, even if SRC is not -;; properly sign-extended -;; ext_ins EXT, DEXT, INS or DINS instruction -;; andi a single ANDI instruction -;; loadpool move a constant into a MIPS16 register by loading it -;; from the pool -;; shift_shift a shift left followed by a shift right -;; -;; This attribute is used to determine the instruction's length and -;; scheduling type. For doubleword moves, the attribute always describes -;; the split instructions; in some cases, it is more appropriate for the -;; scheduling type to be "multi" instead. -(define_attr "move_type" - "unknown,load,fpload,store,fpstore,mtc,mfc,mtlo,mflo,imul,move,fmove, - const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool, - shift_shift" - (const_string "unknown")) - -(define_attr "alu_type" "unknown,add,sub,not,nor,and,or,xor" - (const_string "unknown")) - -;; Main data type used by the insn -(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,SF,DF,TF,FPSW" - (const_string "unknown")) - -;; True if the main data type is twice the size of a word. -(define_attr "dword_mode" "no,yes" - (cond [(and (eq_attr "mode" "DI,DF") - (not (match_test "TARGET_64BIT"))) - (const_string "yes") - - (and (eq_attr "mode" "TI,TF") - (match_test "TARGET_64BIT")) - (const_string "yes")] - (const_string "no"))) - -;; Attributes describing a sync loop. These loops have the form: -;; -;; if (RELEASE_BARRIER == YES) sync -;; 1: OLDVAL = *MEM -;; if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2 -;; CMP = 0 [delay slot] -;; $TMP1 = OLDVAL & EXCLUSIVE_MASK -;; $TMP2 = INSN1 (OLDVAL, INSN1_OP2) -;; $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK) -;; $AT |= $TMP1 | $TMP3 -;; if (!commit (*MEM = $AT)) goto 1. -;; if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot] -;; CMP = 1 -;; if (ACQUIRE_BARRIER == YES) sync -;; 2: -;; -;; where "$" values are temporaries and where the other values are -;; specified by the attributes below. Values are specified as operand -;; numbers and insns are specified as enums. If no operand number is -;; specified, the following values are used instead: -;; -;; - OLDVAL: $AT -;; - CMP: NONE -;; - NEWVAL: $AT -;; - INCLUSIVE_MASK: -1 -;; - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK -;; - EXCLUSIVE_MASK: 0 -;; -;; MEM and INSN1_OP2 are required. -;; -;; Ideally, the operand attributes would be integers, with -1 meaning "none", -;; but the gen* programs don't yet support that. -(define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_cmp" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_required_oldval" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_insn1_op2" "none,0,1,2,3,4,5" (const_string "none")) -(define_attr "sync_insn1" "move,li,addu,addiu,subu,and,andi,or,ori,xor,xori" - (const_string "move")) -(define_attr "sync_insn2" "nop,and,xor,not" - (const_string "nop")) -;; Memory model specifier. -;; "0"-"9" values specify the operand that stores the memory model value. -;; "10" specifies MEMMODEL_ACQ_REL, -;; "11" specifies MEMMODEL_ACQUIRE. -(define_attr "sync_memmodel" "" (const_int 10)) - -;; Accumulator operand for madd patterns. -(define_attr "accum_in" "none,0,1,2,3,4,5" (const_string "none")) - -;; Classification of each insn. -;; branch conditional branch -;; jump unconditional jump -;; call unconditional call -;; load load instruction(s) -;; fpload floating point load -;; fpidxload floating point indexed load -;; store store instruction(s) -;; fpstore floating point store -;; fpidxstore floating point indexed store -;; prefetch memory prefetch (register + offset) -;; prefetchx memory indexed prefetch (register + register) -;; condmove conditional moves -;; mtc transfer to coprocessor -;; mfc transfer from coprocessor -;; mthi transfer to a hi register -;; mtlo transfer to a lo register -;; mfhi transfer from a hi register -;; mflo transfer from a lo register -;; const load constant -;; arith integer arithmetic instructions -;; logical integer logical instructions -;; shift integer shift instructions -;; slt set less than instructions -;; signext sign extend instructions -;; clz the clz and clo instructions -;; pop the pop instruction -;; trap trap if instructions -;; imul integer multiply 2 operands -;; imul3 integer multiply 3 operands -;; imul3nc integer multiply 3 operands without clobbering HI/LO -;; imadd integer multiply-add -;; idiv integer divide 2 operands -;; idiv3 integer divide 3 operands -;; move integer register move ({,D}ADD{,U} with rt = 0) -;; fmove floating point register move -;; fadd floating point add/subtract -;; fmul floating point multiply -;; fmadd floating point multiply-add -;; fdiv floating point divide -;; frdiv floating point reciprocal divide -;; frdiv1 floating point reciprocal divide step 1 -;; frdiv2 floating point reciprocal divide step 2 -;; fabs floating point absolute value -;; fneg floating point negation -;; fcmp floating point compare -;; fcvt floating point convert -;; fsqrt floating point square root -;; frsqrt floating point reciprocal square root -;; frsqrt1 floating point reciprocal square root step1 -;; frsqrt2 floating point reciprocal square root step2 -;; dspmac DSP MAC instructions not saturating the accumulator -;; dspmacsat DSP MAC instructions that saturate the accumulator -;; accext DSP accumulator extract instructions -;; accmod DSP accumulator modify instructions -;; dspalu DSP ALU instructions not saturating the result -;; dspalusat DSP ALU instructions that saturate the result -;; multi multiword sequence (or user asm statements) -;; atomic atomic memory update instruction -;; syncloop memory atomic operation implemented as a sync loop -;; nop no operation -;; ghost an instruction that produces no real code -(define_attr "type" - "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore, - prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical, - shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move, - fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt, - frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat, - multi,atomic,syncloop,nop,ghost" - (cond [(eq_attr "jal" "!unset") (const_string "call") - (eq_attr "got" "load") (const_string "load") - - (eq_attr "alu_type" "add,sub") (const_string "arith") - - (eq_attr "alu_type" "not,nor,and,or,xor") (const_string "logical") - - ;; If a doubleword move uses these expensive instructions, - ;; it is usually better to schedule them in the same way - ;; as the singleword form, rather than as "multi". - (eq_attr "move_type" "load") (const_string "load") - (eq_attr "move_type" "fpload") (const_string "fpload") - (eq_attr "move_type" "store") (const_string "store") - (eq_attr "move_type" "fpstore") (const_string "fpstore") - (eq_attr "move_type" "mtc") (const_string "mtc") - (eq_attr "move_type" "mfc") (const_string "mfc") - (eq_attr "move_type" "mtlo") (const_string "mtlo") - (eq_attr "move_type" "mflo") (const_string "mflo") - - ;; These types of move are always single insns. - (eq_attr "move_type" "imul") (const_string "imul") - (eq_attr "move_type" "fmove") (const_string "fmove") - (eq_attr "move_type" "loadpool") (const_string "load") - (eq_attr "move_type" "signext") (const_string "signext") - (eq_attr "move_type" "ext_ins") (const_string "arith") - (eq_attr "move_type" "arith") (const_string "arith") - (eq_attr "move_type" "logical") (const_string "logical") - (eq_attr "move_type" "sll0") (const_string "shift") - (eq_attr "move_type" "andi") (const_string "logical") - - ;; These types of move are always split. - (eq_attr "move_type" "constN,shift_shift") - (const_string "multi") - - ;; These types of move are split for doubleword modes only. - (and (eq_attr "move_type" "move,const") - (eq_attr "dword_mode" "yes")) - (const_string "multi") - (eq_attr "move_type" "move") (const_string "move") - (eq_attr "move_type" "const") (const_string "const") - (eq_attr "sync_mem" "!none") (const_string "syncloop")] - (const_string "unknown"))) - -;; Mode for conversion types (fcvt) -;; I2S integer to float single (SI/DI to SF) -;; I2D integer to float double (SI/DI to DF) -;; S2I float to integer (SF to SI/DI) -;; D2I float to integer (DF to SI/DI) -;; D2S double to float single -;; S2D float single to double - -(define_attr "cnv_mode" "unknown,I2S,I2D,S2I,D2I,D2S,S2D" - (const_string "unknown")) - -;; Is this an extended instruction in mips16 mode? -(define_attr "extended_mips16" "no,yes" - (if_then_else (ior (eq_attr "move_type" "sll0") - (eq_attr "type" "branch") - (eq_attr "jal" "direct")) - (const_string "yes") - (const_string "no"))) - -;; Length of instruction in bytes. -(define_attr "length" "" - (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc], - ;; relative to the address of the delay slot. If a branch is - ;; outside this range, we have a choice of two sequences. - ;; For PIC, an out-of-range branch like: - ;; - ;; bne r1,r2,target - ;; dslot - ;; - ;; becomes the equivalent of: - ;; - ;; beq r1,r2,1f - ;; dslot - ;; la $at,target - ;; jr $at - ;; nop - ;; 1: - ;; - ;; The non-PIC case is similar except that we use a direct - ;; jump instead of an la/jr pair. Since the target of this - ;; jump is an absolute 28-bit bit address (the other bits - ;; coming from the address of the delay slot) this form cannot - ;; cross a 256MB boundary. We could provide the option of - ;; using la/jr in this case too, but we do not do so at - ;; present. - ;; - ;; The value we specify here does not account for the delay slot - ;; instruction, whose length is added separately. If the RTL - ;; pattern has no explicit delay slot, mips_adjust_insn_length - ;; will add the length of the implicit nop. The range of - ;; [-0x20000, 0x1fffc] from the address of the delay slot - ;; therefore translates to a range of: - ;; - ;; [-(0x20000 - sizeof (branch)), 0x1fffc - sizeof (slot)] - ;; == [-0x1fffc, 0x1fff8] - ;; - ;; from the shorten_branches reference address. - (and (eq_attr "type" "branch") - (not (match_test "TARGET_MIPS16"))) - (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064)) - (le (minus (pc) (match_dup 0)) (const_int 131068))) - (const_int 4) - - ;; The non-PIC case: branch, first delay slot, and J. - (match_test "TARGET_ABSOLUTE_JUMPS") - (const_int 12)] - - ;; Use MAX_PIC_BRANCH_LENGTH as a (gross) overestimate. - ;; mips_adjust_insn_length substitutes the correct length. - ;; - ;; Note that we can't simply use (symbol_ref ...) here - ;; because genattrtab needs to know the maximum length - ;; of an insn. - (const_int MAX_PIC_BRANCH_LENGTH)) - - ;; An unextended MIPS16 branch has a range of [-0x100, 0xfe] - ;; from the address of the following instruction, which leads - ;; to a range of: - ;; - ;; [-(0x100 - sizeof (branch)), 0xfe] - ;; == [-0xfe, 0xfe] - ;; - ;; from the shorten_branches reference address. Extended branches - ;; likewise have a range of [-0x10000, 0xfffe] from the address - ;; of the following instruction, which leads to a range of: - ;; - ;; [-(0x10000 - sizeof (branch)), 0xfffe] - ;; == [-0xfffc, 0xfffe] - ;; - ;; from the reference address. - ;; - ;; When a branch is out of range, mips_reorg splits it into a form - ;; that uses in-range branches. There are four basic sequences: - ;; - ;; (1) Absolute addressing with a readable text segment - ;; (32-bit addresses): - ;; - ;; b... foo 2 bytes - ;; move $1,$2 2 bytes - ;; lw $2,label 2 bytes - ;; jr $2 2 bytes - ;; move $2,$1 2 bytes - ;; .align 2 0 or 2 bytes - ;; label: - ;; .word target 4 bytes - ;; foo: - ;; (16 bytes in the worst case) - ;; - ;; (2) Absolute addressing with a readable text segment - ;; (64-bit addresses): - ;; - ;; b... foo 2 bytes - ;; move $1,$2 2 bytes - ;; ld $2,label 2 bytes - ;; jr $2 2 bytes - ;; move $2,$1 2 bytes - ;; .align 3 0 to 6 bytes - ;; label: - ;; .dword target 8 bytes - ;; foo: - ;; (24 bytes in the worst case) - ;; - ;; (3) Absolute addressing without a readable text segment - ;; (which requires 32-bit addresses at present): - ;; - ;; b... foo 2 bytes - ;; move $1,$2 2 bytes - ;; lui $2,%hi(target) 4 bytes - ;; sll $2,8 2 bytes - ;; sll $2,8 2 bytes - ;; addiu $2,%lo(target) 4 bytes - ;; jr $2 2 bytes - ;; move $2,$1 2 bytes - ;; foo: - ;; (20 bytes) - ;; - ;; (4) PIC addressing (which requires 32-bit addresses at present): - ;; - ;; b... foo 2 bytes - ;; move $1,$2 2 bytes - ;; lw $2,cprestore 0, 2 or 4 bytes - ;; lw $2,%got(target)($2) 4 bytes - ;; addiu $2,%lo(target) 4 bytes - ;; jr $2 2 bytes - ;; move $2,$1 2 bytes - ;; foo: - ;; (20 bytes in the worst case) - ;; - ;; Note that the conditions test adjusted lengths, whereas the - ;; result is an unadjusted length, and is thus twice the true value. - (and (eq_attr "type" "branch") - (match_test "TARGET_MIPS16")) - (cond [(and (le (minus (match_dup 0) (pc)) (const_int 254)) - (le (minus (pc) (match_dup 0)) (const_int 254))) - (const_int 4) - (and (le (minus (match_dup 0) (pc)) (const_int 65534)) - (le (minus (pc) (match_dup 0)) (const_int 65532))) - (const_int 8) - (and (match_test "TARGET_ABICALLS") - (not (match_test "TARGET_ABSOLUTE_ABICALLS"))) - (const_int 40) - (match_test "Pmode == SImode") - (const_int 32) - ] (const_int 48)) - - (and (eq_attr "extended_mips16" "yes") - (match_test "TARGET_MIPS16")) - (const_int 8) - - ;; "Ghost" instructions occupy no space. - (eq_attr "type" "ghost") - (const_int 0) - - (eq_attr "got" "load") - (if_then_else (match_test "TARGET_MIPS16") - (const_int 8) - (const_int 4)) - (eq_attr "got" "xgot_high") - (const_int 8) - - ;; In general, constant-pool loads are extended instructions. - (eq_attr "move_type" "loadpool") - (const_int 8) - - ;; SHIFT_SHIFTs are decomposed into two separate instructions. - ;; They are extended instructions on MIPS16 targets. - (eq_attr "move_type" "shift_shift") - (if_then_else (match_test "TARGET_MIPS16") - (const_int 16) - (const_int 8)) - - ;; Check for doubleword moves that are decomposed into two - ;; instructions. - (and (eq_attr "move_type" "mtc,mfc,mtlo,mflo,move") - (eq_attr "dword_mode" "yes")) - (const_int 8) - - ;; Doubleword CONST{,N} moves are split into two word - ;; CONST{,N} moves. - (and (eq_attr "move_type" "const,constN") - (eq_attr "dword_mode" "yes")) - (symbol_ref "mips_split_const_insns (operands[1]) * 4") - - ;; Otherwise, constants, loads and stores are handled by external - ;; routines. - (eq_attr "move_type" "const,constN") - (symbol_ref "mips_const_insns (operands[1]) * 4") - (eq_attr "move_type" "load,fpload") - (symbol_ref "mips_load_store_insns (operands[1], insn) * 4") - (eq_attr "move_type" "store,fpstore") - (cond [(not (match_test "TARGET_FIX_24K")) - (symbol_ref "mips_load_store_insns (operands[0], insn) * 4")] - (symbol_ref "mips_load_store_insns (operands[0], insn) * 4 + 4")) - - ;; In the worst case, a call macro will take 8 instructions: - ;; - ;; lui $25,%call_hi(FOO) - ;; addu $25,$25,$28 - ;; lw $25,%call_lo(FOO)($25) - ;; nop - ;; jalr $25 - ;; nop - ;; lw $gp,X($sp) - ;; nop - (eq_attr "jal_macro" "yes") - (const_int 32) - - ;; Various VR4120 errata require a nop to be inserted after a macc - ;; instruction. The assembler does this for us, so account for - ;; the worst-case length here. - (and (eq_attr "type" "imadd") - (match_test "TARGET_FIX_VR4120")) - (const_int 8) - - ;; VR4120 errata MD(4): if there are consecutive dmult instructions, - ;; the result of the second one is missed. The assembler should work - ;; around this by inserting a nop after the first dmult. - (and (eq_attr "type" "imul,imul3") - (and (eq_attr "mode" "DI") - (match_test "TARGET_FIX_VR4120"))) - (const_int 8) - - (eq_attr "type" "idiv,idiv3") - (symbol_ref "mips_idiv_insns () * 4") - - (not (eq_attr "sync_mem" "none")) - (symbol_ref "mips_sync_loop_insns (insn, operands) * 4") - ] (const_int 4))) - -;; Attribute describing the processor. -(define_enum_attr "cpu" "processor" - (const (symbol_ref "mips_tune"))) - -;; The type of hardware hazard associated with this instruction. -;; DELAY means that the next instruction cannot read the result -;; of this one. HILO means that the next two instructions cannot -;; write to HI or LO. -(define_attr "hazard" "none,delay,hilo" - (cond [(and (eq_attr "type" "load,fpload,fpidxload") - (match_test "ISA_HAS_LOAD_DELAY")) - (const_string "delay") - - (and (eq_attr "type" "mfc,mtc") - (match_test "ISA_HAS_XFER_DELAY")) - (const_string "delay") - - (and (eq_attr "type" "fcmp") - (match_test "ISA_HAS_FCMP_DELAY")) - (const_string "delay") - - ;; The r4000 multiplication patterns include an mflo instruction. - (and (eq_attr "type" "imul") - (match_test "TARGET_FIX_R4000")) - (const_string "hilo") - - (and (eq_attr "type" "mfhi,mflo") - (not (match_test "ISA_HAS_HILO_INTERLOCKS"))) - (const_string "hilo")] - (const_string "none"))) - -;; Is it a single instruction? -(define_attr "single_insn" "no,yes" - (symbol_ref "(get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4) - ? SINGLE_INSN_YES : SINGLE_INSN_NO)")) - -;; Can the instruction be put into a delay slot? -(define_attr "can_delay" "no,yes" - (if_then_else (and (eq_attr "type" "!branch,call,jump") - (and (eq_attr "hazard" "none") - (eq_attr "single_insn" "yes"))) - (const_string "yes") - (const_string "no"))) - -;; Attribute defining whether or not we can use the branch-likely -;; instructions. -(define_attr "branch_likely" "no,yes" - (if_then_else (match_test "GENERATE_BRANCHLIKELY") - (const_string "yes") - (const_string "no"))) - -;; True if an instruction might assign to hi or lo when reloaded. -;; This is used by the TUNE_MACC_CHAINS code. -(define_attr "may_clobber_hilo" "no,yes" - (if_then_else (eq_attr "type" "imul,imul3,imadd,idiv,mthi,mtlo") - (const_string "yes") - (const_string "no"))) - -;; Describe a user's asm statement. -(define_asm_attributes - [(set_attr "type" "multi") - (set_attr "can_delay" "no")]) - -;; This mode iterator allows 32-bit and 64-bit GPR patterns to be generated -;; from the same template. -(define_mode_iterator GPR [SI (DI "TARGET_64BIT")]) - -;; A copy of GPR that can be used when a pattern has two independent -;; modes. -(define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")]) - -;; This mode iterator allows :HILO to be used as the mode of the -;; concatenated HI and LO registers. -(define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")]) - -;; This mode iterator allows :P to be used for patterns that operate on -;; pointer-sized quantities. Exactly one of the two alternatives will match. -(define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) - -;; This mode iterator allows :MOVECC to be used anywhere that a -;; conditional-move-type condition is needed. -(define_mode_iterator MOVECC [SI (DI "TARGET_64BIT") - (CC "TARGET_HARD_FLOAT && !TARGET_LOONGSON_2EF")]) - -;; 32-bit integer moves for which we provide move patterns. -(define_mode_iterator IMOVE32 - [SI - (V2HI "TARGET_DSP") - (V4QI "TARGET_DSP") - (V2HQ "TARGET_DSP") - (V2UHQ "TARGET_DSP") - (V2HA "TARGET_DSP") - (V2UHA "TARGET_DSP") - (V4QQ "TARGET_DSP") - (V4UQQ "TARGET_DSP")]) - -;; 64-bit modes for which we provide move patterns. -(define_mode_iterator MOVE64 - [DI DF - (V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT") - (V2SI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS") - (V4HI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS") - (V8QI "TARGET_HARD_FLOAT && TARGET_LOONGSON_VECTORS")]) - -;; 128-bit modes for which we provide move patterns on 64-bit targets. -(define_mode_iterator MOVE128 [TI TF]) - -;; This mode iterator allows the QI and HI extension patterns to be -;; defined from the same template. -(define_mode_iterator SHORT [QI HI]) - -;; Likewise the 64-bit truncate-and-shift patterns. -(define_mode_iterator SUBDI [QI HI SI]) - -;; This mode iterator allows :ANYF to be used wherever a scalar or vector -;; floating-point mode is allowed. -(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT") - (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT") - (V2SF "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT")]) - -;; Like ANYF, but only applies to scalar modes. -(define_mode_iterator SCALARF [(SF "TARGET_HARD_FLOAT") - (DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")]) - -;; A floating-point mode for which moves involving FPRs may need to be split. -(define_mode_iterator SPLITF - [(DF "!TARGET_64BIT && TARGET_DOUBLE_FLOAT") - (DI "!TARGET_64BIT && TARGET_DOUBLE_FLOAT") - (V2SF "!TARGET_64BIT && TARGET_PAIRED_SINGLE_FLOAT") - (V2SI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS") - (V4HI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS") - (V8QI "!TARGET_64BIT && TARGET_LOONGSON_VECTORS") - (TF "TARGET_64BIT && TARGET_FLOAT64")]) - -;; In GPR templates, a string like "<d>subu" will expand to "subu" in the -;; 32-bit version and "dsubu" in the 64-bit version. -(define_mode_attr d [(SI "") (DI "d") - (QQ "") (HQ "") (SQ "") (DQ "d") - (UQQ "") (UHQ "") (USQ "") (UDQ "d") - (HA "") (SA "") (DA "d") - (UHA "") (USA "") (UDA "d")]) - -;; Same as d but upper-case. -(define_mode_attr D [(SI "") (DI "D") - (QQ "") (HQ "") (SQ "") (DQ "D") - (UQQ "") (UHQ "") (USQ "") (UDQ "D") - (HA "") (SA "") (DA "D") - (UHA "") (USA "") (UDA "D")]) - -;; This attribute gives the length suffix for a load or store instruction. -;; The same suffixes work for zero and sign extensions. -(define_mode_attr size [(QI "b") (HI "h") (SI "w") (DI "d")]) -(define_mode_attr SIZE [(QI "B") (HI "H") (SI "W") (DI "D")]) - -;; This attributes gives the mode mask of a SHORT. -(define_mode_attr mask [(QI "0x00ff") (HI "0xffff")]) - -;; Mode attributes for GPR loads. -(define_mode_attr load [(SI "lw") (DI "ld")]) -;; Instruction names for stores. -(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd")]) - -;; Similarly for MIPS IV indexed FPR loads and stores. -(define_mode_attr loadx [(SF "lwxc1") (DF "ldxc1") (V2SF "ldxc1")]) -(define_mode_attr storex [(SF "swxc1") (DF "sdxc1") (V2SF "sdxc1")]) - -;; The unextended ranges of the MIPS16 addiu and daddiu instructions -;; are different. Some forms of unextended addiu have an 8-bit immediate -;; field but the equivalent daddiu has only a 5-bit field. -(define_mode_attr si8_di5 [(SI "8") (DI "5")]) - -;; This attribute gives the best constraint to use for registers of -;; a given mode. -(define_mode_attr reg [(SI "d") (DI "d") (CC "z")]) - -;; This attribute gives the format suffix for floating-point operations. -(define_mode_attr fmt [(SF "s") (DF "d") (V2SF "ps")]) - -;; This attribute gives the upper-case mode name for one unit of a -;; floating-point mode. -(define_mode_attr UNITMODE [(SF "SF") (DF "DF") (V2SF "SF")]) - -;; This attribute gives the integer mode that has the same size as a -;; fixed-point mode. -(define_mode_attr IMODE [(QQ "QI") (HQ "HI") (SQ "SI") (DQ "DI") - (UQQ "QI") (UHQ "HI") (USQ "SI") (UDQ "DI") - (HA "HI") (SA "SI") (DA "DI") - (UHA "HI") (USA "SI") (UDA "DI") - (V4UQQ "SI") (V2UHQ "SI") (V2UHA "SI") - (V2HQ "SI") (V2HA "SI")]) - -;; This attribute gives the integer mode that has half the size of -;; the controlling mode. -(define_mode_attr HALFMODE [(DF "SI") (DI "SI") (V2SF "SI") - (V2SI "SI") (V4HI "SI") (V8QI "SI") - (TF "DI")]) - -;; This attribute works around the early SB-1 rev2 core "F2" erratum: -;; -;; In certain cases, div.s and div.ps may have a rounding error -;; and/or wrong inexact flag. -;; -;; Therefore, we only allow div.s if not working around SB-1 rev2 -;; errata or if a slight loss of precision is OK. -(define_mode_attr divide_condition - [DF (SF "!TARGET_FIX_SB1 || flag_unsafe_math_optimizations") - (V2SF "TARGET_SB1 && (!TARGET_FIX_SB1 || flag_unsafe_math_optimizations)")]) - -;; This attribute gives the conditions under which SQRT.fmt instructions -;; can be used. -(define_mode_attr sqrt_condition - [(SF "!ISA_MIPS1") (DF "!ISA_MIPS1") (V2SF "TARGET_SB1")]) - -;; This attribute gives the conditions under which RECIP.fmt and RSQRT.fmt -;; instructions can be used. The MIPS32 and MIPS64 ISAs say that RECIP.D -;; and RSQRT.D are unpredictable when doubles are stored in pairs of FPRs, -;; so for safety's sake, we apply this restriction to all targets. -(define_mode_attr recip_condition - [(SF "ISA_HAS_FP4") - (DF "ISA_HAS_FP4 && TARGET_FLOAT64") - (V2SF "TARGET_SB1")]) - -;; This code iterator allows signed and unsigned widening multiplications -;; to use the same template. -(define_code_iterator any_extend [sign_extend zero_extend]) - -;; This code iterator allows the two right shift instructions to be -;; generated from the same template. -(define_code_iterator any_shiftrt [ashiftrt lshiftrt]) - -;; This code iterator allows the three shift instructions to be generated -;; from the same template. -(define_code_iterator any_shift [ashift ashiftrt lshiftrt]) - -;; This code iterator allows unsigned and signed division to be generated -;; from the same template. -(define_code_iterator any_div [div udiv]) - -;; This code iterator allows unsigned and signed modulus to be generated -;; from the same template. -(define_code_iterator any_mod [mod umod]) - -;; This code iterator allows all native floating-point comparisons to be -;; generated from the same template. -(define_code_iterator fcond [unordered uneq unlt unle eq lt le]) - -;; This code iterator is used for comparisons that can be implemented -;; by swapping the operands. -(define_code_iterator swapped_fcond [ge gt unge ungt]) - -;; Equality operators. -(define_code_iterator equality_op [eq ne]) - -;; These code iterators allow the signed and unsigned scc operations to use -;; the same template. -(define_code_iterator any_gt [gt gtu]) -(define_code_iterator any_ge [ge geu]) -(define_code_iterator any_lt [lt ltu]) -(define_code_iterator any_le [le leu]) - -(define_code_iterator any_return [return simple_return]) - -;; <u> expands to an empty string when doing a signed operation and -;; "u" when doing an unsigned operation. -(define_code_attr u [(sign_extend "") (zero_extend "u") - (div "") (udiv "u") - (mod "") (umod "u") - (gt "") (gtu "u") - (ge "") (geu "u") - (lt "") (ltu "u") - (le "") (leu "u")]) - -;; <U> is like <u> except uppercase. -(define_code_attr U [(sign_extend "") (zero_extend "U")]) - -;; <su> is like <u>, but the signed form expands to "s" rather than "". -(define_code_attr su [(sign_extend "s") (zero_extend "u")]) - -;; <optab> expands to the name of the optab for a particular code. -(define_code_attr optab [(ashift "ashl") - (ashiftrt "ashr") - (lshiftrt "lshr") - (ior "ior") - (xor "xor") - (and "and") - (plus "add") - (minus "sub") - (return "return") - (simple_return "simple_return")]) - -;; <insn> expands to the name of the insn that implements a particular code. -(define_code_attr insn [(ashift "sll") - (ashiftrt "sra") - (lshiftrt "srl") - (ior "or") - (xor "xor") - (and "and") - (plus "addu") - (minus "subu")]) - -;; <immediate_insn> expands to the name of the insn that implements -;; a particular code to operate on immediate values. -(define_code_attr immediate_insn [(ior "ori") - (xor "xori") - (and "andi")]) - -;; <fcond> is the c.cond.fmt condition associated with a particular code. -(define_code_attr fcond [(unordered "un") - (uneq "ueq") - (unlt "ult") - (unle "ule") - (eq "eq") - (lt "lt") - (le "le")]) - -;; Similar, but for swapped conditions. -(define_code_attr swapped_fcond [(ge "le") - (gt "lt") - (unge "ule") - (ungt "ult")]) - -;; The value of the bit when the branch is taken for branch_bit patterns. -;; Comparison is always against zero so this depends on the operator. -(define_code_attr bbv [(eq "0") (ne "1")]) - -;; This is the inverse value of bbv. -(define_code_attr bbinv [(eq "1") (ne "0")]) - -;; ......................... -;; -;; Branch, call and jump delay slots -;; -;; ......................... - -(define_delay (and (eq_attr "type" "branch") - (not (match_test "TARGET_MIPS16")) - (eq_attr "branch_likely" "yes")) - [(eq_attr "can_delay" "yes") - (nil) - (eq_attr "can_delay" "yes")]) - -;; Branches that don't have likely variants do not annul on false. -(define_delay (and (eq_attr "type" "branch") - (not (match_test "TARGET_MIPS16")) - (eq_attr "branch_likely" "no")) - [(eq_attr "can_delay" "yes") - (nil) - (nil)]) - -(define_delay (eq_attr "type" "jump") - [(eq_attr "can_delay" "yes") - (nil) - (nil)]) - -(define_delay (and (eq_attr "type" "call") - (eq_attr "jal_macro" "no")) - [(eq_attr "can_delay" "yes") - (nil) - (nil)]) - -;; Pipeline descriptions. -;; -;; generic.md provides a fallback for processors without a specific -;; pipeline description. It is derived from the old define_function_unit -;; version and uses the "alu" and "imuldiv" units declared below. -;; -;; Some of the processor-specific files are also derived from old -;; define_function_unit descriptions and simply override the parts of -;; generic.md that don't apply. The other processor-specific files -;; are self-contained. -(define_automaton "alu,imuldiv") - -(define_cpu_unit "alu" "alu") -(define_cpu_unit "imuldiv" "imuldiv") - -;; Ghost instructions produce no real code and introduce no hazards. -;; They exist purely to express an effect on dataflow. -(define_insn_reservation "ghost" 0 - (eq_attr "type" "ghost") - "nothing") - -(include "4k.md") -(include "5k.md") -(include "20kc.md") -(include "24k.md") -(include "74k.md") -(include "3000.md") -(include "4000.md") -(include "4100.md") -(include "4130.md") -(include "4300.md") -(include "4600.md") -(include "5000.md") -(include "5400.md") -(include "5500.md") -(include "6000.md") -(include "7000.md") -(include "9000.md") -(include "10000.md") -(include "loongson2ef.md") -(include "loongson3a.md") -(include "octeon.md") -(include "sb1.md") -(include "sr71k.md") -(include "xlr.md") -(include "xlp.md") -(include "generic.md") - -;; -;; .................... -;; -;; CONDITIONAL TRAPS -;; -;; .................... -;; - -(define_insn "trap" - [(trap_if (const_int 1) (const_int 0))] - "" -{ - if (ISA_HAS_COND_TRAP) - return "teq\t$0,$0"; - else if (TARGET_MIPS16) - return "break 0"; - else - return "break"; -} - [(set_attr "type" "trap")]) - -(define_expand "ctrap<mode>4" - [(trap_if (match_operator 0 "comparison_operator" - [(match_operand:GPR 1 "reg_or_0_operand") - (match_operand:GPR 2 "arith_operand")]) - (match_operand 3 "const_0_operand"))] - "ISA_HAS_COND_TRAP" -{ - mips_expand_conditional_trap (operands[0]); - DONE; -}) - -(define_insn "*conditional_trap<mode>" - [(trap_if (match_operator:GPR 0 "trap_comparison_operator" - [(match_operand:GPR 1 "reg_or_0_operand" "dJ") - (match_operand:GPR 2 "arith_operand" "dI")]) - (const_int 0))] - "ISA_HAS_COND_TRAP" - "t%C0\t%z1,%2" - [(set_attr "type" "trap")]) - -;; -;; .................... -;; -;; ADDITION -;; -;; .................... -;; - -(define_insn "add<mode>3" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (plus:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")))] - "" - "add.<fmt>\t%0,%1,%2" - [(set_attr "type" "fadd") - (set_attr "mode" "<UNITMODE>")]) - -(define_expand "add<mode>3" - [(set (match_operand:GPR 0 "register_operand") - (plus:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "arith_operand")))] - "") - -(define_insn "*add<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (plus:GPR (match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "arith_operand" "d,Q")))] - "!TARGET_MIPS16" - "@ - <d>addu\t%0,%1,%2 - <d>addiu\t%0,%1,%2" - [(set_attr "alu_type" "add") - (set_attr "mode" "<MODE>")]) - -(define_insn "*add<mode>3_mips16" - [(set (match_operand:GPR 0 "register_operand" "=ks,d,d,d,d") - (plus:GPR (match_operand:GPR 1 "register_operand" "ks,ks,0,d,d") - (match_operand:GPR 2 "arith_operand" "Q,Q,Q,O,d")))] - "TARGET_MIPS16" - "@ - <d>addiu\t%0,%2 - <d>addiu\t%0,%1,%2 - <d>addiu\t%0,%2 - <d>addiu\t%0,%1,%2 - <d>addu\t%0,%1,%2" - [(set_attr "alu_type" "add") - (set_attr "mode" "<MODE>") - (set_attr_alternative "length" - [(if_then_else (match_operand 2 "m16_simm8_8") - (const_int 4) - (const_int 8)) - (if_then_else (match_operand 2 "m16_uimm<si8_di5>_4") - (const_int 4) - (const_int 8)) - (if_then_else (match_operand 2 "m16_simm<si8_di5>_1") - (const_int 4) - (const_int 8)) - (if_then_else (match_operand 2 "m16_simm4_1") - (const_int 4) - (const_int 8)) - (const_int 4)])]) - -;; On the mips16, we can sometimes split an add of a constant which is -;; a 4 byte instruction into two adds which are both 2 byte -;; instructions. There are two cases: one where we are adding a -;; constant plus a register to another register, and one where we are -;; simply adding a constant to a register. - -(define_split - [(set (match_operand:SI 0 "d_operand") - (plus:SI (match_dup 0) - (match_operand:SI 1 "const_int_operand")))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && ((INTVAL (operands[1]) > 0x7f - && INTVAL (operands[1]) <= 0x7f + 0x7f) - || (INTVAL (operands[1]) < - 0x80 - && INTVAL (operands[1]) >= - 0x80 - 0x80))" - [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) - (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] -{ - HOST_WIDE_INT val = INTVAL (operands[1]); - - if (val >= 0) - { - operands[1] = GEN_INT (0x7f); - operands[2] = GEN_INT (val - 0x7f); - } - else - { - operands[1] = GEN_INT (- 0x80); - operands[2] = GEN_INT (val + 0x80); - } -}) - -(define_split - [(set (match_operand:SI 0 "d_operand") - (plus:SI (match_operand:SI 1 "d_operand") - (match_operand:SI 2 "const_int_operand")))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && REGNO (operands[0]) != REGNO (operands[1]) - && ((INTVAL (operands[2]) > 0x7 - && INTVAL (operands[2]) <= 0x7 + 0x7f) - || (INTVAL (operands[2]) < - 0x8 - && INTVAL (operands[2]) >= - 0x8 - 0x80))" - [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) - (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] -{ - HOST_WIDE_INT val = INTVAL (operands[2]); - - if (val >= 0) - { - operands[2] = GEN_INT (0x7); - operands[3] = GEN_INT (val - 0x7); - } - else - { - operands[2] = GEN_INT (- 0x8); - operands[3] = GEN_INT (val + 0x8); - } -}) - -(define_split - [(set (match_operand:DI 0 "d_operand") - (plus:DI (match_dup 0) - (match_operand:DI 1 "const_int_operand")))] - "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE - && ((INTVAL (operands[1]) > 0xf - && INTVAL (operands[1]) <= 0xf + 0xf) - || (INTVAL (operands[1]) < - 0x10 - && INTVAL (operands[1]) >= - 0x10 - 0x10))" - [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) - (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))] -{ - HOST_WIDE_INT val = INTVAL (operands[1]); - - if (val >= 0) - { - operands[1] = GEN_INT (0xf); - operands[2] = GEN_INT (val - 0xf); - } - else - { - operands[1] = GEN_INT (- 0x10); - operands[2] = GEN_INT (val + 0x10); - } -}) - -(define_split - [(set (match_operand:DI 0 "d_operand") - (plus:DI (match_operand:DI 1 "d_operand") - (match_operand:DI 2 "const_int_operand")))] - "TARGET_MIPS16 && TARGET_64BIT && reload_completed && !TARGET_DEBUG_D_MODE - && REGNO (operands[0]) != REGNO (operands[1]) - && ((INTVAL (operands[2]) > 0x7 - && INTVAL (operands[2]) <= 0x7 + 0xf) - || (INTVAL (operands[2]) < - 0x8 - && INTVAL (operands[2]) >= - 0x8 - 0x10))" - [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2))) - (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] -{ - HOST_WIDE_INT val = INTVAL (operands[2]); - - if (val >= 0) - { - operands[2] = GEN_INT (0x7); - operands[3] = GEN_INT (val - 0x7); - } - else - { - operands[2] = GEN_INT (- 0x8); - operands[3] = GEN_INT (val + 0x8); - } -}) - -(define_insn "*addsi3_extended" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (sign_extend:DI - (plus:SI (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "arith_operand" "d,Q"))))] - "TARGET_64BIT && !TARGET_MIPS16" - "@ - addu\t%0,%1,%2 - addiu\t%0,%1,%2" - [(set_attr "alu_type" "add") - (set_attr "mode" "SI")]) - -;; Split this insn so that the addiu splitters can have a crack at it. -;; Use a conservative length estimate until the split. -(define_insn_and_split "*addsi3_extended_mips16" - [(set (match_operand:DI 0 "register_operand" "=d,d,d") - (sign_extend:DI - (plus:SI (match_operand:SI 1 "register_operand" "0,d,d") - (match_operand:SI 2 "arith_operand" "Q,O,d"))))] - "TARGET_64BIT && TARGET_MIPS16" - "#" - "&& reload_completed" - [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))] - { operands[3] = gen_lowpart (SImode, operands[0]); } - [(set_attr "alu_type" "add") - (set_attr "mode" "SI") - (set_attr "extended_mips16" "yes")]) - -;; Combiner patterns for unsigned byte-add. - -(define_insn "*baddu_si" - [(set (match_operand:SI 0 "register_operand" "=d") - (zero_extend:SI - (plus:QI (match_operand:QI 1 "register_operand" "d") - (match_operand:QI 2 "register_operand" "d"))))] - "ISA_HAS_BADDU" - "baddu\\t%0,%1,%2" - [(set_attr "alu_type" "add")]) - -(define_insn "*baddu_di<mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extend:GPR - (plus:QI (truncate:QI (match_operand:DI 1 "register_operand" "d")) - (truncate:QI (match_operand:DI 2 "register_operand" "d")))))] - "ISA_HAS_BADDU && TARGET_64BIT" - "baddu\\t%0,%1,%2" - [(set_attr "alu_type" "add")]) - -;; -;; .................... -;; -;; SUBTRACTION -;; -;; .................... -;; - -(define_insn "sub<mode>3" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")))] - "" - "sub.<fmt>\t%0,%1,%2" - [(set_attr "type" "fadd") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "sub<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d") - (minus:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d")))] - "" - "<d>subu\t%0,%1,%2" - [(set_attr "alu_type" "sub") - (set_attr "mode" "<MODE>")]) - -(define_insn "*subsi3_extended" - [(set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI - (minus:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d"))))] - "TARGET_64BIT" - "subu\t%0,%1,%2" - [(set_attr "alu_type" "sub") - (set_attr "mode" "DI")]) - -;; -;; .................... -;; -;; MULTIPLICATION -;; -;; .................... -;; - -(define_expand "mul<mode>3" - [(set (match_operand:SCALARF 0 "register_operand") - (mult:SCALARF (match_operand:SCALARF 1 "register_operand") - (match_operand:SCALARF 2 "register_operand")))] - "" - "") - -(define_insn "*mul<mode>3" - [(set (match_operand:SCALARF 0 "register_operand" "=f") - (mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f") - (match_operand:SCALARF 2 "register_operand" "f")))] - "!TARGET_4300_MUL_FIX" - "mul.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmul") - (set_attr "mode" "<MODE>")]) - -;; Early VR4300 silicon has a CPU bug where multiplies with certain -;; operands may corrupt immediately following multiplies. This is a -;; simple fix to insert NOPs. - -(define_insn "*mul<mode>3_r4300" - [(set (match_operand:SCALARF 0 "register_operand" "=f") - (mult:SCALARF (match_operand:SCALARF 1 "register_operand" "f") - (match_operand:SCALARF 2 "register_operand" "f")))] - "TARGET_4300_MUL_FIX" - "mul.<fmt>\t%0,%1,%2\;nop" - [(set_attr "type" "fmul") - (set_attr "mode" "<MODE>") - (set_attr "length" "8")]) - -(define_insn "mulv2sf3" - [(set (match_operand:V2SF 0 "register_operand" "=f") - (mult:V2SF (match_operand:V2SF 1 "register_operand" "f") - (match_operand:V2SF 2 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT" - "mul.ps\t%0,%1,%2" - [(set_attr "type" "fmul") - (set_attr "mode" "SF")]) - -;; The original R4000 has a cpu bug. If a double-word or a variable -;; shift executes while an integer multiplication is in progress, the -;; shift may give an incorrect result. Avoid this by keeping the mflo -;; with the mult on the R4000. -;; -;; From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0" -;; (also valid for MIPS R4000MC processors): -;; -;; "16. R4000PC, R4000SC: Please refer to errata 28 for an update to -;; this errata description. -;; The following code sequence causes the R4000 to incorrectly -;; execute the Double Shift Right Arithmetic 32 (dsra32) -;; instruction. If the dsra32 instruction is executed during an -;; integer multiply, the dsra32 will only shift by the amount in -;; specified in the instruction rather than the amount plus 32 -;; bits. -;; instruction 1: mult rs,rt integer multiply -;; instruction 2-12: dsra32 rd,rt,rs doubleword shift -;; right arithmetic + 32 -;; Workaround: A dsra32 instruction placed after an integer -;; multiply should not be one of the 11 instructions after the -;; multiply instruction." -;; -;; and: -;; -;; "28. R4000PC, R4000SC: The text from errata 16 should be replaced by -;; the following description. -;; All extended shifts (shift by n+32) and variable shifts (32 and -;; 64-bit versions) may produce incorrect results under the -;; following conditions: -;; 1) An integer multiply is currently executing -;; 2) These types of shift instructions are executed immediately -;; following an integer divide instruction. -;; Workaround: -;; 1) Make sure no integer multiply is running wihen these -;; instruction are executed. If this cannot be predicted at -;; compile time, then insert a "mfhi" to R0 instruction -;; immediately after the integer multiply instruction. This -;; will cause the integer multiply to complete before the shift -;; is executed. -;; 2) Separate integer divide and these two classes of shift -;; instructions by another instruction or a noop." -;; -;; These processors have PRId values of 0x00004220 and 0x00004300, -;; respectively. - -(define_expand "mul<mode>3" - [(set (match_operand:GPR 0 "register_operand") - (mult:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand")))] - "" -{ - rtx lo; - - if (TARGET_LOONGSON_2EF || TARGET_LOONGSON_3A) - emit_insn (gen_mul<mode>3_mul3_loongson (operands[0], operands[1], - operands[2])); - else if (ISA_HAS_<D>MUL3) - emit_insn (gen_mul<mode>3_mul3 (operands[0], operands[1], operands[2])); - else if (TARGET_MIPS16) - { - lo = gen_rtx_REG (<MODE>mode, LO_REGNUM); - emit_insn (gen_mul<mode>3_internal (lo, operands[1], operands[2])); - emit_move_insn (operands[0], lo); - } - else if (TARGET_FIX_R4000) - emit_insn (gen_mul<mode>3_r4000 (operands[0], operands[1], operands[2])); - else - emit_insn - (gen_mul<mode>3_internal (operands[0], operands[1], operands[2])); - DONE; -}) - -(define_insn "mul<mode>3_mul3_loongson" - [(set (match_operand:GPR 0 "register_operand" "=d") - (mult:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d")))] - "TARGET_LOONGSON_2EF || TARGET_LOONGSON_3A" -{ - if (TARGET_LOONGSON_2EF) - return "<d>multu.g\t%0,%1,%2"; - else - return "gs<d>multu\t%0,%1,%2"; -} - [(set_attr "type" "imul3nc") - (set_attr "mode" "<MODE>")]) - -(define_insn "mul<mode>3_mul3" - [(set (match_operand:GPR 0 "register_operand" "=d,l") - (mult:GPR (match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "register_operand" "d,d"))) - (clobber (match_scratch:GPR 3 "=l,X"))] - "ISA_HAS_<D>MUL3" -{ - if (which_alternative == 1) - return "<d>mult\t%1,%2"; - if (<MODE>mode == SImode && TARGET_MIPS3900) - return "mult\t%0,%1,%2"; - return "<d>mul\t%0,%1,%2"; -} - [(set_attr "type" "imul3,imul") - (set_attr "mode" "<MODE>")]) - -;; If a register gets allocated to LO, and we spill to memory, the reload -;; will include a move from LO to a GPR. Merge it into the multiplication -;; if it can set the GPR directly. -;; -;; Operand 0: LO -;; Operand 1: GPR (1st multiplication operand) -;; Operand 2: GPR (2nd multiplication operand) -;; Operand 3: GPR (destination) -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "lo_operand") - (mult:SI (match_operand:SI 1 "d_operand") - (match_operand:SI 2 "d_operand"))) - (clobber (scratch:SI))]) - (set (match_operand:SI 3 "d_operand") - (match_dup 0))] - "ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[0])" - [(parallel - [(set (match_dup 3) - (mult:SI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 0))])]) - -(define_insn "mul<mode>3_internal" - [(set (match_operand:GPR 0 "muldiv_target_operand" "=l") - (mult:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d")))] - "!TARGET_FIX_R4000" - "<d>mult\t%1,%2" - [(set_attr "type" "imul") - (set_attr "mode" "<MODE>")]) - -(define_insn "mul<mode>3_r4000" - [(set (match_operand:GPR 0 "register_operand" "=d") - (mult:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d"))) - (clobber (match_scratch:GPR 3 "=l"))] - "TARGET_FIX_R4000" - "<d>mult\t%1,%2\;mflo\t%0" - [(set_attr "type" "imul") - (set_attr "mode" "<MODE>") - (set_attr "length" "8")]) - -;; On the VR4120 and VR4130, it is better to use "mtlo $0; macc" instead -;; of "mult; mflo". They have the same latency, but the first form gives -;; us an extra cycle to compute the operands. - -;; Operand 0: LO -;; Operand 1: GPR (1st multiplication operand) -;; Operand 2: GPR (2nd multiplication operand) -;; Operand 3: GPR (destination) -(define_peephole2 - [(set (match_operand:SI 0 "lo_operand") - (mult:SI (match_operand:SI 1 "d_operand") - (match_operand:SI 2 "d_operand"))) - (set (match_operand:SI 3 "d_operand") - (match_dup 0))] - "ISA_HAS_MACC && !ISA_HAS_MUL3" - [(set (match_dup 0) - (const_int 0)) - (parallel - [(set (match_dup 0) - (plus:SI (mult:SI (match_dup 1) - (match_dup 2)) - (match_dup 0))) - (set (match_dup 3) - (plus:SI (mult:SI (match_dup 1) - (match_dup 2)) - (match_dup 0)))])]) - -;; Multiply-accumulate patterns - -;; This pattern is first matched by combine, which tries to use the -;; pattern wherever it can. We don't know until later whether it -;; is actually profitable to use MADD over a "MUL; ADDIU" sequence, -;; so we need to keep both options open. -;; -;; The second alternative has a "?" marker because it is generally -;; one instruction more costly than the first alternative. This "?" -;; marker is enough to convey the relative costs to the register -;; allocator. -;; -;; However, reload counts reloads of operands 4 and 5 in the same way as -;; reloads of the other operands, even though operands 4 and 5 need no -;; copy instructions. Reload therefore thinks that the second alternative -;; is two reloads more costly than the first. We add "*?*?" to the first -;; alternative as a counterweight. -(define_insn "*mul_acc_si" - [(set (match_operand:SI 0 "register_operand" "=l*?*?,d?") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "register_operand" "d,d")) - (match_operand:SI 3 "register_operand" "0,d"))) - (clobber (match_scratch:SI 4 "=X,l")) - (clobber (match_scratch:SI 5 "=X,&d"))] - "GENERATE_MADD_MSUB && !TARGET_MIPS16" - "@ - madd\t%1,%2 - #" - [(set_attr "type" "imadd") - (set_attr "accum_in" "3") - (set_attr "mode" "SI") - (set_attr "length" "4,8")]) - -;; The same idea applies here. The middle alternative needs one less -;; clobber than the final alternative, so we add "*?" as a counterweight. -(define_insn "*mul_acc_si_r3900" - [(set (match_operand:SI 0 "register_operand" "=l*?*?,d*?,d?") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d,d") - (match_operand:SI 2 "register_operand" "d,d,d")) - (match_operand:SI 3 "register_operand" "0,l,d"))) - (clobber (match_scratch:SI 4 "=X,3,l")) - (clobber (match_scratch:SI 5 "=X,X,&d"))] - "TARGET_MIPS3900 && !TARGET_MIPS16" - "@ - madd\t%1,%2 - madd\t%0,%1,%2 - #" - [(set_attr "type" "imadd") - (set_attr "accum_in" "3") - (set_attr "mode" "SI") - (set_attr "length" "4,4,8")]) - -;; Split *mul_acc_si if both the source and destination accumulator -;; values are GPRs. -(define_split - [(set (match_operand:SI 0 "d_operand") - (plus:SI (mult:SI (match_operand:SI 1 "d_operand") - (match_operand:SI 2 "d_operand")) - (match_operand:SI 3 "d_operand"))) - (clobber (match_operand:SI 4 "lo_operand")) - (clobber (match_operand:SI 5 "d_operand"))] - "reload_completed" - [(parallel [(set (match_dup 5) - (mult:SI (match_dup 1) (match_dup 2))) - (clobber (match_dup 4))]) - (set (match_dup 0) (plus:SI (match_dup 5) (match_dup 3)))] - "") - -(define_insn "*macc" - [(set (match_operand:SI 0 "register_operand" "=l,d") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "register_operand" "d,d")) - (match_operand:SI 3 "register_operand" "0,l"))) - (clobber (match_scratch:SI 4 "=X,3"))] - "ISA_HAS_MACC" -{ - if (which_alternative == 1) - return "macc\t%0,%1,%2"; - else if (TARGET_MIPS5500) - return "madd\t%1,%2"; - else - /* The VR4130 assumes that there is a two-cycle latency between a macc - that "writes" to $0 and an instruction that reads from it. We avoid - this by assigning to $1 instead. */ - return "%[macc\t%@,%1,%2%]"; -} - [(set_attr "type" "imadd") - (set_attr "accum_in" "3") - (set_attr "mode" "SI")]) - -(define_insn "*msac" - [(set (match_operand:SI 0 "register_operand" "=l,d") - (minus:SI (match_operand:SI 1 "register_operand" "0,l") - (mult:SI (match_operand:SI 2 "register_operand" "d,d") - (match_operand:SI 3 "register_operand" "d,d")))) - (clobber (match_scratch:SI 4 "=X,1"))] - "ISA_HAS_MSAC" -{ - if (which_alternative == 1) - return "msac\t%0,%2,%3"; - else if (TARGET_MIPS5500) - return "msub\t%2,%3"; - else - return "msac\t$0,%2,%3"; -} - [(set_attr "type" "imadd") - (set_attr "accum_in" "1") - (set_attr "mode" "SI")]) - -;; An msac-like instruction implemented using negation and a macc. -(define_insn_and_split "*msac_using_macc" - [(set (match_operand:SI 0 "register_operand" "=l,d") - (minus:SI (match_operand:SI 1 "register_operand" "0,l") - (mult:SI (match_operand:SI 2 "register_operand" "d,d") - (match_operand:SI 3 "register_operand" "d,d")))) - (clobber (match_scratch:SI 4 "=X,1")) - (clobber (match_scratch:SI 5 "=d,d"))] - "ISA_HAS_MACC && !ISA_HAS_MSAC" - "#" - "&& reload_completed" - [(set (match_dup 5) - (neg:SI (match_dup 3))) - (parallel - [(set (match_dup 0) - (plus:SI (mult:SI (match_dup 2) - (match_dup 5)) - (match_dup 1))) - (clobber (match_dup 4))])] - "" - [(set_attr "type" "imadd") - (set_attr "accum_in" "1") - (set_attr "length" "8")]) - -;; Patterns generated by the define_peephole2 below. - -(define_insn "*macc2" - [(set (match_operand:SI 0 "muldiv_target_operand" "=l") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d")) - (match_dup 0))) - (set (match_operand:SI 3 "register_operand" "=d") - (plus:SI (mult:SI (match_dup 1) - (match_dup 2)) - (match_dup 0)))] - "ISA_HAS_MACC && reload_completed" - "macc\t%3,%1,%2" - [(set_attr "type" "imadd") - (set_attr "accum_in" "0") - (set_attr "mode" "SI")]) - -(define_insn "*msac2" - [(set (match_operand:SI 0 "muldiv_target_operand" "=l") - (minus:SI (match_dup 0) - (mult:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d")))) - (set (match_operand:SI 3 "register_operand" "=d") - (minus:SI (match_dup 0) - (mult:SI (match_dup 1) - (match_dup 2))))] - "ISA_HAS_MSAC && reload_completed" - "msac\t%3,%1,%2" - [(set_attr "type" "imadd") - (set_attr "accum_in" "0") - (set_attr "mode" "SI")]) - -;; Convert macc $0,<r1>,<r2> & mflo <r3> into macc <r3>,<r1>,<r2> -;; Similarly msac. -;; -;; Operand 0: LO -;; Operand 1: macc/msac -;; Operand 2: GPR (destination) -(define_peephole2 - [(parallel - [(set (match_operand:SI 0 "lo_operand") - (match_operand:SI 1 "macc_msac_operand")) - (clobber (scratch:SI))]) - (set (match_operand:SI 2 "d_operand") - (match_dup 0))] - "" - [(parallel [(set (match_dup 0) - (match_dup 1)) - (set (match_dup 2) - (match_dup 1))])]) - -;; When we have a three-address multiplication instruction, it should -;; be faster to do a separate multiply and add, rather than moving -;; something into LO in order to use a macc instruction. -;; -;; This peephole needs a scratch register to cater for the case when one -;; of the multiplication operands is the same as the destination. -;; -;; Operand 0: GPR (scratch) -;; Operand 1: LO -;; Operand 2: GPR (addend) -;; Operand 3: GPR (destination) -;; Operand 4: macc/msac -;; Operand 5: new multiplication -;; Operand 6: new addition/subtraction -(define_peephole2 - [(match_scratch:SI 0 "d") - (set (match_operand:SI 1 "lo_operand") - (match_operand:SI 2 "d_operand")) - (match_dup 0) - (parallel - [(set (match_operand:SI 3 "d_operand") - (match_operand:SI 4 "macc_msac_operand")) - (clobber (match_dup 1))])] - "ISA_HAS_MUL3 && peep2_reg_dead_p (2, operands[1])" - [(parallel [(set (match_dup 0) - (match_dup 5)) - (clobber (match_dup 1))]) - (set (match_dup 3) - (match_dup 6))] -{ - operands[5] = XEXP (operands[4], GET_CODE (operands[4]) == PLUS ? 0 : 1); - operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, - operands[2], operands[0]); -}) - -;; Same as above, except LO is the initial target of the macc. -;; -;; Operand 0: GPR (scratch) -;; Operand 1: LO -;; Operand 2: GPR (addend) -;; Operand 3: macc/msac -;; Operand 4: GPR (destination) -;; Operand 5: new multiplication -;; Operand 6: new addition/subtraction -(define_peephole2 - [(match_scratch:SI 0 "d") - (set (match_operand:SI 1 "lo_operand") - (match_operand:SI 2 "d_operand")) - (match_dup 0) - (parallel - [(set (match_dup 1) - (match_operand:SI 3 "macc_msac_operand")) - (clobber (scratch:SI))]) - (match_dup 0) - (set (match_operand:SI 4 "d_operand") - (match_dup 1))] - "ISA_HAS_MUL3 && peep2_reg_dead_p (3, operands[1])" - [(parallel [(set (match_dup 0) - (match_dup 5)) - (clobber (match_dup 1))]) - (set (match_dup 4) - (match_dup 6))] -{ - operands[5] = XEXP (operands[3], GET_CODE (operands[3]) == PLUS ? 0 : 1); - operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode, - operands[2], operands[0]); -}) - -;; See the comment above *mul_add_si for details. -(define_insn "*mul_sub_si" - [(set (match_operand:SI 0 "register_operand" "=l*?*?,d?") - (minus:SI (match_operand:SI 1 "register_operand" "0,d") - (mult:SI (match_operand:SI 2 "register_operand" "d,d") - (match_operand:SI 3 "register_operand" "d,d")))) - (clobber (match_scratch:SI 4 "=X,l")) - (clobber (match_scratch:SI 5 "=X,&d"))] - "GENERATE_MADD_MSUB" - "@ - msub\t%2,%3 - #" - [(set_attr "type" "imadd") - (set_attr "accum_in" "1") - (set_attr "mode" "SI") - (set_attr "length" "4,8")]) - -;; Split *mul_sub_si if both the source and destination accumulator -;; values are GPRs. -(define_split - [(set (match_operand:SI 0 "d_operand") - (minus:SI (match_operand:SI 1 "d_operand") - (mult:SI (match_operand:SI 2 "d_operand") - (match_operand:SI 3 "d_operand")))) - (clobber (match_operand:SI 4 "lo_operand")) - (clobber (match_operand:SI 5 "d_operand"))] - "reload_completed" - [(parallel [(set (match_dup 5) - (mult:SI (match_dup 2) (match_dup 3))) - (clobber (match_dup 4))]) - (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 5)))] - "") - -(define_insn "*muls" - [(set (match_operand:SI 0 "register_operand" "=l,d") - (neg:SI (mult:SI (match_operand:SI 1 "register_operand" "d,d") - (match_operand:SI 2 "register_operand" "d,d")))) - (clobber (match_scratch:SI 3 "=X,l"))] - "ISA_HAS_MULS" - "@ - muls\t$0,%1,%2 - muls\t%0,%1,%2" - [(set_attr "type" "imul,imul3") - (set_attr "mode" "SI")]) - -(define_expand "<u>mulsidi3" - [(set (match_operand:DI 0 "register_operand") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand"))))] - "mips_mulsidi3_gen_fn (<CODE>) != NULL" -{ - mulsidi3_gen_fn fn = mips_mulsidi3_gen_fn (<CODE>); - emit_insn (fn (operands[0], operands[1], operands[2])); - DONE; -}) - -(define_expand "<u>mulsidi3_32bit_mips16" - [(set (match_operand:DI 0 "register_operand") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand"))))] - "!TARGET_64BIT && TARGET_MIPS16" -{ - rtx hilo; - - hilo = gen_rtx_REG (DImode, MD_REG_FIRST); - emit_insn (gen_<u>mulsidi3_32bit (hilo, operands[1], operands[2])); - emit_move_insn (operands[0], hilo); - DONE; -}) - -;; As well as being named patterns, these instructions are used by the -;; __builtin_mips_mult<u>() functions. We must always make those functions -;; available if !TARGET_64BIT && ISA_HAS_DSP. -(define_insn "<u>mulsidi3_32bit" - [(set (match_operand:DI 0 "muldiv_target_operand" "=ka") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d"))))] - "!TARGET_64BIT && (!TARGET_FIX_R4000 || ISA_HAS_DSP)" -{ - if (ISA_HAS_DSP_MULT) - return "mult<u>\t%q0,%1,%2"; - else - return "mult<u>\t%1,%2"; -} - [(set_attr "type" "imul") - (set_attr "mode" "SI")]) - -(define_insn "<u>mulsidi3_32bit_r4000" - [(set (match_operand:DI 0 "register_operand" "=d") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (match_scratch:DI 3 "=x"))] - "!TARGET_64BIT && TARGET_FIX_R4000 && !ISA_HAS_DSP" - "mult<u>\t%1,%2\;mflo\t%L0\;mfhi\t%M0" - [(set_attr "type" "imul") - (set_attr "mode" "SI") - (set_attr "length" "12")]) - -(define_insn_and_split "<u>mulsidi3_64bit" - [(set (match_operand:DI 0 "register_operand" "=d") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (match_scratch:TI 3 "=x")) - (clobber (match_scratch:DI 4 "=d"))] - "TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DMUL3 && !TARGET_MIPS16" - "#" - "&& reload_completed" - [(const_int 0)] -{ - emit_insn (gen_<u>mulsidi3_64bit_split (operands[0], operands[1], - operands[2], operands[4])); - DONE; -} - [(set_attr "type" "imul") - (set_attr "mode" "SI") - (set (attr "length") - (if_then_else (match_test "ISA_HAS_EXT_INS") - (const_int 16) - (const_int 28)))]) - -(define_expand "<u>mulsidi3_64bit_mips16" - [(set (match_operand:DI 0 "register_operand") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand"))))] - "TARGET_64BIT && TARGET_MIPS16" -{ - emit_insn (gen_<u>mulsidi3_64bit_split (operands[0], operands[1], - operands[2], gen_reg_rtx (DImode))); - DONE; -}) - -(define_expand "<u>mulsidi3_64bit_split" - [(set (match_operand:DI 0 "register_operand") - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand")))) - (clobber (match_operand:DI 3 "register_operand"))] - "" -{ - rtx hilo; - - hilo = gen_rtx_REG (TImode, MD_REG_FIRST); - emit_insn (gen_<u>mulsidi3_64bit_hilo (hilo, operands[1], operands[2])); - - emit_move_insn (operands[0], gen_rtx_REG (DImode, LO_REGNUM)); - emit_insn (gen_mfhidi_ti (operands[3], hilo)); - - if (ISA_HAS_EXT_INS) - emit_insn (gen_insvdi (operands[0], GEN_INT (32), GEN_INT (32), - operands[3])); - else - { - /* Zero-extend the low part. */ - mips_emit_binary (ASHIFT, operands[0], operands[0], GEN_INT (32)); - mips_emit_binary (LSHIFTRT, operands[0], operands[0], GEN_INT (32)); - - /* Shift the high part into place. */ - mips_emit_binary (ASHIFT, operands[3], operands[3], GEN_INT (32)); - - /* OR the two halves together. */ - mips_emit_binary (IOR, operands[0], operands[0], operands[3]); - } - DONE; -}) - -(define_insn "<u>mulsidi3_64bit_hilo" - [(set (match_operand:TI 0 "muldiv_target_operand" "=x") - (unspec:TI - [(mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d")))] - UNSPEC_SET_HILO))] - "TARGET_64BIT && !TARGET_FIX_R4000" - "mult<u>\t%1,%2" - [(set_attr "type" "imul") - (set_attr "mode" "SI")]) - -;; See comment before the ISA_HAS_DMUL3 case in mips_mulsidi3_gen_fn. -(define_insn "mulsidi3_64bit_dmul" - [(set (match_operand:DI 0 "register_operand" "=d") - (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) - (sign_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (clobber (match_scratch:DI 3 "=l"))] - "TARGET_64BIT && ISA_HAS_DMUL3" - "dmul\t%0,%1,%2" - [(set_attr "type" "imul3") - (set_attr "mode" "DI")]) - -;; Widening multiply with negation. -(define_insn "*muls<u>_di" - [(set (match_operand:DI 0 "muldiv_target_operand" "=x") - (neg:DI - (mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d")))))] - "!TARGET_64BIT && ISA_HAS_MULS" - "muls<u>\t$0,%1,%2" - [(set_attr "type" "imul") - (set_attr "mode" "SI")]) - -;; As well as being named patterns, these instructions are used by the -;; __builtin_mips_msub<u>() functions. We must always make those functions -;; available if !TARGET_64BIT && ISA_HAS_DSP. -;; -;; This leads to a slight inconsistency. We honor any tuning overrides -;; in GENERATE_MADD_MSUB for -mno-dsp, but always ignore them for -mdsp, -;; even if !ISA_HAS_DSP_MULT. -(define_insn "<u>msubsidi4" - [(set (match_operand:DI 0 "muldiv_target_operand" "=ka") - (minus:DI - (match_operand:DI 3 "muldiv_target_operand" "0") - (mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d")))))] - "!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB || ISA_HAS_DSP)" -{ - if (ISA_HAS_DSP_MULT) - return "msub<u>\t%q0,%1,%2"; - else if (TARGET_MIPS5500 || GENERATE_MADD_MSUB) - return "msub<u>\t%1,%2"; - else - return "msac<u>\t$0,%1,%2"; -} - [(set_attr "type" "imadd") - (set_attr "accum_in" "3") - (set_attr "mode" "SI")]) - -;; _highpart patterns - -(define_expand "<su>mulsi3_highpart" - [(set (match_operand:SI 0 "register_operand") - (truncate:SI - (lshiftrt:DI - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand"))) - (const_int 32))))] - "" -{ - if (ISA_HAS_MULHI) - emit_insn (gen_<su>mulsi3_highpart_mulhi_internal (operands[0], - operands[1], - operands[2])); - else if (TARGET_MIPS16) - emit_insn (gen_<su>mulsi3_highpart_split (operands[0], operands[1], - operands[2])); - else - emit_insn (gen_<su>mulsi3_highpart_internal (operands[0], operands[1], - operands[2])); - DONE; -}) - -(define_insn_and_split "<su>mulsi3_highpart_internal" - [(set (match_operand:SI 0 "register_operand" "=d") - (truncate:SI - (lshiftrt:DI - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=l"))] - "!ISA_HAS_MULHI && !TARGET_MIPS16" - { return TARGET_FIX_R4000 ? "mult<u>\t%1,%2\n\tmfhi\t%0" : "#"; } - "&& reload_completed && !TARGET_FIX_R4000" - [(const_int 0)] -{ - emit_insn (gen_<su>mulsi3_highpart_split (operands[0], operands[1], - operands[2])); - DONE; -} - [(set_attr "type" "imul") - (set_attr "mode" "SI") - (set_attr "length" "8")]) - -(define_expand "<su>mulsi3_highpart_split" - [(set (match_operand:SI 0 "register_operand") - (truncate:SI - (lshiftrt:DI - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) - (any_extend:DI (match_operand:SI 2 "register_operand"))) - (const_int 32))))] - "" -{ - rtx hilo; - - if (TARGET_64BIT) - { - hilo = gen_rtx_REG (TImode, MD_REG_FIRST); - emit_insn (gen_<u>mulsidi3_64bit_hilo (hilo, operands[1], operands[2])); - emit_insn (gen_mfhisi_ti (operands[0], hilo)); - } - else - { - hilo = gen_rtx_REG (DImode, MD_REG_FIRST); - emit_insn (gen_<u>mulsidi3_32bit (hilo, operands[1], operands[2])); - emit_insn (gen_mfhisi_di (operands[0], hilo)); - } - DONE; -}) - -(define_insn "<su>mulsi3_highpart_mulhi_internal" - [(set (match_operand:SI 0 "register_operand" "=d") - (truncate:SI - (lshiftrt:DI - (mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=l"))] - "ISA_HAS_MULHI" - "mulhi<u>\t%0,%1,%2" - [(set_attr "type" "imul3") - (set_attr "mode" "SI")]) - -(define_insn "*<su>mulsi3_highpart_neg_mulhi_internal" - [(set (match_operand:SI 0 "register_operand" "=d") - (truncate:SI - (lshiftrt:DI - (neg:DI - (mult:DI - (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=l"))] - "ISA_HAS_MULHI" - "mulshi<u>\t%0,%1,%2" - [(set_attr "type" "imul3") - (set_attr "mode" "SI")]) - -;; Disable unsigned multiplication for -mfix-vr4120. This is for VR4120 -;; errata MD(0), which says that dmultu does not always produce the -;; correct result. -(define_expand "<su>muldi3_highpart" - [(set (match_operand:DI 0 "register_operand") - (truncate:DI - (lshiftrt:TI - (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand")) - (any_extend:TI (match_operand:DI 2 "register_operand"))) - (const_int 64))))] - "TARGET_64BIT && !(<CODE> == ZERO_EXTEND && TARGET_FIX_VR4120)" -{ - if (TARGET_MIPS16) - emit_insn (gen_<su>muldi3_highpart_split (operands[0], operands[1], - operands[2])); - else - emit_insn (gen_<su>muldi3_highpart_internal (operands[0], operands[1], - operands[2])); - DONE; -}) - -(define_insn_and_split "<su>muldi3_highpart_internal" - [(set (match_operand:DI 0 "register_operand" "=d") - (truncate:DI - (lshiftrt:TI - (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d")) - (any_extend:TI (match_operand:DI 2 "register_operand" "d"))) - (const_int 64)))) - (clobber (match_scratch:DI 3 "=l"))] - "TARGET_64BIT - && !TARGET_MIPS16 - && !(<CODE> == ZERO_EXTEND && TARGET_FIX_VR4120)" - { return TARGET_FIX_R4000 ? "dmult<u>\t%1,%2\n\tmfhi\t%0" : "#"; } - "&& reload_completed && !TARGET_FIX_R4000" - [(const_int 0)] -{ - emit_insn (gen_<su>muldi3_highpart_split (operands[0], operands[1], - operands[2])); - DONE; -} - [(set_attr "type" "imul") - (set_attr "mode" "DI") - (set_attr "length" "8")]) - -(define_expand "<su>muldi3_highpart_split" - [(set (match_operand:DI 0 "register_operand") - (truncate:DI - (lshiftrt:TI - (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand")) - (any_extend:TI (match_operand:DI 2 "register_operand"))) - (const_int 64))))] - "" -{ - rtx hilo; - - hilo = gen_rtx_REG (TImode, MD_REG_FIRST); - emit_insn (gen_<u>mulditi3_internal (hilo, operands[1], operands[2])); - emit_insn (gen_mfhidi_ti (operands[0], hilo)); - DONE; -}) - -(define_expand "<u>mulditi3" - [(set (match_operand:TI 0 "register_operand") - (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand")) - (any_extend:TI (match_operand:DI 2 "register_operand"))))] - "TARGET_64BIT && !(<CODE> == ZERO_EXTEND && TARGET_FIX_VR4120)" -{ - rtx hilo; - - if (TARGET_MIPS16) - { - hilo = gen_rtx_REG (TImode, MD_REG_FIRST); - emit_insn (gen_<u>mulditi3_internal (hilo, operands[1], operands[2])); - emit_move_insn (operands[0], hilo); - } - else if (TARGET_FIX_R4000) - emit_insn (gen_<u>mulditi3_r4000 (operands[0], operands[1], operands[2])); - else - emit_insn (gen_<u>mulditi3_internal (operands[0], operands[1], - operands[2])); - DONE; -}) - -(define_insn "<u>mulditi3_internal" - [(set (match_operand:TI 0 "muldiv_target_operand" "=x") - (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d")) - (any_extend:TI (match_operand:DI 2 "register_operand" "d"))))] - "TARGET_64BIT - && !TARGET_FIX_R4000 - && !(<CODE> == ZERO_EXTEND && TARGET_FIX_VR4120)" - "dmult<u>\t%1,%2" - [(set_attr "type" "imul") - (set_attr "mode" "DI")]) - -(define_insn "<u>mulditi3_r4000" - [(set (match_operand:TI 0 "register_operand" "=d") - (mult:TI (any_extend:TI (match_operand:DI 1 "register_operand" "d")) - (any_extend:TI (match_operand:DI 2 "register_operand" "d")))) - (clobber (match_scratch:TI 3 "=x"))] - "TARGET_64BIT - && TARGET_FIX_R4000 - && !(<CODE> == ZERO_EXTEND && TARGET_FIX_VR4120)" - "dmult<u>\t%1,%2\;mflo\t%L0\;mfhi\t%M0" - [(set_attr "type" "imul") - (set_attr "mode" "DI") - (set_attr "length" "12")]) - -;; The R4650 supports a 32-bit multiply/ 64-bit accumulate -;; instruction. The HI/LO registers are used as a 64-bit accumulator. - -(define_insn "madsi" - [(set (match_operand:SI 0 "register_operand" "+l") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "register_operand" "d")) - (match_dup 0)))] - "TARGET_MAD" - "mad\t%1,%2" - [(set_attr "type" "imadd") - (set_attr "accum_in" "0") - (set_attr "mode" "SI")]) - -;; See the comment above <u>msubsidi4 for the relationship between -;; ISA_HAS_DSP and ISA_HAS_DSP_MULT. -(define_insn "<u>maddsidi4" - [(set (match_operand:DI 0 "muldiv_target_operand" "=ka") - (plus:DI - (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) - (any_extend:DI (match_operand:SI 2 "register_operand" "d"))) - (match_operand:DI 3 "muldiv_target_operand" "0")))] - "(TARGET_MAD || ISA_HAS_MACC || GENERATE_MADD_MSUB || ISA_HAS_DSP) - && !TARGET_64BIT" -{ - if (TARGET_MAD) - return "mad<u>\t%1,%2"; - else if (ISA_HAS_DSP_MULT) - return "madd<u>\t%q0,%1,%2"; - else if (GENERATE_MADD_MSUB || TARGET_MIPS5500) - return "madd<u>\t%1,%2"; - else - /* See comment in *macc. */ - return "%[macc<u>\t%@,%1,%2%]"; -} - [(set_attr "type" "imadd") - (set_attr "accum_in" "3") - (set_attr "mode" "SI")]) - -;; Floating point multiply accumulate instructions. - -(define_insn "*madd4<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "f")))] - "ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD" - "madd.<fmt>\t%0,%3,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*madd3<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "0")))] - "ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD" - "madd.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*msub4<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "f")))] - "ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD" - "msub.<fmt>\t%0,%3,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*msub3<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "0")))] - "ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD" - "msub.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmadd4<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (neg:ANYF (plus:ANYF - (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "f"))))] - "ISA_HAS_NMADD4_NMSUB4 (<MODE>mode) - && TARGET_FUSED_MADD - && HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmadd.<fmt>\t%0,%3,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmadd3<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (neg:ANYF (plus:ANYF - (mult:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "0"))))] - "ISA_HAS_NMADD3_NMSUB3 (<MODE>mode) - && TARGET_FUSED_MADD - && HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmadd.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmadd4<mode>_fastmath" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF - (mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")) - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "f")))] - "ISA_HAS_NMADD4_NMSUB4 (<MODE>mode) - && TARGET_FUSED_MADD - && !HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmadd.<fmt>\t%0,%3,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmadd3<mode>_fastmath" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF - (mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")) - (match_operand:ANYF 2 "register_operand" "f")) - (match_operand:ANYF 3 "register_operand" "0")))] - "ISA_HAS_NMADD3_NMSUB3 (<MODE>mode) - && TARGET_FUSED_MADD - && !HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmadd.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "3") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmsub4<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (neg:ANYF (minus:ANYF - (mult:ANYF (match_operand:ANYF 2 "register_operand" "f") - (match_operand:ANYF 3 "register_operand" "f")) - (match_operand:ANYF 1 "register_operand" "f"))))] - "ISA_HAS_NMADD4_NMSUB4 (<MODE>mode) - && TARGET_FUSED_MADD - && HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmsub.<fmt>\t%0,%1,%2,%3" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "1") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmsub3<mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (neg:ANYF (minus:ANYF - (mult:ANYF (match_operand:ANYF 2 "register_operand" "f") - (match_operand:ANYF 3 "register_operand" "f")) - (match_operand:ANYF 1 "register_operand" "0"))))] - "ISA_HAS_NMADD3_NMSUB3 (<MODE>mode) - && TARGET_FUSED_MADD - && HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmsub.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "1") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmsub4<mode>_fastmath" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF - (match_operand:ANYF 1 "register_operand" "f") - (mult:ANYF (match_operand:ANYF 2 "register_operand" "f") - (match_operand:ANYF 3 "register_operand" "f"))))] - "ISA_HAS_NMADD4_NMSUB4 (<MODE>mode) - && TARGET_FUSED_MADD - && !HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmsub.<fmt>\t%0,%1,%2,%3" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "1") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "*nmsub3<mode>_fastmath" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (minus:ANYF - (match_operand:ANYF 1 "register_operand" "f") - (mult:ANYF (match_operand:ANYF 2 "register_operand" "f") - (match_operand:ANYF 3 "register_operand" "0"))))] - "ISA_HAS_NMADD3_NMSUB3 (<MODE>mode) - && TARGET_FUSED_MADD - && !HONOR_SIGNED_ZEROS (<MODE>mode) - && !HONOR_NANS (<MODE>mode)" - "nmsub.<fmt>\t%0,%1,%2" - [(set_attr "type" "fmadd") - (set_attr "accum_in" "1") - (set_attr "mode" "<UNITMODE>")]) - -;; -;; .................... -;; -;; DIVISION and REMAINDER -;; -;; .................... -;; - -(define_expand "div<mode>3" - [(set (match_operand:ANYF 0 "register_operand") - (div:ANYF (match_operand:ANYF 1 "reg_or_1_operand") - (match_operand:ANYF 2 "register_operand")))] - "<divide_condition>" -{ - if (const_1_operand (operands[1], <MODE>mode)) - if (!(<recip_condition> && flag_unsafe_math_optimizations)) - operands[1] = force_reg (<MODE>mode, operands[1]); -}) - -;; These patterns work around the early SB-1 rev2 core "F1" erratum: -;; -;; If an mfc1 or dmfc1 happens to access the floating point register -;; file at the same time a long latency operation (div, sqrt, recip, -;; sqrt) iterates an intermediate result back through the floating -;; point register file bypass, then instead returning the correct -;; register value the mfc1 or dmfc1 operation returns the intermediate -;; result of the long latency operation. -;; -;; The workaround is to insert an unconditional 'mov' from/to the -;; long latency op destination register. - -(define_insn "*div<mode>3" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (div:ANYF (match_operand:ANYF 1 "register_operand" "f") - (match_operand:ANYF 2 "register_operand" "f")))] - "<divide_condition>" -{ - if (TARGET_FIX_SB1) - return "div.<fmt>\t%0,%1,%2\;mov.<fmt>\t%0,%0"; - else - return "div.<fmt>\t%0,%1,%2"; -} - [(set_attr "type" "fdiv") - (set_attr "mode" "<UNITMODE>") - (set (attr "length") - (if_then_else (match_test "TARGET_FIX_SB1") - (const_int 8) - (const_int 4)))]) - -(define_insn "*recip<mode>3" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (div:ANYF (match_operand:ANYF 1 "const_1_operand" "") - (match_operand:ANYF 2 "register_operand" "f")))] - "<recip_condition> && flag_unsafe_math_optimizations" -{ - if (TARGET_FIX_SB1) - return "recip.<fmt>\t%0,%2\;mov.<fmt>\t%0,%0"; - else - return "recip.<fmt>\t%0,%2"; -} - [(set_attr "type" "frdiv") - (set_attr "mode" "<UNITMODE>") - (set (attr "length") - (if_then_else (match_test "TARGET_FIX_SB1") - (const_int 8) - (const_int 4)))]) - -;; VR4120 errata MD(A1): signed division instructions do not work correctly -;; with negative operands. We use special libgcc functions instead. -(define_expand "divmod<mode>4" - [(set (match_operand:GPR 0 "register_operand") - (div:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand"))) - (set (match_operand:GPR 3 "register_operand") - (mod:GPR (match_dup 1) - (match_dup 2)))] - "!TARGET_FIX_VR4120" -{ - if (TARGET_MIPS16) - { - emit_insn (gen_divmod<mode>4_split (operands[3], operands[1], - operands[2])); - emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, LO_REGNUM)); - } - else - emit_insn (gen_divmod<mode>4_internal (operands[0], operands[1], - operands[2], operands[3])); - DONE; -}) - -(define_insn_and_split "divmod<mode>4_internal" - [(set (match_operand:GPR 0 "muldiv_target_operand" "=l") - (div:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d"))) - (set (match_operand:GPR 3 "register_operand" "=d") - (mod:GPR (match_dup 1) - (match_dup 2)))] - "!TARGET_FIX_VR4120 && !TARGET_MIPS16" - "#" - "&& reload_completed" - [(const_int 0)] -{ - emit_insn (gen_divmod<mode>4_split (operands[3], operands[1], operands[2])); - DONE; -} - [(set_attr "type" "idiv") - (set_attr "mode" "<MODE>") - (set_attr "length" "8")]) - -(define_expand "udivmod<mode>4" - [(set (match_operand:GPR 0 "register_operand") - (udiv:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand"))) - (set (match_operand:GPR 3 "register_operand") - (umod:GPR (match_dup 1) - (match_dup 2)))] - "" -{ - if (TARGET_MIPS16) - { - emit_insn (gen_udivmod<mode>4_split (operands[3], operands[1], - operands[2])); - emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, LO_REGNUM)); - } - else - emit_insn (gen_udivmod<mode>4_internal (operands[0], operands[1], - operands[2], operands[3])); - DONE; -}) - -(define_insn_and_split "udivmod<mode>4_internal" - [(set (match_operand:GPR 0 "muldiv_target_operand" "=l") - (udiv:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d"))) - (set (match_operand:GPR 3 "register_operand" "=d") - (umod:GPR (match_dup 1) - (match_dup 2)))] - "!TARGET_MIPS16" - "#" - "reload_completed" - [(const_int 0)] -{ - emit_insn (gen_udivmod<mode>4_split (operands[3], operands[1], operands[2])); - DONE; -} - [(set_attr "type" "idiv") - (set_attr "mode" "<MODE>") - (set_attr "length" "8")]) - -(define_expand "<u>divmod<mode>4_split" - [(set (match_operand:GPR 0 "register_operand") - (any_mod:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand")))] - "" -{ - rtx hilo; - - if (TARGET_64BIT) - { - hilo = gen_rtx_REG (TImode, MD_REG_FIRST); - emit_insn (gen_<u>divmod<mode>4_hilo_ti (hilo, operands[1], - operands[2])); - emit_insn (gen_mfhi<mode>_ti (operands[0], hilo)); - } - else - { - hilo = gen_rtx_REG (DImode, MD_REG_FIRST); - emit_insn (gen_<u>divmod<mode>4_hilo_di (hilo, operands[1], - operands[2])); - emit_insn (gen_mfhi<mode>_di (operands[0], hilo)); - } - DONE; -}) - -(define_insn "<u>divmod<GPR:mode>4_hilo_<HILO:mode>" - [(set (match_operand:HILO 0 "muldiv_target_operand" "=x") - (unspec:HILO - [(any_div:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d"))] - UNSPEC_SET_HILO))] - "" - { return mips_output_division ("<GPR:d>div<u>\t%.,%1,%2", operands); } - [(set_attr "type" "idiv") - (set_attr "mode" "<GPR:MODE>")]) - -;; -;; .................... -;; -;; SQUARE ROOT -;; -;; .................... - -;; These patterns work around the early SB-1 rev2 core "F1" erratum (see -;; "*div[sd]f3" comment for details). - -(define_insn "sqrt<mode>2" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))] - "<sqrt_condition>" -{ - if (TARGET_FIX_SB1) - return "sqrt.<fmt>\t%0,%1\;mov.<fmt>\t%0,%0"; - else - return "sqrt.<fmt>\t%0,%1"; -} - [(set_attr "type" "fsqrt") - (set_attr "mode" "<UNITMODE>") - (set (attr "length") - (if_then_else (match_test "TARGET_FIX_SB1") - (const_int 8) - (const_int 4)))]) - -(define_insn "*rsqrt<mode>a" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (div:ANYF (match_operand:ANYF 1 "const_1_operand" "") - (sqrt:ANYF (match_operand:ANYF 2 "register_operand" "f"))))] - "<recip_condition> && flag_unsafe_math_optimizations" -{ - if (TARGET_FIX_SB1) - return "rsqrt.<fmt>\t%0,%2\;mov.<fmt>\t%0,%0"; - else - return "rsqrt.<fmt>\t%0,%2"; -} - [(set_attr "type" "frsqrt") - (set_attr "mode" "<UNITMODE>") - (set (attr "length") - (if_then_else (match_test "TARGET_FIX_SB1") - (const_int 8) - (const_int 4)))]) - -(define_insn "*rsqrt<mode>b" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (sqrt:ANYF (div:ANYF (match_operand:ANYF 1 "const_1_operand" "") - (match_operand:ANYF 2 "register_operand" "f"))))] - "<recip_condition> && flag_unsafe_math_optimizations" -{ - if (TARGET_FIX_SB1) - return "rsqrt.<fmt>\t%0,%2\;mov.<fmt>\t%0,%0"; - else - return "rsqrt.<fmt>\t%0,%2"; -} - [(set_attr "type" "frsqrt") - (set_attr "mode" "<UNITMODE>") - (set (attr "length") - (if_then_else (match_test "TARGET_FIX_SB1") - (const_int 8) - (const_int 4)))]) - -;; -;; .................... -;; -;; ABSOLUTE VALUE -;; -;; .................... - -;; Do not use the integer abs macro instruction, since that signals an -;; exception on -2147483648 (sigh). - -;; abs.fmt is an arithmetic instruction and treats all NaN inputs as -;; invalid; it does not clear their sign bits. We therefore can't use -;; abs.fmt if the signs of NaNs matter. - -(define_insn "abs<mode>2" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (abs:ANYF (match_operand:ANYF 1 "register_operand" "f")))] - "!HONOR_NANS (<MODE>mode)" - "abs.<fmt>\t%0,%1" - [(set_attr "type" "fabs") - (set_attr "mode" "<UNITMODE>")]) - -;; -;; ................... -;; -;; Count leading zeroes. -;; -;; ................... -;; - -(define_insn "clz<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (clz:GPR (match_operand:GPR 1 "register_operand" "d")))] - "ISA_HAS_CLZ_CLO" - "<d>clz\t%0,%1" - [(set_attr "type" "clz") - (set_attr "mode" "<MODE>")]) - -;; -;; ................... -;; -;; Count number of set bits. -;; -;; ................... -;; - -(define_insn "popcount<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (popcount:GPR (match_operand:GPR 1 "register_operand" "d")))] - "ISA_HAS_POP" - "<d>pop\t%0,%1" - [(set_attr "type" "pop") - (set_attr "mode" "<MODE>")]) - -;; The POP instruction is special as it does not take into account the upper -;; 32bits and is documented that way. -(define_insn "*popcountdi2_trunc" - [(set (match_operand:SI 0 "register_operand" "=d") - (popcount:SI (truncate:SI (match_operand:DI 1 "register_operand" "d"))))] - "ISA_HAS_POP && TARGET_64BIT" - "pop\t%0,%1" - [(set_attr "type" "pop") - (set_attr "mode" "SI")]) - -;; -;; .................... -;; -;; NEGATION and ONE'S COMPLEMENT -;; -;; .................... - -(define_insn "negsi2" - [(set (match_operand:SI 0 "register_operand" "=d") - (neg:SI (match_operand:SI 1 "register_operand" "d")))] - "" -{ - if (TARGET_MIPS16) - return "neg\t%0,%1"; - else - return "subu\t%0,%.,%1"; -} - [(set_attr "alu_type" "sub") - (set_attr "mode" "SI")]) - -(define_insn "negdi2" - [(set (match_operand:DI 0 "register_operand" "=d") - (neg:DI (match_operand:DI 1 "register_operand" "d")))] - "TARGET_64BIT && !TARGET_MIPS16" - "dsubu\t%0,%.,%1" - [(set_attr "alu_type" "sub") - (set_attr "mode" "DI")]) - -;; neg.fmt is an arithmetic instruction and treats all NaN inputs as -;; invalid; it does not flip their sign bit. We therefore can't use -;; neg.fmt if the signs of NaNs matter. - -(define_insn "neg<mode>2" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (neg:ANYF (match_operand:ANYF 1 "register_operand" "f")))] - "!HONOR_NANS (<MODE>mode)" - "neg.<fmt>\t%0,%1" - [(set_attr "type" "fneg") - (set_attr "mode" "<UNITMODE>")]) - -(define_insn "one_cmpl<mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d") - (not:GPR (match_operand:GPR 1 "register_operand" "d")))] - "" -{ - if (TARGET_MIPS16) - return "not\t%0,%1"; - else - return "nor\t%0,%.,%1"; -} - [(set_attr "alu_type" "not") - (set_attr "mode" "<MODE>")]) - -;; -;; .................... -;; -;; LOGICAL -;; -;; .................... -;; - -;; Many of these instructions use trivial define_expands, because we -;; want to use a different set of constraints when TARGET_MIPS16. - -(define_expand "and<mode>3" - [(set (match_operand:GPR 0 "register_operand") - (and:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "and_reg_operand")))]) - -;; The middle-end is not allowed to convert ANDing with 0xffff_ffff into a -;; zero_extendsidi2 because of TRULY_NOOP_TRUNCATION, so handle these here. -;; Note that this variant does not trigger for SI mode because we require -;; a 64-bit HOST_WIDE_INT and 0xffff_ffff wouldn't be a canonical -;; sign-extended SImode value. -;; -;; These are possible combinations for operand 1 and 2. The table -;; includes both MIPS and MIPS16 cases. (r=register, mem=memory, -;; 16=MIPS16, x=match, S=split): -;; -;; \ op1 r/EXT r/!EXT mem r/16 mem/16 -;; op2 -;; -;; andi x x -;; 0xff x x x x -;; 0xffff x x x x -;; 0xffff_ffff x S x S x -;; low-bitmask x -;; register x x -;; register =op1 x - -(define_insn "*and<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d") - (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d") - (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))] - "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])" -{ - int len; - - switch (which_alternative) - { - case 0: - operands[1] = gen_lowpart (QImode, operands[1]); - return "lbu\t%0,%1"; - case 1: - operands[1] = gen_lowpart (HImode, operands[1]); - return "lhu\t%0,%1"; - case 2: - operands[1] = gen_lowpart (SImode, operands[1]); - return "lwu\t%0,%1"; - case 3: - return "andi\t%0,%1,%x2"; - case 4: - len = low_bitmask_len (<MODE>mode, INTVAL (operands[2])); - operands[2] = GEN_INT (len); - return "<d>ext\t%0,%1,0,%2"; - case 5: - return "#"; - case 6: - return "and\t%0,%1,%2"; - default: - gcc_unreachable (); - } -} - [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical") - (set_attr "mode" "<MODE>")]) - -(define_insn "*and<mode>3_mips16" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d") - (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%W,W,W,d,0") - (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d")))] - "TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])" -{ - switch (which_alternative) - { - case 0: - operands[1] = gen_lowpart (QImode, operands[1]); - return "lbu\t%0,%1"; - case 1: - operands[1] = gen_lowpart (HImode, operands[1]); - return "lhu\t%0,%1"; - case 2: - operands[1] = gen_lowpart (SImode, operands[1]); - return "lwu\t%0,%1"; - case 3: - return "#"; - case 4: - return "and\t%0,%2"; - default: - gcc_unreachable (); - } -} - [(set_attr "move_type" "load,load,load,shift_shift,logical") - (set_attr "mode" "<MODE>")]) - -(define_expand "ior<mode>3" - [(set (match_operand:GPR 0 "register_operand") - (ior:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "uns_arith_operand")))] - "" -{ - if (TARGET_MIPS16) - operands[2] = force_reg (<MODE>mode, operands[2]); -}) - -(define_insn "*ior<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (ior:GPR (match_operand:GPR 1 "register_operand" "%d,d") - (match_operand:GPR 2 "uns_arith_operand" "d,K")))] - "!TARGET_MIPS16" - "@ - or\t%0,%1,%2 - ori\t%0,%1,%x2" - [(set_attr "alu_type" "or") - (set_attr "mode" "<MODE>")]) - -(define_insn "*ior<mode>3_mips16" - [(set (match_operand:GPR 0 "register_operand" "=d") - (ior:GPR (match_operand:GPR 1 "register_operand" "%0") - (match_operand:GPR 2 "register_operand" "d")))] - "TARGET_MIPS16" - "or\t%0,%2" - [(set_attr "alu_type" "or") - (set_attr "mode" "<MODE>")]) - -(define_expand "xor<mode>3" - [(set (match_operand:GPR 0 "register_operand") - (xor:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "uns_arith_operand")))] - "" - "") - -(define_insn "" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (xor:GPR (match_operand:GPR 1 "register_operand" "%d,d") - (match_operand:GPR 2 "uns_arith_operand" "d,K")))] - "!TARGET_MIPS16" - "@ - xor\t%0,%1,%2 - xori\t%0,%1,%x2" - [(set_attr "alu_type" "xor") - (set_attr "mode" "<MODE>")]) - -(define_insn "" - [(set (match_operand:GPR 0 "register_operand" "=d,t,t") - (xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d") - (match_operand:GPR 2 "uns_arith_operand" "d,K,d")))] - "TARGET_MIPS16" - "@ - xor\t%0,%2 - cmpi\t%1,%2 - cmp\t%1,%2" - [(set_attr "alu_type" "xor") - (set_attr "mode" "<MODE>") - (set_attr_alternative "length" - [(const_int 4) - (if_then_else (match_operand:VOID 2 "m16_uimm8_1") - (const_int 4) - (const_int 8)) - (const_int 4)])]) - -(define_insn "*nor<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d") - (and:GPR (not:GPR (match_operand:GPR 1 "register_operand" "d")) - (not:GPR (match_operand:GPR 2 "register_operand" "d"))))] - "!TARGET_MIPS16" - "nor\t%0,%1,%2" - [(set_attr "alu_type" "nor") - (set_attr "mode" "<MODE>")]) - -;; -;; .................... -;; -;; TRUNCATION -;; -;; .................... - - - -(define_insn "truncdfsf2" - [(set (match_operand:SF 0 "register_operand" "=f") - (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" - "cvt.s.d\t%0,%1" - [(set_attr "type" "fcvt") - (set_attr "cnv_mode" "D2S") - (set_attr "mode" "SF")]) - -;; Integer truncation patterns. Truncating SImode values to smaller -;; modes is a no-op, as it is for most other GCC ports. Truncating -;; DImode values to SImode is not a no-op for TARGET_64BIT since we -;; need to make sure that the lower 32 bits are properly sign-extended -;; (see TRULY_NOOP_TRUNCATION). Truncating DImode values into modes -;; smaller than SImode is equivalent to two separate truncations: -;; -;; A B -;; DI ---> HI == DI ---> SI ---> HI -;; DI ---> QI == DI ---> SI ---> QI -;; -;; Step A needs a real instruction but step B does not. - -(define_insn "truncdi<mode>2" - [(set (match_operand:SUBDI 0 "nonimmediate_operand" "=d,m") - (truncate:SUBDI (match_operand:DI 1 "register_operand" "d,d")))] - "TARGET_64BIT" - "@ - sll\t%0,%1,0 - <store>\t%1,%0" - [(set_attr "move_type" "sll0,store") - (set_attr "mode" "SI")]) - -;; Combiner patterns to optimize shift/truncate combinations. - -(define_insn "*ashr_trunc<mode>" - [(set (match_operand:SUBDI 0 "register_operand" "=d") - (truncate:SUBDI - (ashiftrt:DI (match_operand:DI 1 "register_operand" "d") - (match_operand:DI 2 "const_arith_operand" ""))))] - "TARGET_64BIT && !TARGET_MIPS16 && IN_RANGE (INTVAL (operands[2]), 32, 63)" - "dsra\t%0,%1,%2" - [(set_attr "type" "shift") - (set_attr "mode" "<MODE>")]) - -(define_insn "*lshr32_trunc<mode>" - [(set (match_operand:SUBDI 0 "register_operand" "=d") - (truncate:SUBDI - (lshiftrt:DI (match_operand:DI 1 "register_operand" "d") - (const_int 32))))] - "TARGET_64BIT && !TARGET_MIPS16" - "dsra\t%0,%1,32" - [(set_attr "type" "shift") - (set_attr "mode" "<MODE>")]) - -;; Logical shift by more than 32 results in proper SI values so truncation is -;; removed by the middle end. Note that a logical shift by 32 is handled by -;; the previous pattern. -(define_insn "*<optab>_trunc<mode>_exts" - [(set (match_operand:SUBDI 0 "register_operand" "=d") - (truncate:SUBDI - (any_shiftrt:DI (match_operand:DI 1 "register_operand" "d") - (match_operand:DI 2 "const_arith_operand" ""))))] - "ISA_HAS_EXTS && TARGET_64BIT && UINTVAL (operands[2]) < 32" - "exts\t%0,%1,%2,31" - [(set_attr "type" "arith") - (set_attr "mode" "<MODE>")]) - -;; -;; .................... -;; -;; ZERO EXTENSION -;; -;; .................... - -;; Extension insns. - -(define_expand "zero_extendsidi2" - [(set (match_operand:DI 0 "register_operand") - (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand")))] - "TARGET_64BIT") - -(define_insn_and_split "*zero_extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))] - "TARGET_64BIT && !ISA_HAS_EXT_INS" - "@ - # - lwu\t%0,%1" - "&& reload_completed && REG_P (operands[1])" - [(set (match_dup 0) - (ashift:DI (match_dup 1) (const_int 32))) - (set (match_dup 0) - (lshiftrt:DI (match_dup 0) (const_int 32)))] - { operands[1] = gen_lowpart (DImode, operands[1]); } - [(set_attr "move_type" "shift_shift,load") - (set_attr "mode" "DI")]) - -(define_insn "*zero_extendsidi2_dext" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,W")))] - "TARGET_64BIT && ISA_HAS_EXT_INS" - "@ - dext\t%0,%1,0,32 - lwu\t%0,%1" - [(set_attr "move_type" "arith,load") - (set_attr "mode" "DI")]) - -;; See the comment before the *and<mode>3 pattern why this is generated by -;; combine. - -(define_split - [(set (match_operand:DI 0 "register_operand") - (and:DI (match_operand:DI 1 "register_operand") - (const_int 4294967295)))] - "TARGET_64BIT && !ISA_HAS_EXT_INS && reload_completed" - [(set (match_dup 0) - (ashift:DI (match_dup 1) (const_int 32))) - (set (match_dup 0) - (lshiftrt:DI (match_dup 0) (const_int 32)))]) - -(define_expand "zero_extend<SHORT:mode><GPR:mode>2" - [(set (match_operand:GPR 0 "register_operand") - (zero_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))] - "" -{ - if (TARGET_MIPS16 && !GENERATE_MIPS16E - && !memory_operand (operands[1], <SHORT:MODE>mode)) - { - emit_insn (gen_and<GPR:mode>3 (operands[0], - gen_lowpart (<GPR:MODE>mode, operands[1]), - force_reg (<GPR:MODE>mode, - GEN_INT (<SHORT:mask>)))); - DONE; - } -}) - -(define_insn "*zero_extend<SHORT:mode><GPR:mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (zero_extend:GPR - (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))] - "!TARGET_MIPS16" - "@ - andi\t%0,%1,<SHORT:mask> - l<SHORT:size>u\t%0,%1" - [(set_attr "move_type" "andi,load") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extend:GPR (match_operand:SHORT 1 "register_operand" "0")))] - "GENERATE_MIPS16E" - "ze<SHORT:size>\t%0" - ;; This instruction is effectively a special encoding of ANDI. - [(set_attr "move_type" "andi") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extend:GPR (match_operand:SHORT 1 "memory_operand" "m")))] - "TARGET_MIPS16" - "l<SHORT:size>u\t%0,%1" - [(set_attr "move_type" "load") - (set_attr "mode" "<GPR:MODE>")]) - -(define_expand "zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand")))] - "" -{ - if (TARGET_MIPS16 && !memory_operand (operands[1], QImode)) - { - emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]), - operands[1])); - DONE; - } -}) - -(define_insn "*zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] - "!TARGET_MIPS16" - "@ - andi\t%0,%1,0x00ff - lbu\t%0,%1" - [(set_attr "move_type" "andi,load") - (set_attr "mode" "HI")]) - -(define_insn "*zero_extendqihi2_mips16" - [(set (match_operand:HI 0 "register_operand" "=d") - (zero_extend:HI (match_operand:QI 1 "memory_operand" "m")))] - "TARGET_MIPS16" - "lbu\t%0,%1" - [(set_attr "move_type" "load") - (set_attr "mode" "HI")]) - -;; Combiner patterns to optimize truncate/zero_extend combinations. - -(define_insn "*zero_extend<GPR:mode>_trunc<SHORT:mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extend:GPR - (truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16" -{ - operands[2] = GEN_INT (GET_MODE_MASK (<SHORT:MODE>mode)); - return "andi\t%0,%1,%x2"; -} - [(set_attr "alu_type" "and") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*zero_extendhi_truncqi" - [(set (match_operand:HI 0 "register_operand" "=d") - (zero_extend:HI - (truncate:QI (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16" - "andi\t%0,%1,0xff" - [(set_attr "alu_type" "and") - (set_attr "mode" "HI")]) - -;; -;; .................... -;; -;; SIGN EXTENSION -;; -;; .................... - -;; Extension insns. -;; Those for integer source operand are ordered widest source type first. - -;; When TARGET_64BIT, all SImode integer and accumulator registers -;; should already be in sign-extended form (see TRULY_NOOP_TRUNCATION -;; and truncdisi2). We can therefore get rid of register->register -;; instructions if we constrain the source to be in the same register as -;; the destination. -;; -;; Only the pre-reload scheduler sees the type of the register alternatives; -;; we split them into nothing before the post-reload scheduler runs. -;; These alternatives therefore have type "move" in order to reflect -;; what happens if the two pre-reload operands cannot be tied, and are -;; instead allocated two separate GPRs. We don't distinguish between -;; the GPR and LO cases because we don't usually know during pre-reload -;; scheduling whether an operand will be LO or not. -(define_insn_and_split "extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=d,l,d") - (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,0,m")))] - "TARGET_64BIT" - "@ - # - # - lw\t%0,%1" - "&& reload_completed && register_operand (operands[1], VOIDmode)" - [(const_int 0)] -{ - emit_note (NOTE_INSN_DELETED); - DONE; -} - [(set_attr "move_type" "move,move,load") - (set_attr "mode" "DI")]) - -(define_expand "extend<SHORT:mode><GPR:mode>2" - [(set (match_operand:GPR 0 "register_operand") - (sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand")))] - "") - -(define_insn "*extend<SHORT:mode><GPR:mode>2_mips16e" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (sign_extend:GPR (match_operand:SHORT 1 "nonimmediate_operand" "0,m")))] - "GENERATE_MIPS16E" - "@ - se<SHORT:size>\t%0 - l<SHORT:size>\t%0,%1" - [(set_attr "move_type" "signext,load") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn_and_split "*extend<SHORT:mode><GPR:mode>2" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (sign_extend:GPR - (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))] - "!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E" - "@ - # - l<SHORT:size>\t%0,%1" - "&& reload_completed && REG_P (operands[1])" - [(set (match_dup 0) (ashift:GPR (match_dup 1) (match_dup 2))) - (set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))] -{ - operands[1] = gen_lowpart (<GPR:MODE>mode, operands[1]); - operands[2] = GEN_INT (GET_MODE_BITSIZE (<GPR:MODE>mode) - - GET_MODE_BITSIZE (<SHORT:MODE>mode)); -} - [(set_attr "move_type" "shift_shift,load") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*extend<SHORT:mode><GPR:mode>2_se<SHORT:size>" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (sign_extend:GPR - (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))] - "ISA_HAS_SEB_SEH" - "@ - se<SHORT:size>\t%0,%1 - l<SHORT:size>\t%0,%1" - [(set_attr "move_type" "signext,load") - (set_attr "mode" "<GPR:MODE>")]) - -(define_expand "extendqihi2" - [(set (match_operand:HI 0 "register_operand") - (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand")))] - "") - -(define_insn "*extendqihi2_mips16e" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,m")))] - "GENERATE_MIPS16E" - "@ - seb\t%0 - lb\t%0,%1" - [(set_attr "move_type" "signext,load") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (sign_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "d,m")))] - "!ISA_HAS_SEB_SEH && !GENERATE_MIPS16E" - "@ - # - lb\t%0,%1" - "&& reload_completed && REG_P (operands[1])" - [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2))) - (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 2)))] -{ - operands[0] = gen_lowpart (SImode, operands[0]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = GEN_INT (GET_MODE_BITSIZE (SImode) - - GET_MODE_BITSIZE (QImode)); -} - [(set_attr "move_type" "shift_shift,load") - (set_attr "mode" "SI")]) - -(define_insn "*extendqihi2_seb" - [(set (match_operand:HI 0 "register_operand" "=d,d") - (sign_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "d,m")))] - "ISA_HAS_SEB_SEH" - "@ - seb\t%0,%1 - lb\t%0,%1" - [(set_attr "move_type" "signext,load") - (set_attr "mode" "SI")]) - -;; Combiner patterns for truncate/sign_extend combinations. The SI versions -;; use the shift/truncate patterns. - -(define_insn_and_split "*extenddi_truncate<mode>" - [(set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI - (truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS" - "#" - "&& reload_completed" - [(set (match_dup 2) - (ashift:DI (match_dup 1) - (match_dup 3))) - (set (match_dup 0) - (ashiftrt:DI (match_dup 2) - (match_dup 3)))] -{ - operands[2] = gen_lowpart (DImode, operands[0]); - operands[3] = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (<MODE>mode)); -} - [(set_attr "move_type" "shift_shift") - (set_attr "mode" "DI")]) - -(define_insn_and_split "*extendsi_truncate<mode>" - [(set (match_operand:SI 0 "register_operand" "=d") - (sign_extend:SI - (truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS" - "#" - "&& reload_completed" - [(set (match_dup 2) - (ashift:DI (match_dup 1) - (match_dup 3))) - (set (match_dup 0) - (truncate:SI (ashiftrt:DI (match_dup 2) - (match_dup 3))))] -{ - operands[2] = gen_lowpart (DImode, operands[0]); - operands[3] = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (<MODE>mode)); -} - [(set_attr "move_type" "shift_shift") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*extendhi_truncateqi" - [(set (match_operand:HI 0 "register_operand" "=d") - (sign_extend:HI - (truncate:QI (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16 && !ISA_HAS_EXTS" - "#" - "&& reload_completed" - [(set (match_dup 2) - (ashift:DI (match_dup 1) - (const_int 56))) - (set (match_dup 0) - (truncate:HI (ashiftrt:DI (match_dup 2) - (const_int 56))))] -{ - operands[2] = gen_lowpart (DImode, operands[0]); -} - [(set_attr "move_type" "shift_shift") - (set_attr "mode" "SI")]) - -(define_insn "*extend<GPR:mode>_truncate<SHORT:mode>_exts" - [(set (match_operand:GPR 0 "register_operand" "=d") - (sign_extend:GPR - (truncate:SHORT (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16 && ISA_HAS_EXTS" -{ - operands[2] = GEN_INT (GET_MODE_BITSIZE (<SHORT:MODE>mode)); - return "exts\t%0,%1,0,%m2"; -} - [(set_attr "type" "arith") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*extendhi_truncateqi_exts" - [(set (match_operand:HI 0 "register_operand" "=d") - (sign_extend:HI - (truncate:QI (match_operand:DI 1 "register_operand" "d"))))] - "TARGET_64BIT && !TARGET_MIPS16 && ISA_HAS_EXTS" - "exts\t%0,%1,0,7" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - -(define_insn "extendsfdf2" - [(set (match_operand:DF 0 "register_operand" "=f") - (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" - "cvt.d.s\t%0,%1" - [(set_attr "type" "fcvt") - (set_attr "cnv_mode" "S2D") - (set_attr "mode" "DF")]) - -;; -;; .................... -;; -;; CONVERSIONS -;; -;; .................... - -(define_expand "fix_truncdfsi2" - [(set (match_operand:SI 0 "register_operand") - (fix:SI (match_operand:DF 1 "register_operand")))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" -{ - if (!ISA_HAS_TRUNC_W) - { - emit_insn (gen_fix_truncdfsi2_macro (operands[0], operands[1])); - DONE; - } -}) - -(define_insn "fix_truncdfsi2_insn" - [(set (match_operand:SI 0 "register_operand" "=f") - (fix:SI (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && ISA_HAS_TRUNC_W" - "trunc.w.d %0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "DF") - (set_attr "cnv_mode" "D2I")]) - -(define_insn "fix_truncdfsi2_macro" - [(set (match_operand:SI 0 "register_operand" "=f") - (fix:SI (match_operand:DF 1 "register_operand" "f"))) - (clobber (match_scratch:DF 2 "=d"))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W" -{ - if (mips_nomacro.nesting_level > 0) - return ".set\tmacro\;trunc.w.d %0,%1,%2\;.set\tnomacro"; - else - return "trunc.w.d %0,%1,%2"; -} - [(set_attr "type" "fcvt") - (set_attr "mode" "DF") - (set_attr "cnv_mode" "D2I") - (set_attr "length" "36")]) - -(define_expand "fix_truncsfsi2" - [(set (match_operand:SI 0 "register_operand") - (fix:SI (match_operand:SF 1 "register_operand")))] - "TARGET_HARD_FLOAT" -{ - if (!ISA_HAS_TRUNC_W) - { - emit_insn (gen_fix_truncsfsi2_macro (operands[0], operands[1])); - DONE; - } -}) - -(define_insn "fix_truncsfsi2_insn" - [(set (match_operand:SI 0 "register_operand" "=f") - (fix:SI (match_operand:SF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && ISA_HAS_TRUNC_W" - "trunc.w.s %0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "SF") - (set_attr "cnv_mode" "S2I")]) - -(define_insn "fix_truncsfsi2_macro" - [(set (match_operand:SI 0 "register_operand" "=f") - (fix:SI (match_operand:SF 1 "register_operand" "f"))) - (clobber (match_scratch:SF 2 "=d"))] - "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W" -{ - if (mips_nomacro.nesting_level > 0) - return ".set\tmacro\;trunc.w.s %0,%1,%2\;.set\tnomacro"; - else - return "trunc.w.s %0,%1,%2"; -} - [(set_attr "type" "fcvt") - (set_attr "mode" "SF") - (set_attr "cnv_mode" "S2I") - (set_attr "length" "36")]) - - -(define_insn "fix_truncdfdi2" - [(set (match_operand:DI 0 "register_operand" "=f") - (fix:DI (match_operand:DF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" - "trunc.l.d %0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "DF") - (set_attr "cnv_mode" "D2I")]) - - -(define_insn "fix_truncsfdi2" - [(set (match_operand:DI 0 "register_operand" "=f") - (fix:DI (match_operand:SF 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" - "trunc.l.s %0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "SF") - (set_attr "cnv_mode" "S2I")]) - - -(define_insn "floatsidf2" - [(set (match_operand:DF 0 "register_operand" "=f") - (float:DF (match_operand:SI 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" - "cvt.d.w\t%0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "DF") - (set_attr "cnv_mode" "I2D")]) - - -(define_insn "floatdidf2" - [(set (match_operand:DF 0 "register_operand" "=f") - (float:DF (match_operand:DI 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" - "cvt.d.l\t%0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "DF") - (set_attr "cnv_mode" "I2D")]) - - -(define_insn "floatsisf2" - [(set (match_operand:SF 0 "register_operand" "=f") - (float:SF (match_operand:SI 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT" - "cvt.s.w\t%0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "SF") - (set_attr "cnv_mode" "I2S")]) - - -(define_insn "floatdisf2" - [(set (match_operand:SF 0 "register_operand" "=f") - (float:SF (match_operand:DI 1 "register_operand" "f")))] - "TARGET_HARD_FLOAT && TARGET_FLOAT64 && TARGET_DOUBLE_FLOAT" - "cvt.s.l\t%0,%1" - [(set_attr "type" "fcvt") - (set_attr "mode" "SF") - (set_attr "cnv_mode" "I2S")]) - - -(define_expand "fixuns_truncdfsi2" - [(set (match_operand:SI 0 "register_operand") - (unsigned_fix:SI (match_operand:DF 1 "register_operand")))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" -{ - rtx reg1 = gen_reg_rtx (DFmode); - rtx reg2 = gen_reg_rtx (DFmode); - rtx reg3 = gen_reg_rtx (SImode); - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx test; - REAL_VALUE_TYPE offset; - - real_2expN (&offset, 31, DFmode); - - if (reg1) /* Turn off complaints about unreached code. */ - { - mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode)); - do_pending_stack_adjust (); - - test = gen_rtx_GE (VOIDmode, operands[1], reg1); - emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1)); - - emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1])); - emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, - gen_rtx_LABEL_REF (VOIDmode, label2))); - emit_barrier (); - - emit_label (label1); - mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1)); - mips_emit_move (reg3, GEN_INT (trunc_int_for_mode - (BITMASK_HIGH, SImode))); - - emit_insn (gen_fix_truncdfsi2 (operands[0], reg2)); - emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); - - emit_label (label2); - - /* Allow REG_NOTES to be set on last insn (labels don't have enough - fields, and can't be used for REG_NOTES anyway). */ - emit_use (stack_pointer_rtx); - DONE; - } -}) - - -(define_expand "fixuns_truncdfdi2" - [(set (match_operand:DI 0 "register_operand") - (unsigned_fix:DI (match_operand:DF 1 "register_operand")))] - "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" -{ - rtx reg1 = gen_reg_rtx (DFmode); - rtx reg2 = gen_reg_rtx (DFmode); - rtx reg3 = gen_reg_rtx (DImode); - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx test; - REAL_VALUE_TYPE offset; - - real_2expN (&offset, 63, DFmode); - - mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode)); - do_pending_stack_adjust (); - - test = gen_rtx_GE (VOIDmode, operands[1], reg1); - emit_jump_insn (gen_cbranchdf4 (test, operands[1], reg1, label1)); - - emit_insn (gen_fix_truncdfdi2 (operands[0], operands[1])); - emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, - gen_rtx_LABEL_REF (VOIDmode, label2))); - emit_barrier (); - - emit_label (label1); - mips_emit_move (reg2, gen_rtx_MINUS (DFmode, operands[1], reg1)); - mips_emit_move (reg3, GEN_INT (BITMASK_HIGH)); - emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32))); - - emit_insn (gen_fix_truncdfdi2 (operands[0], reg2)); - emit_insn (gen_iordi3 (operands[0], operands[0], reg3)); - - emit_label (label2); - - /* Allow REG_NOTES to be set on last insn (labels don't have enough - fields, and can't be used for REG_NOTES anyway). */ - emit_use (stack_pointer_rtx); - DONE; -}) - - -(define_expand "fixuns_truncsfsi2" - [(set (match_operand:SI 0 "register_operand") - (unsigned_fix:SI (match_operand:SF 1 "register_operand")))] - "TARGET_HARD_FLOAT" -{ - rtx reg1 = gen_reg_rtx (SFmode); - rtx reg2 = gen_reg_rtx (SFmode); - rtx reg3 = gen_reg_rtx (SImode); - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx test; - REAL_VALUE_TYPE offset; - - real_2expN (&offset, 31, SFmode); - - mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode)); - do_pending_stack_adjust (); - - test = gen_rtx_GE (VOIDmode, operands[1], reg1); - emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1)); - - emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1])); - emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, - gen_rtx_LABEL_REF (VOIDmode, label2))); - emit_barrier (); - - emit_label (label1); - mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1)); - mips_emit_move (reg3, GEN_INT (trunc_int_for_mode - (BITMASK_HIGH, SImode))); - - emit_insn (gen_fix_truncsfsi2 (operands[0], reg2)); - emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); - - emit_label (label2); - - /* Allow REG_NOTES to be set on last insn (labels don't have enough - fields, and can't be used for REG_NOTES anyway). */ - emit_use (stack_pointer_rtx); - DONE; -}) - - -(define_expand "fixuns_truncsfdi2" - [(set (match_operand:DI 0 "register_operand") - (unsigned_fix:DI (match_operand:SF 1 "register_operand")))] - "TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT" -{ - rtx reg1 = gen_reg_rtx (SFmode); - rtx reg2 = gen_reg_rtx (SFmode); - rtx reg3 = gen_reg_rtx (DImode); - rtx label1 = gen_label_rtx (); - rtx label2 = gen_label_rtx (); - rtx test; - REAL_VALUE_TYPE offset; - - real_2expN (&offset, 63, SFmode); - - mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode)); - do_pending_stack_adjust (); - - test = gen_rtx_GE (VOIDmode, operands[1], reg1); - emit_jump_insn (gen_cbranchsf4 (test, operands[1], reg1, label1)); - - emit_insn (gen_fix_truncsfdi2 (operands[0], operands[1])); - emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, - gen_rtx_LABEL_REF (VOIDmode, label2))); - emit_barrier (); - - emit_label (label1); - mips_emit_move (reg2, gen_rtx_MINUS (SFmode, operands[1], reg1)); - mips_emit_move (reg3, GEN_INT (BITMASK_HIGH)); - emit_insn (gen_ashldi3 (reg3, reg3, GEN_INT (32))); - - emit_insn (gen_fix_truncsfdi2 (operands[0], reg2)); - emit_insn (gen_iordi3 (operands[0], operands[0], reg3)); - - emit_label (label2); - - /* Allow REG_NOTES to be set on last insn (labels don't have enough - fields, and can't be used for REG_NOTES anyway). */ - emit_use (stack_pointer_rtx); - DONE; -}) - -;; -;; .................... -;; -;; DATA MOVEMENT -;; -;; .................... - -;; Bit field extract patterns which use lwl/lwr or ldl/ldr. - -(define_expand "extvmisalign<mode>" - [(set (match_operand:GPR 0 "register_operand") - (sign_extract:GPR (match_operand:BLK 1 "memory_operand") - (match_operand 2 "const_int_operand") - (match_operand 3 "const_int_operand")))] - "!TARGET_MIPS16" -{ - if (mips_expand_ext_as_unaligned_load (operands[0], operands[1], - INTVAL (operands[2]), - INTVAL (operands[3]), - /*unsigned=*/ false)) - DONE; - else - FAIL; -}) - -(define_expand "extv<mode>" - [(set (match_operand:GPR 0 "register_operand") - (sign_extract:GPR (match_operand:GPR 1 "register_operand") - (match_operand 2 "const_int_operand") - (match_operand 3 "const_int_operand")))] - "ISA_HAS_EXTS" -{ - if (UINTVAL (operands[2]) > 32) - FAIL; -}) - -(define_insn "*extv<mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (sign_extract:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand 2 "const_int_operand" "") - (match_operand 3 "const_int_operand" "")))] - "ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32" - "exts\t%0,%1,%3,%m2" - [(set_attr "type" "arith") - (set_attr "mode" "<MODE>")]) - -(define_expand "extzvmisalign<mode>" - [(set (match_operand:GPR 0 "register_operand") - (zero_extract:GPR (match_operand:BLK 1 "memory_operand") - (match_operand 2 "const_int_operand") - (match_operand 3 "const_int_operand")))] - "!TARGET_MIPS16" -{ - if (mips_expand_ext_as_unaligned_load (operands[0], operands[1], - INTVAL (operands[2]), - INTVAL (operands[3]), - /*unsigned=*/ true)) - DONE; - else - FAIL; -}) - -(define_expand "extzv<mode>" - [(set (match_operand:GPR 0 "register_operand") - (zero_extract:GPR (match_operand:GPR 1 "register_operand") - (match_operand 2 "const_int_operand") - (match_operand 3 "const_int_operand")))] - "" -{ - if (!mips_use_ins_ext_p (operands[1], INTVAL (operands[2]), - INTVAL (operands[3]))) - FAIL; -}) - -(define_insn "*extzv<mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (zero_extract:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand 2 "const_int_operand" "") - (match_operand 3 "const_int_operand" "")))] - "mips_use_ins_ext_p (operands[1], INTVAL (operands[2]), - INTVAL (operands[3]))" - "<d>ext\t%0,%1,%3,%2" - [(set_attr "type" "arith") - (set_attr "mode" "<MODE>")]) - -(define_insn "*extzv_truncsi_exts" - [(set (match_operand:SI 0 "register_operand" "=d") - (truncate:SI - (zero_extract:DI (match_operand:DI 1 "register_operand" "d") - (match_operand 2 "const_int_operand" "") - (match_operand 3 "const_int_operand" ""))))] - "ISA_HAS_EXTS && TARGET_64BIT && IN_RANGE (INTVAL (operands[2]), 32, 63)" - "exts\t%0,%1,%3,31" - [(set_attr "type" "arith") - (set_attr "mode" "SI")]) - - -(define_expand "insvmisalign<mode>" - [(set (zero_extract:GPR (match_operand:BLK 0 "memory_operand") - (match_operand 1 "const_int_operand") - (match_operand 2 "const_int_operand")) - (match_operand:GPR 3 "reg_or_0_operand"))] - "!TARGET_MIPS16" -{ - if (mips_expand_ins_as_unaligned_store (operands[0], operands[3], - INTVAL (operands[1]), - INTVAL (operands[2]))) - DONE; - else - FAIL; -}) - -(define_expand "insv<mode>" - [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand") - (match_operand 1 "const_int_operand") - (match_operand 2 "const_int_operand")) - (match_operand:GPR 3 "reg_or_0_operand"))] - "" -{ - if (!mips_use_ins_ext_p (operands[0], INTVAL (operands[1]), - INTVAL (operands[2]))) - FAIL; -}) - -(define_insn "*insv<mode>" - [(set (zero_extract:GPR (match_operand:GPR 0 "register_operand" "+d") - (match_operand:SI 1 "const_int_operand" "") - (match_operand:SI 2 "const_int_operand" "")) - (match_operand:GPR 3 "reg_or_0_operand" "dJ"))] - "mips_use_ins_ext_p (operands[0], INTVAL (operands[1]), - INTVAL (operands[2]))" - "<d>ins\t%0,%z3,%2,%1" - [(set_attr "type" "arith") - (set_attr "mode" "<MODE>")]) - -;; Combiner pattern for cins (clear and insert bit field). We can -;; implement mask-and-shift-left operation with this. Note that if -;; the upper bit of the mask is set in an SImode operation, the mask -;; itself will be sign-extended. mask_low_and_shift_len will -;; therefore be greater than our threshold of 32. - -(define_insn "*cins<mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (and:GPR - (ashift:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "const_int_operand" "")) - (match_operand:GPR 3 "const_int_operand" "")))] - "ISA_HAS_CINS - && mask_low_and_shift_p (<MODE>mode, operands[3], operands[2], 32)" -{ - operands[3] = - GEN_INT (mask_low_and_shift_len (<MODE>mode, operands[3], operands[2])); - return "cins\t%0,%1,%2,%m3"; -} - [(set_attr "type" "shift") - (set_attr "mode" "<MODE>")]) - -;; Unaligned word moves generated by the bit field patterns. -;; -;; As far as the rtl is concerned, both the left-part and right-part -;; instructions can access the whole field. However, the real operand -;; refers to just the first or the last byte (depending on endianness). -;; We therefore use two memory operands to each instruction, one to -;; describe the rtl effect and one to use in the assembly output. -;; -;; Operands 0 and 1 are the rtl-level target and source respectively. -;; This allows us to use the standard length calculations for the "load" -;; and "store" type attributes. - -(define_insn "mov_<load>l" - [(set (match_operand:GPR 0 "register_operand" "=d") - (unspec:GPR [(match_operand:BLK 1 "memory_operand" "m") - (match_operand:QI 2 "memory_operand" "m")] - UNSPEC_LOAD_LEFT))] - "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])" - "<load>l\t%0,%2" - [(set_attr "move_type" "load") - (set_attr "mode" "<MODE>")]) - -(define_insn "mov_<load>r" - [(set (match_operand:GPR 0 "register_operand" "=d") - (unspec:GPR [(match_operand:BLK 1 "memory_operand" "m") - (match_operand:QI 2 "memory_operand" "m") - (match_operand:GPR 3 "register_operand" "0")] - UNSPEC_LOAD_RIGHT))] - "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])" - "<load>r\t%0,%2" - [(set_attr "move_type" "load") - (set_attr "mode" "<MODE>")]) - -(define_insn "mov_<store>l" - [(set (match_operand:BLK 0 "memory_operand" "=m") - (unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ") - (match_operand:QI 2 "memory_operand" "m")] - UNSPEC_STORE_LEFT))] - "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])" - "<store>l\t%z1,%2" - [(set_attr "move_type" "store") - (set_attr "mode" "<MODE>")]) - -(define_insn "mov_<store>r" - [(set (match_operand:BLK 0 "memory_operand" "+m") - (unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ") - (match_operand:QI 2 "memory_operand" "m") - (match_dup 0)] - UNSPEC_STORE_RIGHT))] - "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])" - "<store>r\t%z1,%2" - [(set_attr "move_type" "store") - (set_attr "mode" "<MODE>")]) - -;; An instruction to calculate the high part of a 64-bit SYMBOL_ABSOLUTE. -;; The required value is: -;; -;; (%highest(op1) << 48) + (%higher(op1) << 32) + (%hi(op1) << 16) -;; -;; which translates to: -;; -;; lui op0,%highest(op1) -;; daddiu op0,op0,%higher(op1) -;; dsll op0,op0,16 -;; daddiu op0,op0,%hi(op1) -;; dsll op0,op0,16 -;; -;; The split is deferred until after flow2 to allow the peephole2 below -;; to take effect. -(define_insn_and_split "*lea_high64" - [(set (match_operand:DI 0 "register_operand" "=d") - (high:DI (match_operand:DI 1 "absolute_symbolic_operand" "")))] - "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS" - "#" - "&& epilogue_completed" - [(set (match_dup 0) (high:DI (match_dup 2))) - (set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 2))) - (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16))) - (set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3))) - (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 16)))] -{ - operands[2] = mips_unspec_address (operands[1], SYMBOL_64_HIGH); - operands[3] = mips_unspec_address (operands[1], SYMBOL_64_MID); -} - [(set_attr "length" "20")]) - -;; Use a scratch register to reduce the latency of the above pattern -;; on superscalar machines. The optimized sequence is: -;; -;; lui op1,%highest(op2) -;; lui op0,%hi(op2) -;; daddiu op1,op1,%higher(op2) -;; dsll32 op1,op1,0 -;; daddu op1,op1,op0 -(define_peephole2 - [(set (match_operand:DI 1 "d_operand") - (high:DI (match_operand:DI 2 "absolute_symbolic_operand"))) - (match_scratch:DI 0 "d")] - "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS" - [(set (match_dup 1) (high:DI (match_dup 3))) - (set (match_dup 0) (high:DI (match_dup 4))) - (set (match_dup 1) (lo_sum:DI (match_dup 1) (match_dup 3))) - (set (match_dup 1) (ashift:DI (match_dup 1) (const_int 32))) - (set (match_dup 1) (plus:DI (match_dup 1) (match_dup 0)))] -{ - operands[3] = mips_unspec_address (operands[2], SYMBOL_64_HIGH); - operands[4] = mips_unspec_address (operands[2], SYMBOL_64_LOW); -}) - -;; On most targets, the expansion of (lo_sum (high X) X) for a 64-bit -;; SYMBOL_ABSOLUTE X will take 6 cycles. This next pattern allows combine -;; to merge the HIGH and LO_SUM parts of a move if the HIGH part is only -;; used once. We can then use the sequence: -;; -;; lui op0,%highest(op1) -;; lui op2,%hi(op1) -;; daddiu op0,op0,%higher(op1) -;; daddiu op2,op2,%lo(op1) -;; dsll32 op0,op0,0 -;; daddu op0,op0,op2 -;; -;; which takes 4 cycles on most superscalar targets. -(define_insn_and_split "*lea64" - [(set (match_operand:DI 0 "register_operand" "=d") - (match_operand:DI 1 "absolute_symbolic_operand" "")) - (clobber (match_scratch:DI 2 "=&d"))] - "TARGET_EXPLICIT_RELOCS && ABI_HAS_64BIT_SYMBOLS && cse_not_expected" - "#" - "&& reload_completed" - [(set (match_dup 0) (high:DI (match_dup 3))) - (set (match_dup 2) (high:DI (match_dup 4))) - (set (match_dup 0) (lo_sum:DI (match_dup 0) (match_dup 3))) - (set (match_dup 2) (lo_sum:DI (match_dup 2) (match_dup 4))) - (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32))) - (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 2)))] -{ - operands[3] = mips_unspec_address (operands[1], SYMBOL_64_HIGH); - operands[4] = mips_unspec_address (operands[1], SYMBOL_64_LOW); -} - [(set_attr "length" "24")]) - -;; Split HIGHs into: -;; -;; li op0,%hi(sym) -;; sll op0,16 -;; -;; on MIPS16 targets. -(define_split - [(set (match_operand:P 0 "d_operand") - (high:P (match_operand:P 1 "symbolic_operand_with_high")))] - "TARGET_MIPS16 && reload_completed" - [(set (match_dup 0) (unspec:P [(match_dup 1)] UNSPEC_UNSHIFTED_HIGH)) - (set (match_dup 0) (ashift:P (match_dup 0) (const_int 16)))]) - -(define_insn "*unshifted_high" - [(set (match_operand:P 0 "d_operand" "=d") - (unspec:P [(match_operand:P 1 "symbolic_operand_with_high")] - UNSPEC_UNSHIFTED_HIGH))] - "" - "li\t%0,%h1" - [(set_attr "extended_mips16" "yes")]) - -;; Insns to fetch a symbol from a big GOT. - -(define_insn_and_split "*xgot_hi<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (high:P (match_operand:P 1 "got_disp_operand" "")))] - "TARGET_EXPLICIT_RELOCS && TARGET_XGOT" - "#" - "&& reload_completed" - [(set (match_dup 0) (high:P (match_dup 2))) - (set (match_dup 0) (plus:P (match_dup 0) (match_dup 3)))] -{ - operands[2] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_DISP); - operands[3] = pic_offset_table_rtx; -} - [(set_attr "got" "xgot_high") - (set_attr "mode" "<MODE>")]) - -(define_insn_and_split "*xgot_lo<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (lo_sum:P (match_operand:P 1 "register_operand" "d") - (match_operand:P 2 "got_disp_operand" "")))] - "TARGET_EXPLICIT_RELOCS && TARGET_XGOT" - "#" - "&& reload_completed" - [(set (match_dup 0) - (unspec:P [(match_dup 1) (match_dup 3)] UNSPEC_LOAD_GOT))] - { operands[3] = mips_unspec_address (operands[2], SYMBOL_GOTOFF_DISP); } - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) - -;; Insns to fetch a symbol from a normal GOT. - -(define_insn_and_split "*got_disp<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (match_operand:P 1 "got_disp_operand" ""))] - "TARGET_EXPLICIT_RELOCS && !mips_split_p[SYMBOL_GOT_DISP]" - "#" - "&& reload_completed" - [(set (match_dup 0) (match_dup 2))] - { operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_DISP); } - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) - -;; Insns for loading the "page" part of a page/ofst address from the GOT. - -(define_insn_and_split "*got_page<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (high:P (match_operand:P 1 "got_page_ofst_operand" "")))] - "TARGET_EXPLICIT_RELOCS && !mips_split_hi_p[SYMBOL_GOT_PAGE_OFST]" - "#" - "&& reload_completed" - [(set (match_dup 0) (match_dup 2))] - { operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_PAGE); } - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) - -;; Convenience expander that generates the rhs of a load_got<mode> insn. -(define_expand "unspec_got_<mode>" - [(unspec:P [(match_operand:P 0) - (match_operand:P 1)] UNSPEC_LOAD_GOT)]) - -;; Lower-level instructions for loading an address from the GOT. -;; We could use MEMs, but an unspec gives more optimization -;; opportunities. - -(define_insn "load_got<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec:P [(match_operand:P 1 "register_operand" "d") - (match_operand:P 2 "immediate_operand" "")] - UNSPEC_LOAD_GOT))] - "" - "<load>\t%0,%R2(%1)" - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) - -;; Instructions for adding the low 16 bits of an address to a register. -;; Operand 2 is the address: mips_print_operand works out which relocation -;; should be applied. - -(define_insn "*low<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (lo_sum:P (match_operand:P 1 "register_operand" "d") - (match_operand:P 2 "immediate_operand" "")))] - "!TARGET_MIPS16" - "<d>addiu\t%0,%1,%R2" - [(set_attr "alu_type" "add") - (set_attr "mode" "<MODE>")]) - -(define_insn "*low<mode>_mips16" - [(set (match_operand:P 0 "register_operand" "=d") - (lo_sum:P (match_operand:P 1 "register_operand" "0") - (match_operand:P 2 "immediate_operand" "")))] - "TARGET_MIPS16" - "<d>addiu\t%0,%R2" - [(set_attr "alu_type" "add") - (set_attr "mode" "<MODE>") - (set_attr "extended_mips16" "yes")]) - -;; Expose MIPS16 uses of the global pointer after reload if the function -;; is responsible for setting up the register itself. -(define_split - [(set (match_operand:GPR 0 "d_operand") - (const:GPR (unspec:GPR [(const_int 0)] UNSPEC_GP)))] - "TARGET_MIPS16 && TARGET_USE_GOT && reload_completed" - [(set (match_dup 0) (match_dup 1))] - { operands[1] = pic_offset_table_rtx; }) - -;; Allow combine to split complex const_int load sequences, using operand 2 -;; to store the intermediate results. See move_operand for details. -(define_split - [(set (match_operand:GPR 0 "register_operand") - (match_operand:GPR 1 "splittable_const_int_operand")) - (clobber (match_operand:GPR 2 "register_operand"))] - "" - [(const_int 0)] -{ - mips_move_integer (operands[2], operands[0], INTVAL (operands[1])); - DONE; -}) - -;; Likewise, for symbolic operands. -(define_split - [(set (match_operand:P 0 "register_operand") - (match_operand:P 1)) - (clobber (match_operand:P 2 "register_operand"))] - "mips_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL)" - [(set (match_dup 0) (match_dup 3))] -{ - mips_split_symbol (operands[2], operands[1], - MAX_MACHINE_MODE, &operands[3]); -}) - -;; 64-bit integer moves - -;; Unlike most other insns, the move insns can't be split with -;; different predicates, because register spilling and other parts of -;; the compiler, have memoized the insn number already. - -(define_expand "movdi" - [(set (match_operand:DI 0 "") - (match_operand:DI 1 ""))] - "" -{ - if (mips_legitimize_move (DImode, operands[0], operands[1])) - DONE; -}) - -;; For mips16, we need a special case to handle storing $31 into -;; memory, since we don't have a constraint to match $31. This -;; instruction can be generated by save_restore_insns. - -(define_insn "*mov<mode>_ra" - [(set (match_operand:GPR 0 "stack_operand" "=m") - (reg:GPR RETURN_ADDR_REGNUM))] - "TARGET_MIPS16" - "<store>\t$31,%0" - [(set_attr "move_type" "store") - (set_attr "mode" "<MODE>")]) - -(define_insn "*movdi_32bit" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*a,*d,*f,*f,*d,*m,*B*C*D,*B*C*D,*d,*m") - (match_operand:DI 1 "move_operand" "d,i,m,d,*J,*d,*a,*J*d,*m,*f,*f,*d,*m,*B*C*D,*B*C*D"))] - "!TARGET_64BIT && !TARGET_MIPS16 - && (register_operand (operands[0], DImode) - || reg_or_0_operand (operands[1], DImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,const,load,store,imul,mtlo,mflo,mtc,fpload,mfc,fpstore,mtc,fpload,mfc,fpstore") - (set (attr "mode") - (if_then_else (eq_attr "move_type" "imul") - (const_string "SI") - (const_string "DI")))]) - -(define_insn "*movdi_32bit_mips16" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") - (match_operand:DI 1 "move_operand" "d,d,y,K,N,m,d,*x"))] - "!TARGET_64BIT && TARGET_MIPS16 - && (register_operand (operands[0], DImode) - || register_operand (operands[1], DImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,const,constN,load,store,mflo") - (set_attr "mode" "DI")]) - -(define_insn "*movdi_64bit" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*a,*d,*B*C*D,*B*C*D,*d,*m") - (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))] - "TARGET_64BIT && !TARGET_MIPS16 - && (register_operand (operands[0], DImode) - || reg_or_0_operand (operands[1], DImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mtlo,mflo,mtc,fpload,mfc,fpstore") - (set_attr "mode" "DI")]) - -(define_insn "*movdi_64bit_mips16" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d") - (match_operand:DI 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))] - "TARGET_64BIT && TARGET_MIPS16 - && (register_operand (operands[0], DImode) - || register_operand (operands[1], DImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,const,constN,const,loadpool,load,store,mflo") - (set_attr "mode" "DI")]) - -;; On the mips16, we can split ld $r,N($r) into an add and a load, -;; when the original load is a 4 byte instruction but the add and the -;; load are 2 2 byte instructions. - -(define_split - [(set (match_operand:DI 0 "d_operand") - (mem:DI (plus:DI (match_dup 0) - (match_operand:DI 1 "const_int_operand"))))] - "TARGET_64BIT && TARGET_MIPS16 && reload_completed - && !TARGET_DEBUG_D_MODE - && ((INTVAL (operands[1]) < 0 - && INTVAL (operands[1]) >= -0x10) - || (INTVAL (operands[1]) >= 32 * 8 - && INTVAL (operands[1]) <= 31 * 8 + 0x8) - || (INTVAL (operands[1]) >= 0 - && INTVAL (operands[1]) < 32 * 8 - && (INTVAL (operands[1]) & 7) != 0))" - [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) - (set (match_dup 0) (mem:DI (plus:DI (match_dup 0) (match_dup 2))))] -{ - HOST_WIDE_INT val = INTVAL (operands[1]); - - if (val < 0) - operands[2] = const0_rtx; - else if (val >= 32 * 8) - { - int off = val & 7; - - operands[1] = GEN_INT (0x8 + off); - operands[2] = GEN_INT (val - off - 0x8); - } - else - { - int off = val & 7; - - operands[1] = GEN_INT (off); - operands[2] = GEN_INT (val - off); - } -}) - -;; 32-bit Integer moves - -;; Unlike most other insns, the move insns can't be split with -;; different predicates, because register spilling and other parts of -;; the compiler, have memoized the insn number already. - -(define_expand "mov<mode>" - [(set (match_operand:IMOVE32 0 "") - (match_operand:IMOVE32 1 ""))] - "" -{ - if (mips_legitimize_move (<MODE>mode, operands[0], operands[1])) - DONE; -}) - -;; The difference between these two is whether or not ints are allowed -;; in FP registers (off by default, use -mdebugh to enable). - -(define_insn "*mov<mode>_internal" - [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m") - (match_operand:IMOVE32 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))] - "!TARGET_MIPS16 - && (register_operand (operands[0], <MODE>mode) - || reg_or_0_operand (operands[1], <MODE>mode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore") - (set_attr "mode" "SI")]) - -(define_insn "*mov<mode>_mips16" - [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d") - (match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))] - "TARGET_MIPS16 - && (register_operand (operands[0], <MODE>mode) - || register_operand (operands[1], <MODE>mode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,const,constN,const,loadpool,load,store,mflo") - (set_attr "mode" "SI")]) - -;; On the mips16, we can split lw $r,N($r) into an add and a load, -;; when the original load is a 4 byte instruction but the add and the -;; load are 2 2 byte instructions. - -(define_split - [(set (match_operand:SI 0 "d_operand") - (mem:SI (plus:SI (match_dup 0) - (match_operand:SI 1 "const_int_operand"))))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && ((INTVAL (operands[1]) < 0 - && INTVAL (operands[1]) >= -0x80) - || (INTVAL (operands[1]) >= 32 * 4 - && INTVAL (operands[1]) <= 31 * 4 + 0x7c) - || (INTVAL (operands[1]) >= 0 - && INTVAL (operands[1]) < 32 * 4 - && (INTVAL (operands[1]) & 3) != 0))" - [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) - (set (match_dup 0) (mem:SI (plus:SI (match_dup 0) (match_dup 2))))] -{ - HOST_WIDE_INT val = INTVAL (operands[1]); - - if (val < 0) - operands[2] = const0_rtx; - else if (val >= 32 * 4) - { - int off = val & 3; - - operands[1] = GEN_INT (0x7c + off); - operands[2] = GEN_INT (val - off - 0x7c); - } - else - { - int off = val & 3; - - operands[1] = GEN_INT (off); - operands[2] = GEN_INT (val - off); - } -}) - -;; On the mips16, we can split a load of certain constants into a load -;; and an add. This turns a 4 byte instruction into 2 2 byte -;; instructions. - -(define_split - [(set (match_operand:SI 0 "d_operand") - (match_operand:SI 1 "const_int_operand"))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && INTVAL (operands[1]) >= 0x100 - && INTVAL (operands[1]) <= 0xff + 0x7f" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] -{ - int val = INTVAL (operands[1]); - - operands[1] = GEN_INT (0xff); - operands[2] = GEN_INT (val - 0xff); -}) - -;; MIPS4 supports loading and storing a floating point register from -;; the sum of two general registers. We use two versions for each of -;; these four instructions: one where the two general registers are -;; SImode, and one where they are DImode. This is because general -;; registers will be in SImode when they hold 32-bit values, but, -;; since the 32-bit values are always sign extended, the [ls][wd]xc1 -;; instructions will still work correctly. - -;; ??? Perhaps it would be better to support these instructions by -;; modifying TARGET_LEGITIMATE_ADDRESS_P and friends. However, since -;; these instructions can only be used to load and store floating -;; point registers, that would probably cause trouble in reload. - -(define_insn "*<ANYF:loadx>_<P:mode>" - [(set (match_operand:ANYF 0 "register_operand" "=f") - (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d") - (match_operand:P 2 "register_operand" "d"))))] - "ISA_HAS_FP4" - "<ANYF:loadx>\t%0,%1(%2)" - [(set_attr "type" "fpidxload") - (set_attr "mode" "<ANYF:UNITMODE>")]) - -(define_insn "*<ANYF:storex>_<P:mode>" - [(set (mem:ANYF (plus:P (match_operand:P 1 "register_operand" "d") - (match_operand:P 2 "register_operand" "d"))) - (match_operand:ANYF 0 "register_operand" "f"))] - "ISA_HAS_FP4" - "<ANYF:storex>\t%0,%1(%2)" - [(set_attr "type" "fpidxstore") - (set_attr "mode" "<ANYF:UNITMODE>")]) - -;; Scaled indexed address load. -;; Per md.texi, we only need to look for a pattern with multiply in the -;; address expression, not shift. - -(define_insn "*lwxs" - [(set (match_operand:IMOVE32 0 "register_operand" "=d") - (mem:IMOVE32 - (plus:P (mult:P (match_operand:P 1 "register_operand" "d") - (const_int 4)) - (match_operand:P 2 "register_operand" "d"))))] - "ISA_HAS_LWXS" - "lwxs\t%0,%1(%2)" - [(set_attr "type" "load") - (set_attr "mode" "SI")]) - -;; 16-bit Integer moves - -;; Unlike most other insns, the move insns can't be split with -;; different predicates, because register spilling and other parts of -;; the compiler, have memoized the insn number already. -;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND. - -(define_expand "movhi" - [(set (match_operand:HI 0 "") - (match_operand:HI 1 ""))] - "" -{ - if (mips_legitimize_move (HImode, operands[0], operands[1])) - DONE; -}) - -(define_insn "*movhi_internal" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d") - (match_operand:HI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))] - "!TARGET_MIPS16 - && (register_operand (operands[0], HImode) - || reg_or_0_operand (operands[1], HImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,const,load,store,mtlo,mflo") - (set_attr "mode" "HI")]) - -(define_insn "*movhi_mips16" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") - (match_operand:HI 1 "move_operand" "d,d,y,K,N,m,d,*a"))] - "TARGET_MIPS16 - && (register_operand (operands[0], HImode) - || register_operand (operands[1], HImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,const,constN,load,store,mflo") - (set_attr "mode" "HI")]) - -;; On the mips16, we can split lh $r,N($r) into an add and a load, -;; when the original load is a 4 byte instruction but the add and the -;; load are 2 2 byte instructions. - -(define_split - [(set (match_operand:HI 0 "d_operand") - (mem:HI (plus:SI (match_dup 0) - (match_operand:SI 1 "const_int_operand"))))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && ((INTVAL (operands[1]) < 0 - && INTVAL (operands[1]) >= -0x80) - || (INTVAL (operands[1]) >= 32 * 2 - && INTVAL (operands[1]) <= 31 * 2 + 0x7e) - || (INTVAL (operands[1]) >= 0 - && INTVAL (operands[1]) < 32 * 2 - && (INTVAL (operands[1]) & 1) != 0))" - [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) - (set (match_dup 0) (mem:HI (plus:SI (match_dup 0) (match_dup 2))))] -{ - HOST_WIDE_INT val = INTVAL (operands[1]); - - if (val < 0) - operands[2] = const0_rtx; - else if (val >= 32 * 2) - { - int off = val & 1; - - operands[1] = GEN_INT (0x7e + off); - operands[2] = GEN_INT (val - off - 0x7e); - } - else - { - int off = val & 1; - - operands[1] = GEN_INT (off); - operands[2] = GEN_INT (val - off); - } -}) - -;; 8-bit Integer moves - -;; Unlike most other insns, the move insns can't be split with -;; different predicates, because register spilling and other parts of -;; the compiler, have memoized the insn number already. -;; Unsigned loads are used because LOAD_EXTEND_OP returns ZERO_EXTEND. - -(define_expand "movqi" - [(set (match_operand:QI 0 "") - (match_operand:QI 1 ""))] - "" -{ - if (mips_legitimize_move (QImode, operands[0], operands[1])) - DONE; -}) - -(define_insn "*movqi_internal" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d") - (match_operand:QI 1 "move_operand" "d,I,m,dJ,*d*J,*a"))] - "!TARGET_MIPS16 - && (register_operand (operands[0], QImode) - || reg_or_0_operand (operands[1], QImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,const,load,store,mtlo,mflo") - (set_attr "mode" "QI")]) - -(define_insn "*movqi_mips16" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") - (match_operand:QI 1 "move_operand" "d,d,y,K,N,m,d,*a"))] - "TARGET_MIPS16 - && (register_operand (operands[0], QImode) - || register_operand (operands[1], QImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,const,constN,load,store,mflo") - (set_attr "mode" "QI")]) - -;; On the mips16, we can split lb $r,N($r) into an add and a load, -;; when the original load is a 4 byte instruction but the add and the -;; load are 2 2 byte instructions. - -(define_split - [(set (match_operand:QI 0 "d_operand") - (mem:QI (plus:SI (match_dup 0) - (match_operand:SI 1 "const_int_operand"))))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && ((INTVAL (operands[1]) < 0 - && INTVAL (operands[1]) >= -0x80) - || (INTVAL (operands[1]) >= 32 - && INTVAL (operands[1]) <= 31 + 0x7f))" - [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) - (set (match_dup 0) (mem:QI (plus:SI (match_dup 0) (match_dup 2))))] -{ - HOST_WIDE_INT val = INTVAL (operands[1]); - - if (val < 0) - operands[2] = const0_rtx; - else - { - operands[1] = GEN_INT (0x7f); - operands[2] = GEN_INT (val - 0x7f); - } -}) - -;; 32-bit floating point moves - -(define_expand "movsf" - [(set (match_operand:SF 0 "") - (match_operand:SF 1 ""))] - "" -{ - if (mips_legitimize_move (SFmode, operands[0], operands[1])) - DONE; -}) - -(define_insn "*movsf_hardfloat" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") - (match_operand:SF 1 "move_operand" "f,G,m,f,G,*d,*f,*G*d,*m,*d"))] - "TARGET_HARD_FLOAT - && (register_operand (operands[0], SFmode) - || reg_or_0_operand (operands[1], SFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") - (set_attr "mode" "SF")]) - -(define_insn "*movsf_softfloat" - [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,m") - (match_operand:SF 1 "move_operand" "Gd,m,d"))] - "TARGET_SOFT_FLOAT && !TARGET_MIPS16 - && (register_operand (operands[0], SFmode) - || reg_or_0_operand (operands[1], SFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,load,store") - (set_attr "mode" "SF")]) - -(define_insn "*movsf_mips16" - [(set (match_operand:SF 0 "nonimmediate_operand" "=d,y,d,d,m") - (match_operand:SF 1 "move_operand" "d,d,y,m,d"))] - "TARGET_MIPS16 - && (register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,load,store") - (set_attr "mode" "SF")]) - -;; 64-bit floating point moves - -(define_expand "movdf" - [(set (match_operand:DF 0 "") - (match_operand:DF 1 ""))] - "" -{ - if (mips_legitimize_move (DFmode, operands[0], operands[1])) - DONE; -}) - -(define_insn "*movdf_hardfloat" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") - (match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))] - "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT - && (register_operand (operands[0], DFmode) - || reg_or_0_operand (operands[1], DFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") - (set_attr "mode" "DF")]) - -(define_insn "*movdf_softfloat" - [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,m") - (match_operand:DF 1 "move_operand" "dG,m,dG"))] - "(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT) && !TARGET_MIPS16 - && (register_operand (operands[0], DFmode) - || reg_or_0_operand (operands[1], DFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,load,store") - (set_attr "mode" "DF")]) - -(define_insn "*movdf_mips16" - [(set (match_operand:DF 0 "nonimmediate_operand" "=d,y,d,d,m") - (match_operand:DF 1 "move_operand" "d,d,y,m,d"))] - "TARGET_MIPS16 - && (register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,move,move,load,store") - (set_attr "mode" "DF")]) - -;; 128-bit integer moves - -(define_expand "movti" - [(set (match_operand:TI 0) - (match_operand:TI 1))] - "TARGET_64BIT" -{ - if (mips_legitimize_move (TImode, operands[0], operands[1])) - DONE; -}) - -(define_insn "*movti" - [(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,m,*a,*a,*d") - (match_operand:TI 1 "move_operand" "d,i,m,dJ,*J,*d,*a"))] - "TARGET_64BIT - && !TARGET_MIPS16 - && (register_operand (operands[0], TImode) - || reg_or_0_operand (operands[1], TImode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "move,const,load,store,imul,mtlo,mflo") - (set (attr "mode") - (if_then_else (eq_attr "move_type" "imul") - (const_string "SI") - (const_string "TI")))]) - -(define_insn "*movti_mips16" - [(set (match_operand:TI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") - (match_operand:TI 1 "move_operand" "d,d,y,K,N,m,d,*a"))] - "TARGET_64BIT - && TARGET_MIPS16 - && (register_operand (operands[0], TImode) - || register_operand (operands[1], TImode))" - "#" - [(set_attr "move_type" "move,move,move,const,constN,load,store,mflo") - (set_attr "mode" "TI")]) - -;; 128-bit floating point moves - -(define_expand "movtf" - [(set (match_operand:TF 0) - (match_operand:TF 1))] - "TARGET_64BIT" -{ - if (mips_legitimize_move (TFmode, operands[0], operands[1])) - DONE; -}) - -;; This pattern handles both hard- and soft-float cases. -(define_insn "*movtf" - [(set (match_operand:TF 0 "nonimmediate_operand" "=d,d,m,f,d,f,m") - (match_operand:TF 1 "move_operand" "dG,m,dG,dG,f,m,f"))] - "TARGET_64BIT - && !TARGET_MIPS16 - && (register_operand (operands[0], TFmode) - || reg_or_0_operand (operands[1], TFmode))" - "#" - [(set_attr "move_type" "move,load,store,mtc,mfc,fpload,fpstore") - (set_attr "mode" "TF")]) - -(define_insn "*movtf_mips16" - [(set (match_operand:TF 0 "nonimmediate_operand" "=d,y,d,d,m") - (match_operand:TF 1 "move_operand" "d,d,y,m,d"))] - "TARGET_64BIT - && TARGET_MIPS16 - && (register_operand (operands[0], TFmode) - || register_operand (operands[1], TFmode))" - "#" - [(set_attr "move_type" "move,move,move,load,store") - (set_attr "mode" "TF")]) - -(define_split - [(set (match_operand:MOVE64 0 "nonimmediate_operand") - (match_operand:MOVE64 1 "move_operand"))] - "reload_completed && mips_split_move_insn_p (operands[0], operands[1], insn)" - [(const_int 0)] -{ - mips_split_move_insn (operands[0], operands[1], curr_insn); - DONE; -}) - -(define_split - [(set (match_operand:MOVE128 0 "nonimmediate_operand") - (match_operand:MOVE128 1 "move_operand"))] - "reload_completed && mips_split_move_insn_p (operands[0], operands[1], insn)" - [(const_int 0)] -{ - mips_split_move_insn (operands[0], operands[1], curr_insn); - DONE; -}) - -;; When generating mips16 code, split moves of negative constants into -;; a positive "li" followed by a negation. -(define_split - [(set (match_operand 0 "d_operand") - (match_operand 1 "const_int_operand"))] - "TARGET_MIPS16 && reload_completed && INTVAL (operands[1]) < 0" - [(set (match_dup 2) - (match_dup 3)) - (set (match_dup 2) - (neg:SI (match_dup 2)))] -{ - operands[2] = gen_lowpart (SImode, operands[0]); - operands[3] = GEN_INT (-INTVAL (operands[1])); -}) - -;; 64-bit paired-single floating point moves - -(define_expand "movv2sf" - [(set (match_operand:V2SF 0) - (match_operand:V2SF 1))] - "TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT" -{ - if (mips_legitimize_move (V2SFmode, operands[0], operands[1])) - DONE; -}) - -(define_insn "*movv2sf" - [(set (match_operand:V2SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") - (match_operand:V2SF 1 "move_operand" "f,YG,m,f,YG,*d,*f,*d*YG,*m,*d"))] - "TARGET_HARD_FLOAT - && TARGET_PAIRED_SINGLE_FLOAT - && (register_operand (operands[0], V2SFmode) - || reg_or_0_operand (operands[1], V2SFmode))" - { return mips_output_move (operands[0], operands[1]); } - [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store") - (set_attr "mode" "DF")]) - -;; Extract the high part of a HI/LO value. See mips_hard_regno_mode_ok_p -;; for the reason why we can't just use (reg:GPR HI_REGNUM). -;; -;; When generating VR4120 or VR4130 code, we use MACCHI and DMACCHI -;; instead of MFHI. This avoids both the normal MIPS III hi/lo hazards -;; and the errata related to -mfix-vr4130. -(define_insn "mfhi<GPR:mode>_<HILO:mode>" - [(set (match_operand:GPR 0 "register_operand" "=d") - (unspec:GPR [(match_operand:HILO 1 "hilo_operand" "x")] - UNSPEC_MFHI))] - "" - { return ISA_HAS_MACCHI ? "<GPR:d>macchi\t%0,%.,%." : "mfhi\t%0"; } - [(set_attr "type" "mfhi") - (set_attr "mode" "<GPR:MODE>")]) - -;; Set the high part of a HI/LO value, given that the low part has -;; already been set. See mips_hard_regno_mode_ok_p for the reason -;; why we can't just use (reg:GPR HI_REGNUM). -(define_insn "mthi<GPR:mode>_<HILO:mode>" - [(set (match_operand:HILO 0 "register_operand" "=x") - (unspec:HILO [(match_operand:GPR 1 "reg_or_0_operand" "dJ") - (match_operand:GPR 2 "register_operand" "l")] - UNSPEC_MTHI))] - "" - "mthi\t%z1" - [(set_attr "type" "mthi") - (set_attr "mode" "SI")]) - -;; Emit a doubleword move in which exactly one of the operands is -;; a floating-point register. We can't just emit two normal moves -;; because of the constraints imposed by the FPU register model; -;; see mips_cannot_change_mode_class for details. Instead, we keep -;; the FPR whole and use special patterns to refer to each word of -;; the other operand. - -(define_expand "move_doubleword_fpr<mode>" - [(set (match_operand:SPLITF 0) - (match_operand:SPLITF 1))] - "" -{ - if (FP_REG_RTX_P (operands[0])) - { - rtx low = mips_subword (operands[1], 0); - rtx high = mips_subword (operands[1], 1); - emit_insn (gen_load_low<mode> (operands[0], low)); - if (TARGET_FLOAT64 && !TARGET_64BIT) - emit_insn (gen_mthc1<mode> (operands[0], high, operands[0])); - else - emit_insn (gen_load_high<mode> (operands[0], high, operands[0])); - } - else - { - rtx low = mips_subword (operands[0], 0); - rtx high = mips_subword (operands[0], 1); - emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx)); - if (TARGET_FLOAT64 && !TARGET_64BIT) - emit_insn (gen_mfhc1<mode> (high, operands[1])); - else - emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx)); - } - DONE; -}) - -;; Load the low word of operand 0 with operand 1. -(define_insn "load_low<mode>" - [(set (match_operand:SPLITF 0 "register_operand" "=f,f") - (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "dJ,m")] - UNSPEC_LOAD_LOW))] - "TARGET_HARD_FLOAT" -{ - operands[0] = mips_subword (operands[0], 0); - return mips_output_move (operands[0], operands[1]); -} - [(set_attr "move_type" "mtc,fpload") - (set_attr "mode" "<HALFMODE>")]) - -;; Load the high word of operand 0 from operand 1, preserving the value -;; in the low word. -(define_insn "load_high<mode>" - [(set (match_operand:SPLITF 0 "register_operand" "=f,f") - (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "dJ,m") - (match_operand:SPLITF 2 "register_operand" "0,0")] - UNSPEC_LOAD_HIGH))] - "TARGET_HARD_FLOAT" -{ - operands[0] = mips_subword (operands[0], 1); - return mips_output_move (operands[0], operands[1]); -} - [(set_attr "move_type" "mtc,fpload") - (set_attr "mode" "<HALFMODE>")]) - -;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the -;; high word and 0 to store the low word. -(define_insn "store_word<mode>" - [(set (match_operand:<HALFMODE> 0 "nonimmediate_operand" "=d,m") - (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f,f") - (match_operand 2 "const_int_operand")] - UNSPEC_STORE_WORD))] - "TARGET_HARD_FLOAT" -{ - operands[1] = mips_subword (operands[1], INTVAL (operands[2])); - return mips_output_move (operands[0], operands[1]); -} - [(set_attr "move_type" "mfc,fpstore") - (set_attr "mode" "<HALFMODE>")]) - -;; Move operand 1 to the high word of operand 0 using mthc1, preserving the -;; value in the low word. -(define_insn "mthc1<mode>" - [(set (match_operand:SPLITF 0 "register_operand" "=f") - (unspec:SPLITF [(match_operand:<HALFMODE> 1 "reg_or_0_operand" "dJ") - (match_operand:SPLITF 2 "register_operand" "0")] - UNSPEC_MTHC1))] - "TARGET_HARD_FLOAT && ISA_HAS_MXHC1" - "mthc1\t%z1,%0" - [(set_attr "move_type" "mtc") - (set_attr "mode" "<HALFMODE>")]) - -;; Move high word of operand 1 to operand 0 using mfhc1. -(define_insn "mfhc1<mode>" - [(set (match_operand:<HALFMODE> 0 "register_operand" "=d") - (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f")] - UNSPEC_MFHC1))] - "TARGET_HARD_FLOAT && ISA_HAS_MXHC1" - "mfhc1\t%0,%1" - [(set_attr "move_type" "mfc") - (set_attr "mode" "<HALFMODE>")]) - -;; Move a constant that satisfies CONST_GP_P into operand 0. -(define_expand "load_const_gp_<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (const:P (unspec:P [(const_int 0)] UNSPEC_GP)))]) - -;; Insn to initialize $gp for n32/n64 abicalls. Operand 0 is the offset -;; of _gp from the start of this function. Operand 1 is the incoming -;; function address. -(define_insn_and_split "loadgp_newabi_<mode>" - [(set (match_operand:P 0 "register_operand" "=&d") - (unspec:P [(match_operand:P 1) - (match_operand:P 2 "register_operand" "d")] - UNSPEC_LOADGP))] - "mips_current_loadgp_style () == LOADGP_NEWABI" - { return mips_must_initialize_gp_p () ? "#" : ""; } - "&& mips_must_initialize_gp_p ()" - [(set (match_dup 0) (match_dup 3)) - (set (match_dup 0) (match_dup 4)) - (set (match_dup 0) (match_dup 5))] -{ - operands[3] = gen_rtx_HIGH (Pmode, operands[1]); - operands[4] = gen_rtx_PLUS (Pmode, operands[0], operands[2]); - operands[5] = gen_rtx_LO_SUM (Pmode, operands[0], operands[1]); -} - [(set_attr "type" "ghost")]) - -;; Likewise, for -mno-shared code. Operand 0 is the __gnu_local_gp symbol. -(define_insn_and_split "loadgp_absolute_<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec:P [(match_operand:P 1)] UNSPEC_LOADGP))] - "mips_current_loadgp_style () == LOADGP_ABSOLUTE" - { return mips_must_initialize_gp_p () ? "#" : ""; } - "&& mips_must_initialize_gp_p ()" - [(const_int 0)] -{ - mips_emit_move (operands[0], operands[1]); - DONE; -} - [(set_attr "type" "ghost")]) - -;; This blockage instruction prevents the gp load from being -;; scheduled after an implicit use of gp. It also prevents -;; the load from being deleted as dead. -(define_insn "loadgp_blockage" - [(unspec_volatile [(reg:SI 28)] UNSPEC_BLOCKAGE)] - "" - "" - [(set_attr "type" "ghost")]) - -;; Initialize $gp for RTP PIC. Operand 0 is the __GOTT_BASE__ symbol -;; and operand 1 is the __GOTT_INDEX__ symbol. -(define_insn_and_split "loadgp_rtp_<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec:P [(match_operand:P 1 "symbol_ref_operand") - (match_operand:P 2 "symbol_ref_operand")] - UNSPEC_LOADGP))] - "mips_current_loadgp_style () == LOADGP_RTP" - { return mips_must_initialize_gp_p () ? "#" : ""; } - "&& mips_must_initialize_gp_p ()" - [(set (match_dup 0) (high:P (match_dup 3))) - (set (match_dup 0) (unspec:P [(match_dup 0) - (match_dup 3)] UNSPEC_LOAD_GOT)) - (set (match_dup 0) (unspec:P [(match_dup 0) - (match_dup 4)] UNSPEC_LOAD_GOT))] -{ - operands[3] = mips_unspec_address (operands[1], SYMBOL_ABSOLUTE); - operands[4] = mips_unspec_address (operands[2], SYMBOL_HALF); -} - [(set_attr "type" "ghost")]) - -;; Initialize the global pointer for MIPS16 code. Operand 0 is the -;; global pointer and operand 1 is the MIPS16 register that holds -;; the required value. -(define_insn_and_split "copygp_mips16_<mode>" - [(set (match_operand:P 0 "register_operand" "=y") - (unspec:P [(match_operand:P 1 "register_operand" "d")] - UNSPEC_COPYGP))] - "TARGET_MIPS16" - { return mips_must_initialize_gp_p () ? "#" : ""; } - "&& mips_must_initialize_gp_p ()" - [(set (match_dup 0) (match_dup 1))] - "" - [(set_attr "type" "ghost")]) - -;; A placeholder for where the cprestore instruction should go, -;; if we decide we need one. Operand 0 and operand 1 are as for -;; "cprestore". Operand 2 is a register that holds the gp value. -;; -;; The "cprestore" pattern requires operand 2 to be pic_offset_table_rtx, -;; otherwise any register that holds the correct value will do. -(define_insn_and_split "potential_cprestore_<mode>" - [(set (match_operand:P 0 "cprestore_save_slot_operand" "=X,X") - (unspec:P [(match_operand:P 1 "const_int_operand" "I,i") - (match_operand:P 2 "register_operand" "d,d")] - UNSPEC_POTENTIAL_CPRESTORE)) - (clobber (match_operand:P 3 "scratch_operand" "=X,&d"))] - "!TARGET_CPRESTORE_DIRECTIVE || operands[2] == pic_offset_table_rtx" - { return mips_must_initialize_gp_p () ? "#" : ""; } - "mips_must_initialize_gp_p ()" - [(const_int 0)] -{ - mips_save_gp_to_cprestore_slot (operands[0], operands[1], - operands[2], operands[3]); - DONE; -} - [(set_attr "type" "ghost")]) - -;; Emit a .cprestore directive, which normally expands to a single store -;; instruction. Operand 0 is a (possibly illegitimate) sp-based MEM -;; for the cprestore slot. Operand 1 is the offset of the slot from -;; the stack pointer. (This is redundant with operand 0, but it makes -;; things a little simpler.) -(define_insn "cprestore_<mode>" - [(set (match_operand:P 0 "cprestore_save_slot_operand" "=X,X") - (unspec:P [(match_operand:P 1 "const_int_operand" "I,i") - (reg:P 28)] - UNSPEC_CPRESTORE))] - "TARGET_CPRESTORE_DIRECTIVE" -{ - if (mips_nomacro.nesting_level > 0 && which_alternative == 1) - return ".set\tmacro\;.cprestore\t%1\;.set\tnomacro"; - else - return ".cprestore\t%1"; -} - [(set_attr "type" "store") - (set_attr "length" "4,12")]) - -(define_insn "use_cprestore_<mode>" - [(set (reg:P CPRESTORE_SLOT_REGNUM) - (match_operand:P 0 "cprestore_load_slot_operand"))] - "" - "" - [(set_attr "type" "ghost")]) - -;; Expand in-line code to clear the instruction cache between operand[0] and -;; operand[1]. -(define_expand "clear_cache" - [(match_operand 0 "pmode_register_operand") - (match_operand 1 "pmode_register_operand")] - "" - " -{ - if (TARGET_SYNCI) - { - mips_expand_synci_loop (operands[0], operands[1]); - emit_insn (gen_sync ()); - emit_insn (PMODE_INSN (gen_clear_hazard, ())); - } - else if (mips_cache_flush_func && mips_cache_flush_func[0]) - { - rtx len = gen_reg_rtx (Pmode); - emit_insn (gen_sub3_insn (len, operands[1], operands[0])); - MIPS_ICACHE_SYNC (operands[0], len); - } - DONE; -}") - -(define_insn "sync" - [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] - "GENERATE_SYNC" - { return mips_output_sync (); }) - -(define_insn "synci" - [(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")] - UNSPEC_SYNCI)] - "TARGET_SYNCI" - "synci\t0(%0)") - -(define_insn "rdhwr_synci_step_<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec_volatile [(const_int 1)] - UNSPEC_RDHWR))] - "ISA_HAS_SYNCI" - "rdhwr\t%0,$1") - -(define_insn "clear_hazard_<mode>" - [(unspec_volatile [(const_int 0)] UNSPEC_CLEAR_HAZARD) - (clobber (reg:P RETURN_ADDR_REGNUM))] - "ISA_HAS_SYNCI" -{ - return "%(%<bal\t1f\n" - "\tnop\n" - "1:\t<d>addiu\t$31,$31,12\n" - "\tjr.hb\t$31\n" - "\tnop%>%)"; -} - [(set_attr "length" "20")]) - -;; Cache operations for R4000-style caches. -(define_insn "mips_cache" - [(set (mem:BLK (scratch)) - (unspec:BLK [(match_operand:SI 0 "const_int_operand") - (match_operand:QI 1 "address_operand" "p")] - UNSPEC_MIPS_CACHE))] - "ISA_HAS_CACHE" - "cache\t%X0,%a1") - -;; Similar, but with the operands hard-coded to an R10K cache barrier -;; operation. We keep the pattern distinct so that we can identify -;; cache operations inserted by -mr10k-cache-barrier=, and so that -;; the operation is never inserted into a delay slot. -(define_insn "r10k_cache_barrier" - [(set (mem:BLK (scratch)) - (unspec:BLK [(const_int 0)] UNSPEC_R10K_CACHE_BARRIER))] - "ISA_HAS_CACHE" - "cache\t0x14,0(%$)" - [(set_attr "can_delay" "no")]) - -;; Block moves, see mips.c for more details. -;; Argument 0 is the destination -;; Argument 1 is the source -;; Argument 2 is the length -;; Argument 3 is the alignment - -(define_expand "movmemsi" - [(parallel [(set (match_operand:BLK 0 "general_operand") - (match_operand:BLK 1 "general_operand")) - (use (match_operand:SI 2 "")) - (use (match_operand:SI 3 "const_int_operand"))])] - "!TARGET_MIPS16 && !TARGET_MEMCPY" -{ - if (mips_expand_block_move (operands[0], operands[1], operands[2])) - DONE; - else - FAIL; -}) - -;; -;; .................... -;; -;; SHIFTS -;; -;; .................... - -(define_expand "<optab><mode>3" - [(set (match_operand:GPR 0 "register_operand") - (any_shift:GPR (match_operand:GPR 1 "register_operand") - (match_operand:SI 2 "arith_operand")))] - "" -{ - /* On the mips16, a shift of more than 8 is a four byte instruction, - so, for a shift between 8 and 16, it is just as fast to do two - shifts of 8 or less. If there is a lot of shifting going on, we - may win in CSE. Otherwise combine will put the shifts back - together again. This can be called by mips_function_arg, so we must - be careful not to allocate a new register if we've reached the - reload pass. */ - if (TARGET_MIPS16 - && optimize - && CONST_INT_P (operands[2]) - && INTVAL (operands[2]) > 8 - && INTVAL (operands[2]) <= 16 - && !reload_in_progress - && !reload_completed) - { - rtx temp = gen_reg_rtx (<MODE>mode); - - emit_insn (gen_<optab><mode>3 (temp, operands[1], GEN_INT (8))); - emit_insn (gen_<optab><mode>3 (operands[0], temp, - GEN_INT (INTVAL (operands[2]) - 8))); - DONE; - } -}) - -(define_insn "*<optab><mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d") - (any_shift:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:SI 2 "arith_operand" "dI")))] - "!TARGET_MIPS16" -{ - if (CONST_INT_P (operands[2])) - operands[2] = GEN_INT (INTVAL (operands[2]) - & (GET_MODE_BITSIZE (<MODE>mode) - 1)); - - return "<d><insn>\t%0,%1,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "<MODE>")]) - -(define_insn "*<optab>si3_extend" - [(set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI - (any_shift:SI (match_operand:SI 1 "register_operand" "d") - (match_operand:SI 2 "arith_operand" "dI"))))] - "TARGET_64BIT && !TARGET_MIPS16" -{ - if (CONST_INT_P (operands[2])) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - - return "<insn>\t%0,%1,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "SI")]) - -(define_insn "*<optab>si3_mips16" - [(set (match_operand:SI 0 "register_operand" "=d,d") - (any_shift:SI (match_operand:SI 1 "register_operand" "0,d") - (match_operand:SI 2 "arith_operand" "d,I")))] - "TARGET_MIPS16" -{ - if (which_alternative == 0) - return "<insn>\t%0,%2"; - - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - return "<insn>\t%0,%1,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "SI") - (set_attr_alternative "length" - [(const_int 4) - (if_then_else (match_operand 2 "m16_uimm3_b") - (const_int 4) - (const_int 8))])]) - -;; We need separate DImode MIPS16 patterns because of the irregularity -;; of right shifts. -(define_insn "*ashldi3_mips16" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ashift:DI (match_operand:DI 1 "register_operand" "0,d") - (match_operand:SI 2 "arith_operand" "d,I")))] - "TARGET_64BIT && TARGET_MIPS16" -{ - if (which_alternative == 0) - return "dsll\t%0,%2"; - - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); - return "dsll\t%0,%1,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "DI") - (set_attr_alternative "length" - [(const_int 4) - (if_then_else (match_operand 2 "m16_uimm3_b") - (const_int 4) - (const_int 8))])]) - -(define_insn "*ashrdi3_mips16" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "arith_operand" "d,I")))] - "TARGET_64BIT && TARGET_MIPS16" -{ - if (CONST_INT_P (operands[2])) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); - - return "dsra\t%0,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "DI") - (set_attr_alternative "length" - [(const_int 4) - (if_then_else (match_operand 2 "m16_uimm3_b") - (const_int 4) - (const_int 8))])]) - -(define_insn "*lshrdi3_mips16" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "0,0") - (match_operand:SI 2 "arith_operand" "d,I")))] - "TARGET_64BIT && TARGET_MIPS16" -{ - if (CONST_INT_P (operands[2])) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); - - return "dsrl\t%0,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "DI") - (set_attr_alternative "length" - [(const_int 4) - (if_then_else (match_operand 2 "m16_uimm3_b") - (const_int 4) - (const_int 8))])]) - -;; On the mips16, we can split a 4 byte shift into 2 2 byte shifts. - -(define_split - [(set (match_operand:GPR 0 "d_operand") - (any_shift:GPR (match_operand:GPR 1 "d_operand") - (match_operand:GPR 2 "const_int_operand")))] - "TARGET_MIPS16 && reload_completed && !TARGET_DEBUG_D_MODE - && INTVAL (operands[2]) > 8 - && INTVAL (operands[2]) <= 16" - [(set (match_dup 0) (any_shift:GPR (match_dup 1) (const_int 8))) - (set (match_dup 0) (any_shift:GPR (match_dup 0) (match_dup 2)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 8); }) - -;; If we load a byte on the mips16 as a bitfield, the resulting -;; sequence of instructions is too complicated for combine, because it -;; involves four instructions: a load, a shift, a constant load into a -;; register, and an and (the key problem here is that the mips16 does -;; not have and immediate). We recognize a shift of a load in order -;; to make it simple enough for combine to understand. -;; -;; The length here is the worst case: the length of the split version -;; will be more accurate. -(define_insn_and_split "" - [(set (match_operand:SI 0 "register_operand" "=d") - (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") - (match_operand:SI 2 "immediate_operand" "I")))] - "TARGET_MIPS16" - "#" - "" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))] - "" - [(set_attr "type" "load") - (set_attr "mode" "SI") - (set_attr "length" "16")]) - -(define_insn "rotr<mode>3" - [(set (match_operand:GPR 0 "register_operand" "=d") - (rotatert:GPR (match_operand:GPR 1 "register_operand" "d") - (match_operand:SI 2 "arith_operand" "dI")))] - "ISA_HAS_ROR" -{ - if (CONST_INT_P (operands[2])) - gcc_assert (INTVAL (operands[2]) >= 0 - && INTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)); - - return "<d>ror\t%0,%1,%2"; -} - [(set_attr "type" "shift") - (set_attr "mode" "<MODE>")]) - -;; -;; .................... -;; -;; CONDITIONAL BRANCHES -;; -;; .................... - -;; Conditional branches on floating-point equality tests. - -(define_insn "*branch_fp" - [(set (pc) - (if_then_else - (match_operator 1 "equality_operator" - [(match_operand:CC 2 "register_operand" "z") - (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_HARD_FLOAT" -{ - return mips_output_conditional_branch (insn, operands, - MIPS_BRANCH ("b%F1", "%Z2%0"), - MIPS_BRANCH ("b%W1", "%Z2%0")); -} - [(set_attr "type" "branch")]) - -(define_insn "*branch_fp_inverted" - [(set (pc) - (if_then_else - (match_operator 1 "equality_operator" - [(match_operand:CC 2 "register_operand" "z") - (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_HARD_FLOAT" -{ - return mips_output_conditional_branch (insn, operands, - MIPS_BRANCH ("b%W1", "%Z2%0"), - MIPS_BRANCH ("b%F1", "%Z2%0")); -} - [(set_attr "type" "branch")]) - -;; Conditional branches on ordered comparisons with zero. - -(define_insn "*branch_order<mode>" - [(set (pc) - (if_then_else - (match_operator 1 "order_operator" - [(match_operand:GPR 2 "register_operand" "d") - (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "!TARGET_MIPS16" - { return mips_output_order_conditional_branch (insn, operands, false); } - [(set_attr "type" "branch")]) - -(define_insn "*branch_order<mode>_inverted" - [(set (pc) - (if_then_else - (match_operator 1 "order_operator" - [(match_operand:GPR 2 "register_operand" "d") - (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "!TARGET_MIPS16" - { return mips_output_order_conditional_branch (insn, operands, true); } - [(set_attr "type" "branch")]) - -;; Conditional branch on equality comparison. - -(define_insn "*branch_equality<mode>" - [(set (pc) - (if_then_else - (match_operator 1 "equality_operator" - [(match_operand:GPR 2 "register_operand" "d") - (match_operand:GPR 3 "reg_or_0_operand" "dJ")]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "!TARGET_MIPS16" -{ - return mips_output_conditional_branch (insn, operands, - MIPS_BRANCH ("b%C1", "%2,%z3,%0"), - MIPS_BRANCH ("b%N1", "%2,%z3,%0")); -} - [(set_attr "type" "branch")]) - -(define_insn "*branch_equality<mode>_inverted" - [(set (pc) - (if_then_else - (match_operator 1 "equality_operator" - [(match_operand:GPR 2 "register_operand" "d") - (match_operand:GPR 3 "reg_or_0_operand" "dJ")]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "!TARGET_MIPS16" -{ - return mips_output_conditional_branch (insn, operands, - MIPS_BRANCH ("b%N1", "%2,%z3,%0"), - MIPS_BRANCH ("b%C1", "%2,%z3,%0")); -} - [(set_attr "type" "branch")]) - -;; MIPS16 branches - -(define_insn "*branch_equality<mode>_mips16" - [(set (pc) - (if_then_else - (match_operator 1 "equality_operator" - [(match_operand:GPR 2 "register_operand" "d,t") - (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "TARGET_MIPS16" - "@ - b%C1z\t%2,%0 - bt%C1z\t%0" - [(set_attr "type" "branch")]) - -(define_insn "*branch_equality<mode>_mips16_inverted" - [(set (pc) - (if_then_else - (match_operator 1 "equality_operator" - [(match_operand:GPR 2 "register_operand" "d,t") - (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "TARGET_MIPS16" - "@ - b%N1z\t%2,%0 - bt%N1z\t%0" - [(set_attr "type" "branch")]) - -(define_expand "cbranch<mode>4" - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "nonmemory_operand")]) - (label_ref (match_operand 3 "")) - (pc)))] - "" -{ - mips_expand_conditional_branch (operands); - DONE; -}) - -(define_expand "cbranch<mode>4" - [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(match_operand:SCALARF 1 "register_operand") - (match_operand:SCALARF 2 "register_operand")]) - (label_ref (match_operand 3 "")) - (pc)))] - "" -{ - mips_expand_conditional_branch (operands); - DONE; -}) - -;; Used to implement built-in functions. -(define_expand "condjump" - [(set (pc) - (if_then_else (match_operand 0) - (label_ref (match_operand 1)) - (pc)))]) - -;; Branch if bit is set/clear. - -(define_insn "*branch_bit<bbv><mode>" - [(set (pc) - (if_then_else - (equality_op (zero_extract:GPR - (match_operand:GPR 1 "register_operand" "d") - (const_int 1) - (match_operand 2 "const_int_operand" "")) - (const_int 0)) - (label_ref (match_operand 0 "")) - (pc)))] - "ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)" -{ - return - mips_output_conditional_branch (insn, operands, - MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"), - MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0")); -} - [(set_attr "type" "branch") - (set_attr "branch_likely" "no")]) - -(define_insn "*branch_bit<bbv><mode>_inverted" - [(set (pc) - (if_then_else - (equality_op (zero_extract:GPR - (match_operand:GPR 1 "register_operand" "d") - (const_int 1) - (match_operand 2 "const_int_operand" "")) - (const_int 0)) - (pc) - (label_ref (match_operand 0 ""))))] - "ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)" -{ - return - mips_output_conditional_branch (insn, operands, - MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"), - MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0")); -} - [(set_attr "type" "branch") - (set_attr "branch_likely" "no")]) - -;; -;; .................... -;; -;; SETTING A REGISTER FROM A COMPARISON -;; -;; .................... - -;; Destination is always set in SI mode. - -(define_expand "cstore<mode>4" - [(set (match_operand:SI 0 "register_operand") - (match_operator:SI 1 "mips_cstore_operator" - [(match_operand:GPR 2 "register_operand") - (match_operand:GPR 3 "nonmemory_operand")]))] - "" -{ - mips_expand_scc (operands); - DONE; -}) - -(define_insn "*seq_zero_<GPR:mode><GPR2:mode>" - [(set (match_operand:GPR2 0 "register_operand" "=d") - (eq:GPR2 (match_operand:GPR 1 "register_operand" "d") - (const_int 0)))] - "!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE" - "sltu\t%0,%1,1" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*seq_zero_<GPR:mode><GPR2:mode>_mips16" - [(set (match_operand:GPR2 0 "register_operand" "=t") - (eq:GPR2 (match_operand:GPR 1 "register_operand" "d") - (const_int 0)))] - "TARGET_MIPS16 && !ISA_HAS_SEQ_SNE" - "sltu\t%1,1" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -;; Generate sltiu unless using seq results in better code. -(define_insn "*seq_<GPR:mode><GPR2:mode>_seq" - [(set (match_operand:GPR2 0 "register_operand" "=d,d,d") - (eq:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d") - (match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))] - "ISA_HAS_SEQ_SNE" - "@ - seq\t%0,%1,%2 - sltiu\t%0,%1,1 - seqi\t%0,%1,%2" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*sne_zero_<GPR:mode><GPR2:mode>" - [(set (match_operand:GPR2 0 "register_operand" "=d") - (ne:GPR2 (match_operand:GPR 1 "register_operand" "d") - (const_int 0)))] - "!TARGET_MIPS16 && !ISA_HAS_SEQ_SNE" - "sltu\t%0,%.,%1" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -;; Generate sltu unless using sne results in better code. -(define_insn "*sne_<GPR:mode><GPR2:mode>_sne" - [(set (match_operand:GPR2 0 "register_operand" "=d,d,d") - (ne:GPR2 (match_operand:GPR 1 "register_operand" "%d,d,d") - (match_operand:GPR 2 "reg_imm10_operand" "d,J,YB")))] - "ISA_HAS_SEQ_SNE" - "@ - sne\t%0,%1,%2 - sltu\t%0,%.,%1 - snei\t%0,%1,%2" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*sgt<u>_<GPR:mode><GPR2:mode>" - [(set (match_operand:GPR2 0 "register_operand" "=d") - (any_gt:GPR2 (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "reg_or_0_operand" "dJ")))] - "!TARGET_MIPS16" - "slt<u>\t%0,%z2,%1" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*sgt<u>_<GPR:mode><GPR2:mode>_mips16" - [(set (match_operand:GPR2 0 "register_operand" "=t") - (any_gt:GPR2 (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "register_operand" "d")))] - "TARGET_MIPS16" - "slt<u>\t%2,%1" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*sge<u>_<GPR:mode><GPR2:mode>" - [(set (match_operand:GPR2 0 "register_operand" "=d") - (any_ge:GPR2 (match_operand:GPR 1 "register_operand" "d") - (const_int 1)))] - "!TARGET_MIPS16" - "slt<u>\t%0,%.,%1" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*slt<u>_<GPR:mode><GPR2:mode>" - [(set (match_operand:GPR2 0 "register_operand" "=d") - (any_lt:GPR2 (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "arith_operand" "dI")))] - "!TARGET_MIPS16" - "slt<u>\t%0,%1,%2" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*slt<u>_<GPR:mode><GPR2:mode>_mips16" - [(set (match_operand:GPR2 0 "register_operand" "=t,t") - (any_lt:GPR2 (match_operand:GPR 1 "register_operand" "d,d") - (match_operand:GPR 2 "arith_operand" "d,I")))] - "TARGET_MIPS16" - "slt<u>\t%1,%2" - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>") - (set_attr_alternative "length" - [(const_int 4) - (if_then_else (match_operand 2 "m16_uimm8_1") - (const_int 4) - (const_int 8))])]) - -(define_insn "*sle<u>_<GPR:mode><GPR2:mode>" - [(set (match_operand:GPR2 0 "register_operand" "=d") - (any_le:GPR2 (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "sle_operand" "")))] - "!TARGET_MIPS16" -{ - operands[2] = GEN_INT (INTVAL (operands[2]) + 1); - return "slt<u>\t%0,%1,%2"; -} - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*sle<u>_<GPR:mode><GPR2:mode>_mips16" - [(set (match_operand:GPR2 0 "register_operand" "=t") - (any_le:GPR2 (match_operand:GPR 1 "register_operand" "d") - (match_operand:GPR 2 "sle_operand" "")))] - "TARGET_MIPS16" -{ - operands[2] = GEN_INT (INTVAL (operands[2]) + 1); - return "slt<u>\t%1,%2"; -} - [(set_attr "type" "slt") - (set_attr "mode" "<GPR:MODE>") - (set (attr "length") (if_then_else (match_operand 2 "m16_uimm8_m1_1") - (const_int 4) - (const_int 8)))]) - -;; -;; .................... -;; -;; FLOATING POINT COMPARISONS -;; -;; .................... - -(define_insn "s<code>_<mode>" - [(set (match_operand:CC 0 "register_operand" "=z") - (fcond:CC (match_operand:SCALARF 1 "register_operand" "f") - (match_operand:SCALARF 2 "register_operand" "f")))] - "" - "c.<fcond>.<fmt>\t%Z0%1,%2" - [(set_attr "type" "fcmp") - (set_attr "mode" "FPSW")]) - -(define_insn "s<code>_<mode>" - [(set (match_operand:CC 0 "register_operand" "=z") - (swapped_fcond:CC (match_operand:SCALARF 1 "register_operand" "f") - (match_operand:SCALARF 2 "register_operand" "f")))] - "" - "c.<swapped_fcond>.<fmt>\t%Z0%2,%1" - [(set_attr "type" "fcmp") - (set_attr "mode" "FPSW")]) - -;; -;; .................... -;; -;; UNCONDITIONAL BRANCHES -;; -;; .................... - -;; Unconditional branches. - -(define_expand "jump" - [(set (pc) - (label_ref (match_operand 0)))]) - -(define_insn "*jump_absolute" - [(set (pc) - (label_ref (match_operand 0)))] - "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS" - { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); } - [(set_attr "type" "jump")]) - -(define_insn "*jump_pic" - [(set (pc) - (label_ref (match_operand 0)))] - "!TARGET_MIPS16 && !TARGET_ABSOLUTE_JUMPS" -{ - if (get_attr_length (insn) <= 8) - return "%*b\t%l0%/"; - else - { - mips_output_load_label (operands[0]); - return "%*jr\t%@%/%]"; - } -} - [(set_attr "type" "branch")]) - -;; We need a different insn for the mips16, because a mips16 branch -;; does not have a delay slot. - -(define_insn "*jump_mips16" - [(set (pc) - (label_ref (match_operand 0 "" "")))] - "TARGET_MIPS16" - "b\t%l0" - [(set_attr "type" "branch") - (set (attr "length") - ;; This calculation is like the normal branch one, but the - ;; range of the unextended instruction is [-0x800, 0x7fe] rather - ;; than [-0x100, 0xfe]. This translates to a range of: - ;; - ;; [-(0x800 - sizeof (branch)), 0x7fe] - ;; == [-0x7fe, 0x7fe] - ;; - ;; from the shorten_branches reference address. Long-branch - ;; sequences will replace this one, so the minimum length - ;; is one instruction shorter than for conditional branches. - (cond [(and (le (minus (match_dup 0) (pc)) (const_int 2046)) - (le (minus (pc) (match_dup 0)) (const_int 2046))) - (const_int 4) - (and (le (minus (match_dup 0) (pc)) (const_int 65534)) - (le (minus (pc) (match_dup 0)) (const_int 65532))) - (const_int 8) - (and (match_test "TARGET_ABICALLS") - (not (match_test "TARGET_ABSOLUTE_ABICALLS"))) - (const_int 36) - (match_test "Pmode == SImode") - (const_int 28) - ] (const_int 44)))]) - -(define_expand "indirect_jump" - [(set (pc) (match_operand 0 "register_operand"))] - "" -{ - operands[0] = force_reg (Pmode, operands[0]); - emit_jump_insn (PMODE_INSN (gen_indirect_jump, (operands[0]))); - DONE; -}) - -(define_insn "indirect_jump_<mode>" - [(set (pc) (match_operand:P 0 "register_operand" "d"))] - "" - "%*j\t%0%/" - [(set_attr "type" "jump") - (set_attr "mode" "none")]) - -;; A combined jump-and-move instruction, used for MIPS16 long-branch -;; sequences. Having a dedicated pattern is more convenient than -;; creating a SEQUENCE for this special case. -(define_insn "indirect_jump_and_restore_<mode>" - [(set (pc) (match_operand:P 1 "register_operand" "d")) - (set (match_operand:P 0 "register_operand" "=d") - (match_operand:P 2 "register_operand" "y"))] - "" - "%(%<jr\t%1\;move\t%0,%2%>%)" - [(set_attr "type" "multi") - (set_attr "extended_mips16" "yes")]) - -(define_expand "tablejump" - [(set (pc) - (match_operand 0 "register_operand")) - (use (label_ref (match_operand 1 "")))] - "!TARGET_MIPS16_SHORT_JUMP_TABLES" -{ - if (TARGET_GPWORD) - operands[0] = expand_binop (Pmode, add_optab, operands[0], - pic_offset_table_rtx, 0, 0, OPTAB_WIDEN); - else if (TARGET_RTP_PIC) - { - /* When generating RTP PIC, we use case table entries that are relative - to the start of the function. Add the function's address to the - value we loaded. */ - rtx start = get_hard_reg_initial_val (Pmode, PIC_FUNCTION_ADDR_REGNUM); - operands[0] = expand_binop (ptr_mode, add_optab, operands[0], - start, 0, 0, OPTAB_WIDEN); - } - - emit_jump_insn (PMODE_INSN (gen_tablejump, (operands[0], operands[1]))); - DONE; -}) - -(define_insn "tablejump_<mode>" - [(set (pc) - (match_operand:P 0 "register_operand" "d")) - (use (label_ref (match_operand 1 "" "")))] - "" - "%*j\t%0%/" - [(set_attr "type" "jump") - (set_attr "mode" "none")]) - -;; For MIPS16, we don't know whether a given jump table will use short or -;; word-sized offsets until late in compilation, when we are able to determine -;; the sizes of the insns which comprise the containing function. This -;; necessitates the use of the casesi rather than the tablejump pattern, since -;; the latter tries to calculate the index of the offset to jump through early -;; in compilation, i.e. at expand time, when nothing is known about the -;; eventual function layout. - -(define_expand "casesi" - [(match_operand:SI 0 "register_operand" "") ; index to jump on - (match_operand:SI 1 "const_int_operand" "") ; lower bound - (match_operand:SI 2 "const_int_operand" "") ; total range - (match_operand 3 "" "") ; table label - (match_operand 4 "" "")] ; out of range label - "TARGET_MIPS16_SHORT_JUMP_TABLES" -{ - if (operands[1] != const0_rtx) - { - rtx reg = gen_reg_rtx (SImode); - rtx offset = gen_int_mode (-INTVAL (operands[1]), SImode); - - if (!arith_operand (offset, SImode)) - offset = force_reg (SImode, offset); - - emit_insn (gen_addsi3 (reg, operands[0], offset)); - operands[0] = reg; - } - - if (!arith_operand (operands[0], SImode)) - operands[0] = force_reg (SImode, operands[0]); - - operands[2] = GEN_INT (INTVAL (operands[2]) + 1); - - emit_jump_insn (PMODE_INSN (gen_casesi_internal_mips16, - (operands[0], operands[2], - operands[3], operands[4]))); - - DONE; -}) - -(define_insn "casesi_internal_mips16_<mode>" - [(set (pc) - (if_then_else - (leu (match_operand:SI 0 "register_operand" "d") - (match_operand:SI 1 "arith_operand" "dI")) - (unspec:P - [(match_dup 0) - (label_ref (match_operand 2 "" ""))] - UNSPEC_CASESI_DISPATCH) - (label_ref (match_operand 3 "" "")))) - (clobber (match_scratch:P 4 "=d")) - (clobber (match_scratch:P 5 "=d")) - (clobber (reg:SI MIPS16_T_REGNUM))] - "TARGET_MIPS16_SHORT_JUMP_TABLES" -{ - rtx diff_vec = PATTERN (next_real_insn (operands[2])); - - gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); - - output_asm_insn ("sltu\t%0, %1", operands); - output_asm_insn ("bteqz\t%3", operands); - - switch (GET_MODE (diff_vec)) - { - case HImode: - output_asm_insn ("sll\t%5, %0, 1", operands); - output_asm_insn ("la\t%4, %2", operands); - output_asm_insn ("<d>addu\t%5, %4, %5", operands); - output_asm_insn ("lh\t%5, 0(%5)", operands); - break; - - case SImode: - output_asm_insn ("sll\t%5, %0, 2", operands); - output_asm_insn ("la\t%4, %2", operands); - output_asm_insn ("<d>addu\t%5, %4, %5", operands); - output_asm_insn ("lw\t%5, 0(%5)", operands); - break; - - default: - gcc_unreachable (); - } - - output_asm_insn ("addu\t%4, %4, %5", operands); - - return "j\t%4"; -} - [(set_attr "length" "32")]) - -;; For TARGET_USE_GOT, we save the gp in the jmp_buf as well. -;; While it is possible to either pull it off the stack (in the -;; o32 case) or recalculate it given t9 and our target label, -;; it takes 3 or 4 insns to do so. - -(define_expand "builtin_setjmp_setup" - [(use (match_operand 0 "register_operand"))] - "TARGET_USE_GOT" -{ - rtx addr; - - addr = plus_constant (Pmode, operands[0], GET_MODE_SIZE (Pmode) * 3); - mips_emit_move (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx); - DONE; -}) - -;; Restore the gp that we saved above. Despite the earlier comment, it seems -;; that older code did recalculate the gp from $25. Continue to jump through -;; $25 for compatibility (we lose nothing by doing so). - -(define_expand "builtin_longjmp" - [(use (match_operand 0 "register_operand"))] - "TARGET_USE_GOT" -{ - /* The elements of the buffer are, in order: */ - int W = GET_MODE_SIZE (Pmode); - rtx fp = gen_rtx_MEM (Pmode, operands[0]); - rtx lab = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0], 1*W)); - rtx stack = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0], 2*W)); - rtx gpv = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0], 3*W)); - rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM); - /* Use gen_raw_REG to avoid being given pic_offset_table_rtx. - The target is bound to be using $28 as the global pointer - but the current function might not be. */ - rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM); - - /* This bit is similar to expand_builtin_longjmp except that it - restores $gp as well. */ - mips_emit_move (hard_frame_pointer_rtx, fp); - mips_emit_move (pv, lab); - emit_stack_restore (SAVE_NONLOCAL, stack); - mips_emit_move (gp, gpv); - emit_use (hard_frame_pointer_rtx); - emit_use (stack_pointer_rtx); - emit_use (gp); - emit_indirect_jump (pv); - DONE; -}) - -;; -;; .................... -;; -;; Function prologue/epilogue -;; -;; .................... -;; - -(define_expand "prologue" - [(const_int 1)] - "" -{ - mips_expand_prologue (); - DONE; -}) - -;; Block any insns from being moved before this point, since the -;; profiling call to mcount can use various registers that aren't -;; saved or used to pass arguments. - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] - "" - "" - [(set_attr "type" "ghost") - (set_attr "mode" "none")]) - -(define_insn "probe_stack_range_<P:mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec_volatile:P [(match_operand:P 1 "register_operand" "0") - (match_operand:P 2 "register_operand" "d")] - UNSPEC_PROBE_STACK_RANGE))] - "" - { return mips_output_probe_stack_range (operands[0], operands[2]); } - [(set_attr "type" "unknown") - (set_attr "can_delay" "no") - (set_attr "mode" "<MODE>")]) - -(define_expand "epilogue" - [(const_int 2)] - "" -{ - mips_expand_epilogue (false); - DONE; -}) - -(define_expand "sibcall_epilogue" - [(const_int 2)] - "" -{ - mips_expand_epilogue (true); - DONE; -}) - -;; Trivial return. Make it look like a normal return insn as that -;; allows jump optimizations to work better. - -(define_expand "return" - [(simple_return)] - "mips_can_use_return_insn ()" - { mips_expand_before_return (); }) - -(define_expand "simple_return" - [(simple_return)] - "" - { mips_expand_before_return (); }) - -(define_insn "*<optab>" - [(any_return)] - "" - "%*j\t$31%/" - [(set_attr "type" "jump") - (set_attr "mode" "none")]) - -;; Normal return. - -(define_insn "<optab>_internal" - [(any_return) - (use (match_operand 0 "pmode_register_operand" ""))] - "" - "%*j\t%0%/" - [(set_attr "type" "jump") - (set_attr "mode" "none")]) - -;; Exception return. -(define_insn "mips_eret" - [(return) - (unspec_volatile [(const_int 0)] UNSPEC_ERET)] - "" - "eret" - [(set_attr "type" "trap") - (set_attr "mode" "none")]) - -;; Debug exception return. -(define_insn "mips_deret" - [(return) - (unspec_volatile [(const_int 0)] UNSPEC_DERET)] - "" - "deret" - [(set_attr "type" "trap") - (set_attr "mode" "none")]) - -;; Disable interrupts. -(define_insn "mips_di" - [(unspec_volatile [(const_int 0)] UNSPEC_DI)] - "" - "di" - [(set_attr "type" "trap") - (set_attr "mode" "none")]) - -;; Execution hazard barrier. -(define_insn "mips_ehb" - [(unspec_volatile [(const_int 0)] UNSPEC_EHB)] - "" - "ehb" - [(set_attr "type" "trap") - (set_attr "mode" "none")]) - -;; Read GPR from previous shadow register set. -(define_insn "mips_rdpgpr" - [(set (match_operand:SI 0 "register_operand" "=d") - (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d")] - UNSPEC_RDPGPR))] - "" - "rdpgpr\t%0,%1" - [(set_attr "type" "move") - (set_attr "mode" "SI")]) - -;; Move involving COP0 registers. -(define_insn "cop0_move" - [(set (match_operand:SI 0 "register_operand" "=B,d") - (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d,B")] - UNSPEC_COP0))] - "" -{ return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "mtc,mfc") - (set_attr "mode" "SI")]) - -;; This is used in compiling the unwind routines. -(define_expand "eh_return" - [(use (match_operand 0 "general_operand"))] - "" -{ - if (GET_MODE (operands[0]) != word_mode) - operands[0] = convert_to_mode (word_mode, operands[0], 0); - if (TARGET_64BIT) - emit_insn (gen_eh_set_lr_di (operands[0])); - else - emit_insn (gen_eh_set_lr_si (operands[0])); - DONE; -}) - -;; Clobber the return address on the stack. We can't expand this -;; until we know where it will be put in the stack frame. - -(define_insn "eh_set_lr_si" - [(unspec [(match_operand:SI 0 "register_operand" "d")] UNSPEC_EH_RETURN) - (clobber (match_scratch:SI 1 "=&d"))] - "! TARGET_64BIT" - "#") - -(define_insn "eh_set_lr_di" - [(unspec [(match_operand:DI 0 "register_operand" "d")] UNSPEC_EH_RETURN) - (clobber (match_scratch:DI 1 "=&d"))] - "TARGET_64BIT" - "#") - -(define_split - [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN) - (clobber (match_scratch 1))] - "reload_completed" - [(const_int 0)] -{ - mips_set_return_address (operands[0], operands[1]); - DONE; -}) - -(define_expand "exception_receiver" - [(const_int 0)] - "TARGET_USE_GOT" -{ - /* See the comment above load_call<mode> for details. */ - emit_insn (gen_set_got_version ()); - - /* If we have a call-clobbered $gp, restore it from its save slot. */ - if (HAVE_restore_gp_si) - emit_insn (gen_restore_gp_si ()); - else if (HAVE_restore_gp_di) - emit_insn (gen_restore_gp_di ()); - DONE; -}) - -(define_expand "nonlocal_goto_receiver" - [(const_int 0)] - "TARGET_USE_GOT" -{ - /* See the comment above load_call<mode> for details. */ - emit_insn (gen_set_got_version ()); - DONE; -}) - -;; Restore $gp from its .cprestore stack slot. The instruction remains -;; volatile until all uses of $28 are exposed. -(define_insn_and_split "restore_gp_<mode>" - [(set (reg:P 28) - (unspec_volatile:P [(const_int 0)] UNSPEC_RESTORE_GP)) - (clobber (match_scratch:P 0 "=&d"))] - "TARGET_CALL_CLOBBERED_GP" - "#" - "&& epilogue_completed" - [(const_int 0)] -{ - mips_restore_gp_from_cprestore_slot (operands[0]); - DONE; -} - [(set_attr "type" "ghost")]) - -;; Move between $gp and its register save slot. -(define_insn_and_split "move_gp<mode>" - [(set (match_operand:GPR 0 "nonimmediate_operand" "=d,m") - (unspec:GPR [(match_operand:GPR 1 "move_operand" "m,d")] - UNSPEC_MOVE_GP))] - "" - { return mips_must_initialize_gp_p () ? "#" : ""; } - "mips_must_initialize_gp_p ()" - [(const_int 0)] -{ - mips_emit_move (operands[0], operands[1]); - DONE; -} - [(set_attr "type" "ghost")]) - -;; -;; .................... -;; -;; FUNCTION CALLS -;; -;; .................... - -;; Instructions to load a call address from the GOT. The address might -;; point to a function or to a lazy binding stub. In the latter case, -;; the stub will use the dynamic linker to resolve the function, which -;; in turn will change the GOT entry to point to the function's real -;; address. -;; -;; This means that every call, even pure and constant ones, can -;; potentially modify the GOT entry. And once a stub has been called, -;; we must not call it again. -;; -;; We represent this restriction using an imaginary, fixed, call-saved -;; register called GOT_VERSION_REGNUM. The idea is to make the register -;; live throughout the function and to change its value after every -;; potential call site. This stops any rtx value that uses the register -;; from being computed before an earlier call. To do this, we: -;; -;; - Ensure that the register is live on entry to the function, -;; so that it is never thought to be used uninitalized. -;; -;; - Ensure that the register is live on exit from the function, -;; so that it is live throughout. -;; -;; - Make each call (lazily-bound or not) use the current value -;; of GOT_VERSION_REGNUM, so that updates of the register are -;; not moved across call boundaries. -;; -;; - Add "ghost" definitions of the register to the beginning of -;; blocks reached by EH and ABNORMAL_CALL edges, because those -;; edges may involve calls that normal paths don't. (E.g. the -;; unwinding code that handles a non-call exception may change -;; lazily-bound GOT entries.) We do this by making the -;; exception_receiver and nonlocal_goto_receiver expanders emit -;; a set_got_version instruction. -;; -;; - After each call (lazily-bound or not), use a "ghost" -;; update_got_version instruction to change the register's value. -;; This instruction mimics the _possible_ effect of the dynamic -;; resolver during the call and it remains live even if the call -;; itself becomes dead. -;; -;; - Leave GOT_VERSION_REGNUM out of all register classes. -;; The register is therefore not a valid register_operand -;; and cannot be moved to or from other registers. - -(define_insn "load_call<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec:P [(match_operand:P 1 "register_operand" "d") - (match_operand:P 2 "immediate_operand" "") - (reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL))] - "TARGET_USE_GOT" - "<load>\t%0,%R2(%1)" - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) - -(define_insn "set_got_version" - [(set (reg:SI GOT_VERSION_REGNUM) - (unspec_volatile:SI [(const_int 0)] UNSPEC_SET_GOT_VERSION))] - "TARGET_USE_GOT" - "" - [(set_attr "type" "ghost")]) - -(define_insn "update_got_version" - [(set (reg:SI GOT_VERSION_REGNUM) - (unspec:SI [(reg:SI GOT_VERSION_REGNUM)] UNSPEC_UPDATE_GOT_VERSION))] - "TARGET_USE_GOT" - "" - [(set_attr "type" "ghost")]) - -;; Sibling calls. All these patterns use jump instructions. - -;; If TARGET_SIBCALLS, call_insn_operand will only accept constant -;; addresses if a direct jump is acceptable. Since the 'S' constraint -;; is defined in terms of call_insn_operand, the same is true of the -;; constraints. - -;; When we use an indirect jump, we need a register that will be -;; preserved by the epilogue. Since TARGET_USE_PIC_FN_ADDR_REG forces -;; us to use $25 for this purpose -- and $25 is never clobbered by the -;; epilogue -- we might as well use it for !TARGET_USE_PIC_FN_ADDR_REG -;; as well. - -(define_expand "sibcall" - [(parallel [(call (match_operand 0 "") - (match_operand 1 "")) - (use (match_operand 2 "")) ;; next_arg_reg - (use (match_operand 3 ""))])] ;; struct_value_size_rtx - "TARGET_SIBCALLS" -{ - mips_expand_call (MIPS_CALL_SIBCALL, NULL_RTX, XEXP (operands[0], 0), - operands[1], operands[2], false); - DONE; -}) - -(define_insn "sibcall_internal" - [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S")) - (match_operand 1 "" ""))] - "TARGET_SIBCALLS && SIBLING_CALL_P (insn)" - { return MIPS_CALL ("j", operands, 0, 1); } - [(set_attr "jal" "indirect,direct") - (set_attr "jal_macro" "no")]) - -(define_expand "sibcall_value" - [(parallel [(set (match_operand 0 "") - (call (match_operand 1 "") - (match_operand 2 ""))) - (use (match_operand 3 ""))])] ;; next_arg_reg - "TARGET_SIBCALLS" -{ - mips_expand_call (MIPS_CALL_SIBCALL, operands[0], XEXP (operands[1], 0), - operands[2], operands[3], false); - DONE; -}) - -(define_insn "sibcall_value_internal" - [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "call_insn_operand" "j,S")) - (match_operand 2 "" "")))] - "TARGET_SIBCALLS && SIBLING_CALL_P (insn)" - { return MIPS_CALL ("j", operands, 1, 2); } - [(set_attr "jal" "indirect,direct") - (set_attr "jal_macro" "no")]) - -(define_insn "sibcall_value_multiple_internal" - [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "call_insn_operand" "j,S")) - (match_operand 2 "" ""))) - (set (match_operand 3 "register_operand" "") - (call (mem:SI (match_dup 1)) - (match_dup 2)))] - "TARGET_SIBCALLS && SIBLING_CALL_P (insn)" - { return MIPS_CALL ("j", operands, 1, 2); } - [(set_attr "jal" "indirect,direct") - (set_attr "jal_macro" "no")]) - -(define_expand "call" - [(parallel [(call (match_operand 0 "") - (match_operand 1 "")) - (use (match_operand 2 "")) ;; next_arg_reg - (use (match_operand 3 ""))])] ;; struct_value_size_rtx - "" -{ - mips_expand_call (MIPS_CALL_NORMAL, NULL_RTX, XEXP (operands[0], 0), - operands[1], operands[2], false); - DONE; -}) - -;; This instruction directly corresponds to an assembly-language "jal". -;; There are four cases: -;; -;; - -mno-abicalls: -;; Both symbolic and register destinations are OK. The pattern -;; always expands to a single mips instruction. -;; -;; - -mabicalls/-mno-explicit-relocs: -;; Again, both symbolic and register destinations are OK. -;; The call is treated as a multi-instruction black box. -;; -;; - -mabicalls/-mexplicit-relocs with n32 or n64: -;; Only "jal $25" is allowed. This expands to a single "jalr $25" -;; instruction. -;; -;; - -mabicalls/-mexplicit-relocs with o32 or o64: -;; Only "jal $25" is allowed. The call is actually two instructions: -;; "jalr $25" followed by an insn to reload $gp. -;; -;; In the last case, we can generate the individual instructions with -;; a define_split. There are several things to be wary of: -;; -;; - We can't expose the load of $gp before reload. If we did, -;; it might get removed as dead, but reload can introduce new -;; uses of $gp by rematerializing constants. -;; -;; - We shouldn't restore $gp after calls that never return. -;; It isn't valid to insert instructions between a noreturn -;; call and the following barrier. -;; -;; - The splitter deliberately changes the liveness of $gp. The unsplit -;; instruction preserves $gp and so have no effect on its liveness. -;; But once we generate the separate insns, it becomes obvious that -;; $gp is not live on entry to the call. -;; -(define_insn_and_split "call_internal" - [(call (mem:SI (match_operand 0 "call_insn_operand" "c,S")) - (match_operand 1 "" "")) - (clobber (reg:SI RETURN_ADDR_REGNUM))] - "" - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, 1); } - "reload_completed && TARGET_SPLIT_CALLS" - [(const_int 0)] -{ - mips_split_call (curr_insn, gen_call_split (operands[0], operands[1])); - DONE; -} - [(set_attr "jal" "indirect,direct")]) - -(define_insn "call_split" - [(call (mem:SI (match_operand 0 "call_insn_operand" "c,S")) - (match_operand 1 "" "")) - (clobber (reg:SI RETURN_ADDR_REGNUM)) - (clobber (reg:SI 28))] - "TARGET_SPLIT_CALLS" - { return MIPS_CALL ("jal", operands, 0, 1); } - [(set_attr "jal" "indirect,direct") - (set_attr "jal_macro" "no")]) - -;; A pattern for calls that must be made directly. It is used for -;; MIPS16 calls that the linker may need to redirect to a hard-float -;; stub; the linker relies on the call relocation type to detect when -;; such redirection is needed. -(define_insn_and_split "call_internal_direct" - [(call (mem:SI (match_operand 0 "const_call_insn_operand")) - (match_operand 1)) - (const_int 1) - (clobber (reg:SI RETURN_ADDR_REGNUM))] - "" - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, -1); } - "reload_completed && TARGET_SPLIT_CALLS" - [(const_int 0)] -{ - mips_split_call (curr_insn, - gen_call_direct_split (operands[0], operands[1])); - DONE; -} - [(set_attr "jal" "direct")]) - -(define_insn "call_direct_split" - [(call (mem:SI (match_operand 0 "const_call_insn_operand")) - (match_operand 1)) - (const_int 1) - (clobber (reg:SI RETURN_ADDR_REGNUM)) - (clobber (reg:SI 28))] - "TARGET_SPLIT_CALLS" - { return MIPS_CALL ("jal", operands, 0, -1); } - [(set_attr "jal" "direct") - (set_attr "jal_macro" "no")]) - -(define_expand "call_value" - [(parallel [(set (match_operand 0 "") - (call (match_operand 1 "") - (match_operand 2 ""))) - (use (match_operand 3 ""))])] ;; next_arg_reg - "" -{ - mips_expand_call (MIPS_CALL_NORMAL, operands[0], XEXP (operands[1], 0), - operands[2], operands[3], false); - DONE; -}) - -;; See comment for call_internal. -(define_insn_and_split "call_value_internal" - [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "call_insn_operand" "c,S")) - (match_operand 2 "" ""))) - (clobber (reg:SI RETURN_ADDR_REGNUM))] - "" - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); } - "reload_completed && TARGET_SPLIT_CALLS" - [(const_int 0)] -{ - mips_split_call (curr_insn, - gen_call_value_split (operands[0], operands[1], - operands[2])); - DONE; -} - [(set_attr "jal" "indirect,direct")]) - -(define_insn "call_value_split" - [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "call_insn_operand" "c,S")) - (match_operand 2 "" ""))) - (clobber (reg:SI RETURN_ADDR_REGNUM)) - (clobber (reg:SI 28))] - "TARGET_SPLIT_CALLS" - { return MIPS_CALL ("jal", operands, 1, 2); } - [(set_attr "jal" "indirect,direct") - (set_attr "jal_macro" "no")]) - -;; See call_internal_direct. -(define_insn_and_split "call_value_internal_direct" - [(set (match_operand 0 "register_operand") - (call (mem:SI (match_operand 1 "const_call_insn_operand")) - (match_operand 2))) - (const_int 1) - (clobber (reg:SI RETURN_ADDR_REGNUM))] - "" - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, -1); } - "reload_completed && TARGET_SPLIT_CALLS" - [(const_int 0)] -{ - mips_split_call (curr_insn, - gen_call_value_direct_split (operands[0], operands[1], - operands[2])); - DONE; -} - [(set_attr "jal" "direct")]) - -(define_insn "call_value_direct_split" - [(set (match_operand 0 "register_operand") - (call (mem:SI (match_operand 1 "const_call_insn_operand")) - (match_operand 2))) - (const_int 1) - (clobber (reg:SI RETURN_ADDR_REGNUM)) - (clobber (reg:SI 28))] - "TARGET_SPLIT_CALLS" - { return MIPS_CALL ("jal", operands, 1, -1); } - [(set_attr "jal" "direct") - (set_attr "jal_macro" "no")]) - -;; See comment for call_internal. -(define_insn_and_split "call_value_multiple_internal" - [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "call_insn_operand" "c,S")) - (match_operand 2 "" ""))) - (set (match_operand 3 "register_operand" "") - (call (mem:SI (match_dup 1)) - (match_dup 2))) - (clobber (reg:SI RETURN_ADDR_REGNUM))] - "" - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); } - "reload_completed && TARGET_SPLIT_CALLS" - [(const_int 0)] -{ - mips_split_call (curr_insn, - gen_call_value_multiple_split (operands[0], operands[1], - operands[2], operands[3])); - DONE; -} - [(set_attr "jal" "indirect,direct")]) - -(define_insn "call_value_multiple_split" - [(set (match_operand 0 "register_operand" "") - (call (mem:SI (match_operand 1 "call_insn_operand" "c,S")) - (match_operand 2 "" ""))) - (set (match_operand 3 "register_operand" "") - (call (mem:SI (match_dup 1)) - (match_dup 2))) - (clobber (reg:SI RETURN_ADDR_REGNUM)) - (clobber (reg:SI 28))] - "TARGET_SPLIT_CALLS" - { return MIPS_CALL ("jal", operands, 1, 2); } - [(set_attr "jal" "indirect,direct") - (set_attr "jal_macro" "no")]) - -;; Call subroutine returning any type. - -(define_expand "untyped_call" - [(parallel [(call (match_operand 0 "") - (const_int 0)) - (match_operand 1 "") - (match_operand 2 "")])] - "" -{ - int i; - - emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); - - for (i = 0; i < XVECLEN (operands[2], 0); i++) - { - rtx set = XVECEXP (operands[2], 0, i); - mips_emit_move (SET_DEST (set), SET_SRC (set)); - } - - emit_insn (gen_blockage ()); - DONE; -}) - -;; -;; .................... -;; -;; MISC. -;; -;; .................... -;; - - -(define_insn "prefetch" - [(prefetch (match_operand:QI 0 "address_operand" "p") - (match_operand 1 "const_int_operand" "n") - (match_operand 2 "const_int_operand" "n"))] - "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS" -{ - if (TARGET_LOONGSON_2EF || TARGET_LOONGSON_3A) - /* Loongson 2[ef] and Loongson 3a use load to $0 to perform prefetching. */ - return "ld\t$0,%a0"; - operands[1] = mips_prefetch_cookie (operands[1], operands[2]); - return "pref\t%1,%a0"; -} - [(set_attr "type" "prefetch")]) - -(define_insn "*prefetch_indexed_<mode>" - [(prefetch (plus:P (match_operand:P 0 "register_operand" "d") - (match_operand:P 1 "register_operand" "d")) - (match_operand 2 "const_int_operand" "n") - (match_operand 3 "const_int_operand" "n"))] - "ISA_HAS_PREFETCHX && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT" -{ - operands[2] = mips_prefetch_cookie (operands[2], operands[3]); - return "prefx\t%2,%1(%0)"; -} - [(set_attr "type" "prefetchx")]) - -(define_insn "nop" - [(const_int 0)] - "" - "%(nop%)" - [(set_attr "type" "nop") - (set_attr "mode" "none")]) - -;; Like nop, but commented out when outside a .set noreorder block. -(define_insn "hazard_nop" - [(const_int 1)] - "" - { - if (mips_noreorder.nesting_level > 0) - return "nop"; - else - return "#nop"; - } - [(set_attr "type" "nop")]) - -;; MIPS4 Conditional move instructions. - -(define_insn "*mov<GPR:mode>_on_<MOVECC:mode>" - [(set (match_operand:GPR 0 "register_operand" "=d,d") - (if_then_else:GPR - (match_operator:MOVECC 4 "equality_operator" - [(match_operand:MOVECC 1 "register_operand" "<MOVECC:reg>,<MOVECC:reg>") - (const_int 0)]) - (match_operand:GPR 2 "reg_or_0_operand" "dJ,0") - (match_operand:GPR 3 "reg_or_0_operand" "0,dJ")))] - "ISA_HAS_CONDMOVE" - "@ - mov%T4\t%0,%z2,%1 - mov%t4\t%0,%z3,%1" - [(set_attr "type" "condmove") - (set_attr "mode" "<GPR:MODE>")]) - -(define_insn "*mov<SCALARF:mode>_on_<MOVECC:mode>" - [(set (match_operand:SCALARF 0 "register_operand" "=f,f") - (if_then_else:SCALARF - (match_operator:MOVECC 4 "equality_operator" - [(match_operand:MOVECC 1 "register_operand" "<MOVECC:reg>,<MOVECC:reg>") - (const_int 0)]) - (match_operand:SCALARF 2 "register_operand" "f,0") - (match_operand:SCALARF 3 "register_operand" "0,f")))] - "ISA_HAS_FP_CONDMOVE" - "@ - mov%T4.<fmt>\t%0,%2,%1 - mov%t4.<fmt>\t%0,%3,%1" - [(set_attr "type" "condmove") - (set_attr "mode" "<SCALARF:MODE>")]) - -;; These are the main define_expand's used to make conditional moves. - -(define_expand "mov<mode>cc" - [(set (match_dup 4) (match_operand 1 "comparison_operator")) - (set (match_operand:GPR 0 "register_operand") - (if_then_else:GPR (match_dup 5) - (match_operand:GPR 2 "reg_or_0_operand") - (match_operand:GPR 3 "reg_or_0_operand")))] - "ISA_HAS_CONDMOVE" -{ - mips_expand_conditional_move (operands); - DONE; -}) - -(define_expand "mov<mode>cc" - [(set (match_dup 4) (match_operand 1 "comparison_operator")) - (set (match_operand:SCALARF 0 "register_operand") - (if_then_else:SCALARF (match_dup 5) - (match_operand:SCALARF 2 "register_operand") - (match_operand:SCALARF 3 "register_operand")))] - "ISA_HAS_FP_CONDMOVE" -{ - mips_expand_conditional_move (operands); - DONE; -}) - -;; -;; .................... -;; -;; mips16 inline constant tables -;; -;; .................... -;; - -(define_insn "consttable_tls_reloc" - [(unspec_volatile [(match_operand 0 "tls_reloc_operand" "") - (match_operand 1 "const_int_operand" "")] - UNSPEC_CONSTTABLE_INT)] - "TARGET_MIPS16_PCREL_LOADS" - { return mips_output_tls_reloc_directive (&operands[0]); } - [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))]) - -(define_insn "consttable_int" - [(unspec_volatile [(match_operand 0 "consttable_operand" "") - (match_operand 1 "const_int_operand" "")] - UNSPEC_CONSTTABLE_INT)] - "TARGET_MIPS16" -{ - assemble_integer (mips_strip_unspec_address (operands[0]), - INTVAL (operands[1]), - BITS_PER_UNIT * INTVAL (operands[1]), 1); - return ""; -} - [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))]) - -(define_insn "consttable_float" - [(unspec_volatile [(match_operand 0 "consttable_operand" "")] - UNSPEC_CONSTTABLE_FLOAT)] - "TARGET_MIPS16" -{ - REAL_VALUE_TYPE d; - - gcc_assert (GET_CODE (operands[0]) == CONST_DOUBLE); - REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]); - assemble_real (d, GET_MODE (operands[0]), - GET_MODE_BITSIZE (GET_MODE (operands[0]))); - return ""; -} - [(set (attr "length") - (symbol_ref "GET_MODE_SIZE (GET_MODE (operands[0]))"))]) - -(define_insn "align" - [(unspec_volatile [(match_operand 0 "const_int_operand" "")] UNSPEC_ALIGN)] - "" - ".align\t%0" - [(set (attr "length") (symbol_ref "(1 << INTVAL (operands[0])) - 1"))]) - -(define_split - [(match_operand 0 "small_data_pattern")] - "reload_completed" - [(match_dup 0)] - { operands[0] = mips_rewrite_small_data (operands[0]); }) - -;; -;; .................... -;; -;; MIPS16e Save/Restore -;; -;; .................... -;; - -(define_insn "*mips16e_save_restore" - [(match_parallel 0 "" - [(set (match_operand:SI 1 "register_operand") - (plus:SI (match_dup 1) - (match_operand:SI 2 "const_int_operand")))])] - "operands[1] == stack_pointer_rtx - && mips16e_save_restore_pattern_p (operands[0], INTVAL (operands[2]), NULL)" - { return mips16e_output_save_restore (operands[0], INTVAL (operands[2])); } - [(set_attr "type" "arith") - (set_attr "extended_mips16" "yes")]) - -;; Thread-Local Storage - -;; The TLS base pointer is accessed via "rdhwr $3, $29". No current -;; MIPS architecture defines this register, and no current -;; implementation provides it; instead, any OS which supports TLS is -;; expected to trap and emulate this instruction. rdhwr is part of the -;; MIPS 32r2 specification, but we use it on any architecture because -;; we expect it to be emulated. Use .set to force the assembler to -;; accept it. -;; -;; We do not use a constraint to force the destination to be $3 -;; because $3 can appear explicitly as a function return value. -;; If we leave the use of $3 implicit in the constraints until -;; reload, we may end up making a $3 return value live across -;; the instruction, leading to a spill failure when reloading it. -(define_insn_and_split "tls_get_tp_<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP)) - (clobber (reg:P TLS_GET_TP_REGNUM))] - "HAVE_AS_TLS && !TARGET_MIPS16" - "#" - "&& reload_completed" - [(set (reg:P TLS_GET_TP_REGNUM) - (unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP)) - (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM))] - "" - [(set_attr "type" "unknown") - ; Since rdhwr always generates a trap for now, putting it in a delay - ; slot would make the kernel's emulation of it much slower. - (set_attr "can_delay" "no") - (set_attr "mode" "<MODE>") - (set_attr "length" "8")]) - -(define_insn "*tls_get_tp_<mode>_split" - [(set (reg:P TLS_GET_TP_REGNUM) - (unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))] - "HAVE_AS_TLS && !TARGET_MIPS16" - ".set\tpush\;.set\tmips32r2\t\;rdhwr\t$3,$29\;.set\tpop" - [(set_attr "type" "unknown") - ; See tls_get_tp_<mode> - (set_attr "can_delay" "no") - (set_attr "mode" "<MODE>")]) - -;; In MIPS16 mode, the TLS base pointer is accessed by a -;; libgcc helper function __mips16_rdhwr(), as 'rdhwr' is not -;; accessible in MIPS16. -;; -;; This is not represented as a call insn, to avoid the -;; unnecesarry clobbering of caller-save registers by a -;; function consisting only of: "rdhwr $3,$29; j $31; nop;" -;; -;; A $25 clobber is added to cater for a $25 load stub added by the -;; linker to __mips16_rdhwr when the call is made from non-PIC code. - -(define_insn_and_split "tls_get_tp_mips16_<mode>" - [(set (match_operand:P 0 "register_operand" "=d") - (unspec:P [(match_operand:P 1 "call_insn_operand" "dS")] - UNSPEC_TLS_GET_TP)) - (clobber (reg:P TLS_GET_TP_REGNUM)) - (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM)) - (clobber (reg:P RETURN_ADDR_REGNUM))] - "HAVE_AS_TLS && TARGET_MIPS16" - "#" - "&& reload_completed" - [(parallel [(set (reg:P TLS_GET_TP_REGNUM) - (unspec:P [(match_dup 1)] UNSPEC_TLS_GET_TP)) - (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM)) - (clobber (reg:P RETURN_ADDR_REGNUM))]) - (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM))] - "" - [(set_attr "type" "multi") - (set_attr "length" "16") - (set_attr "mode" "<MODE>")]) - -(define_insn "*tls_get_tp_mips16_call_<mode>" - [(set (reg:P TLS_GET_TP_REGNUM) - (unspec:P [(match_operand:P 0 "call_insn_operand" "dS")] - UNSPEC_TLS_GET_TP)) - (clobber (reg:P PIC_FUNCTION_ADDR_REGNUM)) - (clobber (reg:P RETURN_ADDR_REGNUM))] - "HAVE_AS_TLS && TARGET_MIPS16" - { return MIPS_CALL ("jal", operands, 0, -1); } - [(set_attr "type" "call") - (set_attr "length" "12") - (set_attr "mode" "<MODE>")]) - -;; Named pattern for expanding thread pointer reference. -(define_expand "get_thread_pointer<mode>" - [(match_operand:P 0 "register_operand" "=d")] - "HAVE_AS_TLS" -{ - mips_expand_thread_pointer (operands[0]); - DONE; -}) - - -;; Synchronization instructions. - -(include "sync.md") - -; The MIPS Paired-Single Floating Point and MIPS-3D Instructions. - -(include "mips-ps-3d.md") - -; The MIPS DSP Instructions. - -(include "mips-dsp.md") - -; The MIPS DSP REV 2 Instructions. - -(include "mips-dspr2.md") - -; MIPS fixed-point instructions. -(include "mips-fixed.md") - -; ST-Microelectronics Loongson-2E/2F-specific patterns. -(include "loongson.md") - -(define_c_enum "unspec" [ - UNSPEC_ADDRESS_FIRST -]) |