| Index: gcc/gcc/config/mips/mips.md
|
| diff --git a/gcc/gcc/config/mips/mips.md b/gcc/gcc/config/mips/mips.md
|
| index 10572743e754eb8b6e05bbe2b2686b402fc35130..a854327432862f61ca6fe68c1bf2d9d98fa16f23 100644
|
| --- a/gcc/gcc/config/mips/mips.md
|
| +++ b/gcc/gcc/config/mips/mips.md
|
| @@ -1,6 +1,6 @@
|
| ;; Mips.md Machine Description for MIPS based processors
|
| ;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
| -;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
| +;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
| ;; Free Software Foundation, Inc.
|
| ;; Contributed by A. Lichnewsky, lich@inria.inria.fr
|
| ;; Changes by Michael Meissner, meissner@osf.org
|
| @@ -29,11 +29,13 @@
|
| (UNSPEC_STORE_WORD 2)
|
| (UNSPEC_GET_FNADDR 3)
|
| (UNSPEC_BLOCKAGE 4)
|
| - (UNSPEC_CPRESTORE 5)
|
| - (UNSPEC_RESTORE_GP 6)
|
| - (UNSPEC_EH_RETURN 7)
|
| - (UNSPEC_CONSTTABLE_INT 8)
|
| - (UNSPEC_CONSTTABLE_FLOAT 9)
|
| + (UNSPEC_POTENTIAL_CPRESTORE 5)
|
| + (UNSPEC_CPRESTORE 6)
|
| + (UNSPEC_RESTORE_GP 7)
|
| + (UNSPEC_MOVE_GP 8)
|
| + (UNSPEC_EH_RETURN 9)
|
| + (UNSPEC_CONSTTABLE_INT 10)
|
| + (UNSPEC_CONSTTABLE_FLOAT 11)
|
| (UNSPEC_ALIGN 14)
|
| (UNSPEC_HIGH 17)
|
| (UNSPEC_LOAD_LEFT 18)
|
| @@ -67,10 +69,21 @@
|
| (UNSPEC_SET_GOT_VERSION 46)
|
| (UNSPEC_UPDATE_GOT_VERSION 47)
|
| (UNSPEC_COPYGP 48)
|
| + (UNSPEC_ERET 49)
|
| + (UNSPEC_DERET 50)
|
| + (UNSPEC_DI 51)
|
| + (UNSPEC_EHB 52)
|
| + (UNSPEC_RDPGPR 53)
|
| + (UNSPEC_COP0 54)
|
| + ;; 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 55)
|
|
|
| (UNSPEC_ADDRESS_FIRST 100)
|
|
|
| (TLS_GET_TP_REGNUM 3)
|
| + (RETURN_ADDR_REGNUM 31)
|
| + (CPRESTORE_SLOT_REGNUM 76)
|
| (GOT_VERSION_REGNUM 79)
|
|
|
| ;; For MIPS Paired-Singled Floating Point Instructions.
|
| @@ -250,6 +263,9 @@
|
|
|
| (UNSPEC_MIPS_CACHE 600)
|
| (UNSPEC_R10K_CACHE_BARRIER 601)
|
| +
|
| + ;; PIC long branch sequences are never longer than 100 bytes.
|
| + (MAX_PIC_BRANCH_LENGTH 100)
|
| ]
|
| )
|
|
|
| @@ -275,14 +291,15 @@
|
| ;;
|
| ;; jal is always a macro for TARGET_CALL_CLOBBERED_GP because it includes
|
| ;; an instruction to restore $gp. Direct jals are also macros for
|
| -;; flag_pic && !TARGET_ABSOLUTE_ABICALLS because they first load
|
| -;; the target address into a register.
|
| +;; !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
|
| - || (flag_pic && !TARGET_ABSOLUTE_ABICALLS)")
|
| + (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")]
|
| + (symbol_ref "(TARGET_CALL_CLOBBERED_GP
|
| + ? JAL_MACRO_YES : JAL_MACRO_NO)")]
|
| (const_string "no")))
|
|
|
| ;; Classification of moves, extensions and truncations. Most values
|
| @@ -293,6 +310,7 @@
|
| ;; 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
|
| @@ -305,7 +323,8 @@
|
| ;; scheduling type to be "multi" instead.
|
| (define_attr "move_type"
|
| "unknown,load,fpload,store,fpstore,mtc,mfc,mthilo,mfhilo,move,fmove,
|
| - const,constN,signext,sll0,andi,loadpool,shift_shift,lui_movf"
|
| + const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool,
|
| + shift_shift,lui_movf"
|
| (const_string "unknown"))
|
|
|
| ;; Main data type used by the insn
|
| @@ -400,6 +419,9 @@
|
| (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")
|
|
|
| @@ -436,15 +458,59 @@
|
| (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
|
| +;; $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]
|
| +;; 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
|
| +;; - 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_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"))
|
| +(define_attr "sync_release_barrier" "yes,no"
|
| + (const_string "yes"))
|
| +
|
| ;; Length of instruction in bytes.
|
| (define_attr "length" ""
|
| (cond [(and (eq_attr "extended_mips16" "yes")
|
| (ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
|
| (const_int 8)
|
|
|
| - ;; Direct branch instructions have a range of [-0x40000,0x3fffc].
|
| - ;; If a branch is outside this range, we have a choice of two
|
| - ;; sequences. For PIC, an out-of-range branch like:
|
| + ;; 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
|
| @@ -458,9 +524,6 @@
|
| ;; nop
|
| ;; 1:
|
| ;;
|
| - ;; where the load address can be up to three instructions long
|
| - ;; (lw, nop, addiu).
|
| - ;;
|
| ;; 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
|
| @@ -475,12 +538,21 @@
|
| ;; will add the length of the implicit nop. The values for
|
| ;; forward and backward branches will be different as well.
|
| (eq_attr "type" "branch")
|
| - (cond [(and (le (minus (match_dup 1) (pc)) (const_int 131064))
|
| - (le (minus (pc) (match_dup 1)) (const_int 131068)))
|
| - (const_int 4)
|
| - (ne (symbol_ref "flag_pic") (const_int 0))
|
| - (const_int 24)
|
| - ] (const_int 12))
|
| + (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.
|
| + (ne (symbol_ref "TARGET_ABSOLUTE_JUMPS") (const_int 0))
|
| + (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))
|
|
|
| ;; "Ghost" instructions occupy no space.
|
| (eq_attr "type" "ghost")
|
| @@ -559,13 +631,16 @@
|
|
|
| (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. This attribute must match exactly
|
| ;; with the processor_type enumeration in mips.h.
|
| (define_attr "cpu"
|
| "r3000,4kc,4kp,5kc,5kf,20kc,24kc,24kf2_1,24kf1_1,74kc,74kf2_1,74kf1_1,74kf3_2,loongson_2e,loongson_2f,m4k,octeon,r3900,r6000,r4000,r4100,r4111,r4120,r4130,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,r10000,sb1,sb1a,sr71000,xlr"
|
| - (const (symbol_ref "mips_tune")))
|
| + (const (symbol_ref "mips_tune_attr")))
|
|
|
| ;; The type of hardware hazard associated with this instruction.
|
| ;; DELAY means that the next instruction cannot read the result
|
| @@ -596,7 +671,8 @@
|
|
|
| ;; Is it a single instruction?
|
| (define_attr "single_insn" "no,yes"
|
| - (symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)"))
|
| + (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"
|
| @@ -718,9 +794,10 @@
|
| ;; This attributes gives the mode mask of a SHORT.
|
| (define_mode_attr mask [(QI "0x00ff") (HI "0xffff")])
|
|
|
| -;; Mode attributes for GPR loads and stores.
|
| +;; Mode attributes for GPR loads.
|
| (define_mode_attr load [(SI "lw") (DI "ld")])
|
| -(define_mode_attr store [(SI "sw") (DI "sd")])
|
| +;; 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")])
|
| @@ -782,11 +859,6 @@
|
| (DF "ISA_HAS_FP4 && TARGET_FLOAT64")
|
| (V2SF "TARGET_SB1")])
|
|
|
| -;; This code iterator allows all branch instructions to be generated from
|
| -;; a single define_expand template.
|
| -(define_code_iterator any_cond [unordered ordered unlt unge uneq ltgt unle ungt
|
| - eq ne gt ge lt le gtu geu ltu leu])
|
| -
|
| ;; This code iterator allows signed and unsigned widening multiplications
|
| ;; to use the same template.
|
| (define_code_iterator any_extend [sign_extend zero_extend])
|
| @@ -985,19 +1057,15 @@
|
| }
|
| [(set_attr "type" "trap")])
|
|
|
| -(define_expand "conditional_trap"
|
| +(define_expand "ctrap<mode>4"
|
| [(trap_if (match_operator 0 "comparison_operator"
|
| - [(match_dup 2) (match_dup 3)])
|
| - (match_operand 1 "const_int_operand"))]
|
| + [(match_operand:GPR 1 "reg_or_0_operand")
|
| + (match_operand:GPR 2 "arith_operand")])
|
| + (match_operand 3 "const_0_operand"))]
|
| "ISA_HAS_COND_TRAP"
|
| {
|
| - if (GET_MODE_CLASS (GET_MODE (cmp_operands[0])) == MODE_INT
|
| - && operands[1] == const0_rtx)
|
| - {
|
| - mips_expand_conditional_trap (GET_CODE (operands[0]));
|
| - DONE;
|
| - }
|
| - FAIL;
|
| + mips_expand_conditional_trap (operands[0]);
|
| + DONE;
|
| })
|
|
|
| (define_insn "*conditional_trap<mode>"
|
| @@ -1779,15 +1847,10 @@
|
| [(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_FIX_R4000"
|
| + "mips_mulsidi3_gen_fn (<CODE>) != NULL"
|
| {
|
| - if (TARGET_64BIT)
|
| - emit_insn (gen_<u>mulsidi3_64bit (operands[0], operands[1], operands[2]));
|
| - else if (TARGET_FIX_R4000)
|
| - emit_insn (gen_<u>mulsidi3_32bit_r4000 (operands[0], operands[1],
|
| - operands[2]));
|
| - else
|
| - emit_insn (gen_<u>mulsidi3_32bit (operands[0], operands[1], operands[2]));
|
| + mulsidi3_gen_fn fn = mips_mulsidi3_gen_fn (<CODE>);
|
| + emit_insn (fn (operands[0], operands[1], operands[2]));
|
| DONE;
|
| })
|
|
|
| @@ -1811,45 +1874,75 @@
|
| (set_attr "mode" "SI")
|
| (set_attr "length" "12")])
|
|
|
| -(define_insn_and_split "<u>mulsidi3_64bit"
|
| +(define_insn "<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"
|
| + "TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DMUL3"
|
| "#"
|
| - "&& reload_completed"
|
| + [(set_attr "type" "imul")
|
| + (set_attr "mode" "SI")
|
| + (set (attr "length")
|
| + (if_then_else (ne (symbol_ref "ISA_HAS_EXT_INS") (const_int 0))
|
| + (const_int 16)
|
| + (const_int 28)))])
|
| +
|
| +(define_split
|
| + [(set (match_operand:DI 0 "d_operand")
|
| + (mult:DI (any_extend:DI (match_operand:SI 1 "d_operand"))
|
| + (any_extend:DI (match_operand:SI 2 "d_operand"))))
|
| + (clobber (match_operand:TI 3 "hilo_operand"))
|
| + (clobber (match_operand:DI 4 "d_operand"))]
|
| + "TARGET_64BIT && !TARGET_FIX_R4000 && ISA_HAS_EXT_INS && reload_completed"
|
| [(set (match_dup 3)
|
| (unspec:TI [(mult:DI (any_extend:DI (match_dup 1))
|
| (any_extend:DI (match_dup 2)))]
|
| UNSPEC_SET_HILO))
|
|
|
| - ;; OP4 <- LO, OP0 <- HI
|
| - (set (match_dup 4) (match_dup 5))
|
| - (set (match_dup 0) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
| + ;; OP0 <- LO, OP4 <- HI
|
| + (set (match_dup 0) (match_dup 5))
|
| + (set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
|
|
| - ;; Zero-extend OP4.
|
| - (set (match_dup 4)
|
| - (ashift:DI (match_dup 4)
|
| - (const_int 32)))
|
| - (set (match_dup 4)
|
| - (lshiftrt:DI (match_dup 4)
|
| - (const_int 32)))
|
| + (set (zero_extract:DI (match_dup 0) (const_int 32) (const_int 32))
|
| + (match_dup 4))]
|
| + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); })
|
|
|
| - ;; Shift OP0 into place.
|
| +(define_split
|
| + [(set (match_operand:DI 0 "d_operand")
|
| + (mult:DI (any_extend:DI (match_operand:SI 1 "d_operand"))
|
| + (any_extend:DI (match_operand:SI 2 "d_operand"))))
|
| + (clobber (match_operand:TI 3 "hilo_operand"))
|
| + (clobber (match_operand:DI 4 "d_operand"))]
|
| + "TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_EXT_INS && reload_completed"
|
| + [(set (match_dup 3)
|
| + (unspec:TI [(mult:DI (any_extend:DI (match_dup 1))
|
| + (any_extend:DI (match_dup 2)))]
|
| + UNSPEC_SET_HILO))
|
| +
|
| + ;; OP0 <- LO, OP4 <- HI
|
| + (set (match_dup 0) (match_dup 5))
|
| + (set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI))
|
| +
|
| + ;; Zero-extend OP0.
|
| (set (match_dup 0)
|
| (ashift:DI (match_dup 0)
|
| (const_int 32)))
|
| + (set (match_dup 0)
|
| + (lshiftrt:DI (match_dup 0)
|
| + (const_int 32)))
|
| +
|
| + ;; Shift OP4 into place.
|
| + (set (match_dup 4)
|
| + (ashift:DI (match_dup 4)
|
| + (const_int 32)))
|
|
|
| ;; OR the two halves together
|
| (set (match_dup 0)
|
| (ior:DI (match_dup 0)
|
| (match_dup 4)))]
|
| - { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); }
|
| - [(set_attr "type" "imul")
|
| - (set_attr "mode" "SI")
|
| - (set_attr "length" "24")])
|
| + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); })
|
|
|
| (define_insn "<u>mulsidi3_64bit_hilo"
|
| [(set (match_operand:TI 0 "register_operand" "=x")
|
| @@ -1863,6 +1956,17 @@
|
| [(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 "register_operand" "=x")
|
| @@ -2559,31 +2663,91 @@
|
| (define_expand "and<mode>3"
|
| [(set (match_operand:GPR 0 "register_operand")
|
| (and: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]);
|
| -})
|
| + (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")
|
| - (and:GPR (match_operand:GPR 1 "register_operand" "%d,d")
|
| - (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
|
| - "!TARGET_MIPS16"
|
| - "@
|
| - and\t%0,%1,%2
|
| - andi\t%0,%1,%x2"
|
| - [(set_attr "type" "logical")
|
| + [(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")
|
| - (and:GPR (match_operand:GPR 1 "register_operand" "%0")
|
| - (match_operand:GPR 2 "register_operand" "d")))]
|
| - "TARGET_MIPS16"
|
| - "and\t%0,%2"
|
| - [(set_attr "type" "logical")
|
| + [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
|
| + (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%o,o,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"
|
| @@ -2692,33 +2856,13 @@
|
| ;;
|
| ;; Step A needs a real instruction but step B does not.
|
|
|
| -(define_insn "truncdisi2"
|
| - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,m")
|
| - (truncate:SI (match_operand:DI 1 "register_operand" "d,d")))]
|
| +(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
|
| - sw\t%1,%0"
|
| - [(set_attr "move_type" "sll0,store")
|
| - (set_attr "mode" "SI")])
|
| -
|
| -(define_insn "truncdihi2"
|
| - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m")
|
| - (truncate:HI (match_operand:DI 1 "register_operand" "d,d")))]
|
| - "TARGET_64BIT"
|
| - "@
|
| - sll\t%0,%1,0
|
| - sh\t%1,%0"
|
| - [(set_attr "move_type" "sll0,store")
|
| - (set_attr "mode" "SI")])
|
| -
|
| -(define_insn "truncdiqi2"
|
| - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m")
|
| - (truncate:QI (match_operand:DI 1 "register_operand" "d,d")))]
|
| - "TARGET_64BIT"
|
| - "@
|
| - sll\t%0,%1,0
|
| - sb\t%1,%0"
|
| + <store>\t%1,%0"
|
| [(set_attr "move_type" "sll0,store")
|
| (set_attr "mode" "SI")])
|
|
|
| @@ -2744,8 +2888,9 @@
|
| [(set_attr "type" "shift")
|
| (set_attr "mode" "<MODE>")])
|
|
|
| -;; Logical shift by 32 or more results in proper SI values so
|
| -;; truncation is removed by the middle end.
|
| +;; 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
|
| @@ -2755,74 +2900,6 @@
|
| "exts\t%0,%1,%2,31"
|
| [(set_attr "type" "arith")
|
| (set_attr "mode" "<MODE>")])
|
| -
|
| -;; Combiner patterns for truncate/sign_extend combinations. The SI versions
|
| -;; use the shift/truncate patterns above.
|
| -
|
| -(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"
|
| - "#"
|
| - "&& 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));
|
| -})
|
| -
|
| -(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"
|
| - "#"
|
| - "&& 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));
|
| -})
|
| -
|
| -;; Combiner patterns to optimize truncate/zero_extend combinations.
|
| -
|
| -(define_insn "*zero_extend<mode>_trunchi"
|
| - [(set (match_operand:GPR 0 "register_operand" "=d")
|
| - (zero_extend:GPR
|
| - (truncate:HI (match_operand:DI 1 "register_operand" "d"))))]
|
| - "TARGET_64BIT && !TARGET_MIPS16"
|
| - "andi\t%0,%1,0xffff"
|
| - [(set_attr "type" "logical")
|
| - (set_attr "mode" "<MODE>")])
|
| -
|
| -(define_insn "*zero_extend<mode>_truncqi"
|
| - [(set (match_operand:GPR 0 "register_operand" "=d")
|
| - (zero_extend:GPR
|
| - (truncate:QI (match_operand:DI 1 "register_operand" "d"))))]
|
| - "TARGET_64BIT && !TARGET_MIPS16"
|
| - "andi\t%0,%1,0xff"
|
| - [(set_attr "type" "logical")
|
| - (set_attr "mode" "<MODE>")])
|
| -
|
| -(define_insn ""
|
| - [(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 "type" "logical")
|
| - (set_attr "mode" "HI")])
|
|
|
| ;;
|
| ;; ....................
|
| @@ -2833,10 +2910,15 @@
|
|
|
| ;; Extension insns.
|
|
|
| -(define_insn_and_split "zero_extendsidi2"
|
| +(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"
|
| + "TARGET_64BIT && !ISA_HAS_EXT_INS"
|
| "@
|
| #
|
| lwu\t%0,%1"
|
| @@ -2849,29 +2931,28 @@
|
| [(set_attr "move_type" "shift_shift,load")
|
| (set_attr "mode" "DI")])
|
|
|
| -;; Combine is not allowed to convert this insn into a zero_extendsidi2
|
| -;; because of TRULY_NOOP_TRUNCATION.
|
| -
|
| -(define_insn_and_split "*clear_upper32"
|
| +(define_insn "*zero_extendsidi2_dext"
|
| [(set (match_operand:DI 0 "register_operand" "=d,d")
|
| - (and:DI (match_operand:DI 1 "nonimmediate_operand" "d,W")
|
| - (const_int 4294967295)))]
|
| - "TARGET_64BIT"
|
| -{
|
| - if (which_alternative == 0)
|
| - return "#";
|
| + (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")])
|
|
|
| - operands[1] = gen_lowpart (SImode, operands[1]);
|
| - return "lwu\t%0,%1";
|
| -}
|
| - "&& reload_completed && REG_P (operands[1])"
|
| +;; 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)))]
|
| - ""
|
| - [(set_attr "move_type" "shift_shift,load")
|
| - (set_attr "mode" "DI")])
|
| + (lshiftrt:DI (match_dup 0) (const_int 32)))])
|
|
|
| (define_expand "zero_extend<SHORT:mode><GPR:mode>2"
|
| [(set (match_operand:GPR 0 "register_operand")
|
| @@ -2947,6 +3028,29 @@
|
| "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 "type" "logical")
|
| + (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 "type" "logical")
|
| + (set_attr "mode" "HI")])
|
|
|
| ;;
|
| ;; ....................
|
| @@ -3073,6 +3177,89 @@
|
| [(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")))]
|
| @@ -3116,7 +3303,7 @@
|
| (clobber (match_scratch:DF 2 "=d"))]
|
| "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
|
| {
|
| - if (set_nomacro)
|
| + 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";
|
| @@ -3153,7 +3340,7 @@
|
| (clobber (match_scratch:SF 2 "=d"))]
|
| "TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
|
| {
|
| - if (set_nomacro)
|
| + 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";
|
| @@ -3234,6 +3421,7 @@
|
| 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);
|
| @@ -3243,8 +3431,8 @@
|
| mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
|
| do_pending_stack_adjust ();
|
|
|
| - emit_insn (gen_cmpdf (operands[1], reg1));
|
| - emit_jump_insn (gen_bge (label1));
|
| + 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,
|
| @@ -3279,6 +3467,7 @@
|
| 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);
|
| @@ -3286,8 +3475,8 @@
|
| mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, DFmode));
|
| do_pending_stack_adjust ();
|
|
|
| - emit_insn (gen_cmpdf (operands[1], reg1));
|
| - emit_jump_insn (gen_bge (label1));
|
| + 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,
|
| @@ -3321,6 +3510,7 @@
|
| 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);
|
| @@ -3328,8 +3518,8 @@
|
| mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
|
| do_pending_stack_adjust ();
|
|
|
| - emit_insn (gen_cmpsf (operands[1], reg1));
|
| - emit_jump_insn (gen_bge (label1));
|
| + 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,
|
| @@ -3363,6 +3553,7 @@
|
| 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);
|
| @@ -3370,8 +3561,8 @@
|
| mips_emit_move (reg1, CONST_DOUBLE_FROM_REAL_VALUE (offset, SFmode));
|
| do_pending_stack_adjust ();
|
|
|
| - emit_insn (gen_cmpsf (operands[1], reg1));
|
| - emit_jump_insn (gen_bge (label1));
|
| + 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,
|
| @@ -3477,16 +3668,16 @@
|
| [(set_attr "type" "arith")
|
| (set_attr "mode" "<MODE>")])
|
|
|
| -(define_insn "*extzv_trunc<mode>_exts"
|
| - [(set (match_operand:GPR 0 "register_operand" "=d")
|
| - (truncate:GPR
|
| +(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" "<MODE>")])
|
| + (set_attr "mode" "SI")])
|
|
|
|
|
| (define_expand "insv"
|
| @@ -3858,7 +4049,7 @@
|
|
|
| (define_insn "*mov<mode>_ra"
|
| [(set (match_operand:GPR 0 "stack_operand" "=m")
|
| - (reg:GPR 31))]
|
| + (reg:GPR RETURN_ADDR_REGNUM))]
|
| "TARGET_MIPS16"
|
| "<store>\t$31,%0"
|
| [(set_attr "move_type" "store")
|
| @@ -4096,7 +4287,7 @@
|
| ;; instructions will still work correctly.
|
|
|
| ;; ??? Perhaps it would be better to support these instructions by
|
| -;; modifying GO_IF_LEGITIMATE_ADDRESS and friends. However, since
|
| +;; 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.
|
|
|
| @@ -4125,9 +4316,9 @@
|
| (define_insn "*lwxs"
|
| [(set (match_operand:IMOVE32 0 "register_operand" "=d")
|
| (mem:IMOVE32
|
| - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
| - (const_int 4))
|
| - (match_operand:SI 2 "register_operand" "d"))))]
|
| + (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")
|
| @@ -4616,12 +4807,12 @@
|
| ;; function address.
|
| (define_insn_and_split "loadgp_newabi_<mode>"
|
| [(set (match_operand:P 0 "register_operand" "=d")
|
| - (unspec_volatile:P [(match_operand:P 1)
|
| - (match_operand:P 2 "register_operand" "d")]
|
| - UNSPEC_LOADGP))]
|
| + (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))]
|
| @@ -4630,21 +4821,21 @@
|
| operands[4] = gen_rtx_PLUS (Pmode, operands[0], operands[2]);
|
| operands[5] = gen_rtx_LO_SUM (Pmode, operands[0], operands[1]);
|
| }
|
| - [(set_attr "length" "12")])
|
| + [(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_volatile:P [(match_operand:P 1)] UNSPEC_LOADGP))]
|
| + (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 "length" "8")])
|
| + [(set_attr "type" "ghost")])
|
|
|
| ;; This blockage instruction prevents the gp load from being
|
| ;; scheduled after an implicit use of gp. It also prevents
|
| @@ -4653,19 +4844,18 @@
|
| [(unspec_volatile [(reg:SI 28)] UNSPEC_BLOCKAGE)]
|
| ""
|
| ""
|
| - [(set_attr "type" "ghost")
|
| - (set_attr "mode" "none")])
|
| + [(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_volatile:P [(match_operand:P 1 "symbol_ref_operand")
|
| - (match_operand:P 2 "symbol_ref_operand")]
|
| - UNSPEC_LOADGP))]
|
| + (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))
|
| @@ -4675,37 +4865,72 @@
|
| operands[3] = mips_unspec_address (operands[1], SYMBOL_ABSOLUTE);
|
| operands[4] = mips_unspec_address (operands[2], SYMBOL_HALF);
|
| }
|
| - [(set_attr "length" "12")])
|
| + [(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"
|
| [(set (match_operand:SI 0 "register_operand" "=y")
|
| - (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d")]
|
| - UNSPEC_COPYGP))]
|
| + (unspec:SI [(match_operand:SI 1 "register_operand" "d")]
|
| + UNSPEC_COPYGP))]
|
| "TARGET_MIPS16"
|
| - "#"
|
| - "&& reload_completed"
|
| - [(set (match_dup 0) (match_dup 1))])
|
| + { 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"
|
| + [(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
|
| + (unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
|
| + (match_operand:SI 2 "register_operand" "d,d")]
|
| + UNSPEC_POTENTIAL_CPRESTORE))
|
| + (clobber (match_operand:SI 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. Note that we continue to use .cprestore for explicit reloc
|
| -;; code so that jals inside inline asms will work correctly.
|
| +;; 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"
|
| - [(unspec_volatile [(match_operand 0 "const_int_operand" "I,i")
|
| - (use (reg:SI 28))]
|
| - UNSPEC_CPRESTORE)]
|
| - ""
|
| -{
|
| - if (set_nomacro && which_alternative == 1)
|
| - return ".set\tmacro\;.cprestore\t%0\;.set\tnomacro";
|
| + [(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
|
| + (unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
|
| + (reg:SI 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%0";
|
| + return ".cprestore\t%1";
|
| }
|
| [(set_attr "type" "store")
|
| (set_attr "length" "4,12")])
|
|
|
| +(define_insn "use_cprestore"
|
| + [(set (reg:SI CPRESTORE_SLOT_REGNUM)
|
| + (match_operand:SI 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"
|
| @@ -4714,7 +4939,7 @@
|
| ""
|
| "
|
| {
|
| - if (ISA_HAS_SYNCI)
|
| + if (TARGET_SYNCI)
|
| {
|
| mips_expand_synci_loop (operands[0], operands[1]);
|
| emit_insn (gen_sync ());
|
| @@ -4734,12 +4959,12 @@
|
| (define_insn "sync"
|
| [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
|
| "GENERATE_SYNC"
|
| - "%|sync%-")
|
| + { return mips_output_sync (); })
|
|
|
| (define_insn "synci"
|
| [(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")]
|
| UNSPEC_SYNCI)]
|
| - "ISA_HAS_SYNCI"
|
| + "TARGET_SYNCI"
|
| "synci\t0(%0)")
|
|
|
| (define_insn "rdhwr_synci_step_<mode>"
|
| @@ -4751,7 +4976,7 @@
|
|
|
| (define_insn "clear_hazard_<mode>"
|
| [(unspec_volatile [(const_int 0)] UNSPEC_CLEAR_HAZARD)
|
| - (clobber (reg:P 31))]
|
| + (clobber (reg:P RETURN_ADDR_REGNUM))]
|
| "ISA_HAS_SYNCI"
|
| {
|
| return "%(%<bal\t1f\n"
|
| @@ -4823,7 +5048,7 @@
|
| reload pass. */
|
| if (TARGET_MIPS16
|
| && optimize
|
| - && GET_CODE (operands[2]) == CONST_INT
|
| + && CONST_INT_P (operands[2])
|
| && INTVAL (operands[2]) > 8
|
| && INTVAL (operands[2]) <= 16
|
| && !reload_in_progress
|
| @@ -4844,7 +5069,7 @@
|
| (match_operand:SI 2 "arith_operand" "dI")))]
|
| "!TARGET_MIPS16"
|
| {
|
| - if (GET_CODE (operands[2]) == CONST_INT)
|
| + if (CONST_INT_P (operands[2]))
|
| operands[2] = GEN_INT (INTVAL (operands[2])
|
| & (GET_MODE_BITSIZE (<MODE>mode) - 1));
|
|
|
| @@ -4860,7 +5085,7 @@
|
| (match_operand:SI 2 "arith_operand" "dI"))))]
|
| "TARGET_64BIT && !TARGET_MIPS16"
|
| {
|
| - if (GET_CODE (operands[2]) == CONST_INT)
|
| + if (CONST_INT_P (operands[2]))
|
| operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
|
|
|
| return "<insn>\t%0,%1,%2";
|
| @@ -4916,7 +5141,7 @@
|
| (match_operand:SI 2 "arith_operand" "d,I")))]
|
| "TARGET_64BIT && TARGET_MIPS16"
|
| {
|
| - if (GET_CODE (operands[2]) == CONST_INT)
|
| + if (CONST_INT_P (operands[2]))
|
| operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|
|
| return "dsra\t%0,%2";
|
| @@ -4935,7 +5160,7 @@
|
| (match_operand:SI 2 "arith_operand" "d,I")))]
|
| "TARGET_64BIT && TARGET_MIPS16"
|
| {
|
| - if (GET_CODE (operands[2]) == CONST_INT)
|
| + if (CONST_INT_P (operands[2]))
|
| operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|
|
| return "dsrl\t%0,%2";
|
| @@ -4990,7 +5215,7 @@
|
| (match_operand:SI 2 "arith_operand" "dI")))]
|
| "ISA_HAS_ROR"
|
| {
|
| - if (GET_CODE (operands[2]) == CONST_INT)
|
| + if (CONST_INT_P (operands[2]))
|
| gcc_assert (INTVAL (operands[2]) >= 0
|
| && INTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode));
|
|
|
| @@ -5002,50 +5227,6 @@
|
| ;;
|
| ;; ....................
|
| ;;
|
| -;; COMPARISONS
|
| -;;
|
| -;; ....................
|
| -
|
| -;; Flow here is rather complex:
|
| -;;
|
| -;; 1) The cmp{si,di,sf,df} routine is called. It deposits the arguments
|
| -;; into cmp_operands[] but generates no RTL.
|
| -;;
|
| -;; 2) The appropriate branch define_expand is called, which then
|
| -;; creates the appropriate RTL for the comparison and branch.
|
| -;; Different CC modes are used, based on what type of branch is
|
| -;; done, so that we can constrain things appropriately. There
|
| -;; are assumptions in the rest of GCC that break if we fold the
|
| -;; operands into the branches for integer operations, and use cc0
|
| -;; for floating point, so we use the fp status register instead.
|
| -;; If needed, an appropriate temporary is created to hold the
|
| -;; of the integer compare.
|
| -
|
| -(define_expand "cmp<mode>"
|
| - [(set (cc0)
|
| - (compare:CC (match_operand:GPR 0 "register_operand")
|
| - (match_operand:GPR 1 "nonmemory_operand")))]
|
| - ""
|
| -{
|
| - cmp_operands[0] = operands[0];
|
| - cmp_operands[1] = operands[1];
|
| - DONE;
|
| -})
|
| -
|
| -(define_expand "cmp<mode>"
|
| - [(set (cc0)
|
| - (compare:CC (match_operand:SCALARF 0 "register_operand")
|
| - (match_operand:SCALARF 1 "register_operand")))]
|
| - ""
|
| -{
|
| - cmp_operands[0] = operands[0];
|
| - cmp_operands[1] = operands[1];
|
| - DONE;
|
| -})
|
| -
|
| -;;
|
| -;; ....................
|
| -;;
|
| ;; CONDITIONAL BRANCHES
|
| ;;
|
| ;; ....................
|
| @@ -5055,100 +5236,94 @@
|
| (define_insn "*branch_fp"
|
| [(set (pc)
|
| (if_then_else
|
| - (match_operator 0 "equality_operator"
|
| + (match_operator 1 "equality_operator"
|
| [(match_operand:CC 2 "register_operand" "z")
|
| (const_int 0)])
|
| - (label_ref (match_operand 1 "" ""))
|
| + (label_ref (match_operand 0 "" ""))
|
| (pc)))]
|
| "TARGET_HARD_FLOAT"
|
| {
|
| return mips_output_conditional_branch (insn, operands,
|
| - MIPS_BRANCH ("b%F0", "%Z2%1"),
|
| - MIPS_BRANCH ("b%W0", "%Z2%1"));
|
| + MIPS_BRANCH ("b%F1", "%Z2%0"),
|
| + MIPS_BRANCH ("b%W1", "%Z2%0"));
|
| }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| (define_insn "*branch_fp_inverted"
|
| [(set (pc)
|
| (if_then_else
|
| - (match_operator 0 "equality_operator"
|
| + (match_operator 1 "equality_operator"
|
| [(match_operand:CC 2 "register_operand" "z")
|
| (const_int 0)])
|
| (pc)
|
| - (label_ref (match_operand 1 "" ""))))]
|
| + (label_ref (match_operand 0 "" ""))))]
|
| "TARGET_HARD_FLOAT"
|
| {
|
| return mips_output_conditional_branch (insn, operands,
|
| - MIPS_BRANCH ("b%W0", "%Z2%1"),
|
| - MIPS_BRANCH ("b%F0", "%Z2%1"));
|
| + MIPS_BRANCH ("b%W1", "%Z2%0"),
|
| + MIPS_BRANCH ("b%F1", "%Z2%0"));
|
| }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| ;; Conditional branches on ordered comparisons with zero.
|
|
|
| (define_insn "*branch_order<mode>"
|
| [(set (pc)
|
| (if_then_else
|
| - (match_operator 0 "order_operator"
|
| + (match_operator 1 "order_operator"
|
| [(match_operand:GPR 2 "register_operand" "d")
|
| (const_int 0)])
|
| - (label_ref (match_operand 1 "" ""))
|
| + (label_ref (match_operand 0 "" ""))
|
| (pc)))]
|
| "!TARGET_MIPS16"
|
| { return mips_output_order_conditional_branch (insn, operands, false); }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| (define_insn "*branch_order<mode>_inverted"
|
| [(set (pc)
|
| (if_then_else
|
| - (match_operator 0 "order_operator"
|
| + (match_operator 1 "order_operator"
|
| [(match_operand:GPR 2 "register_operand" "d")
|
| (const_int 0)])
|
| (pc)
|
| - (label_ref (match_operand 1 "" ""))))]
|
| + (label_ref (match_operand 0 "" ""))))]
|
| "!TARGET_MIPS16"
|
| { return mips_output_order_conditional_branch (insn, operands, true); }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| ;; Conditional branch on equality comparison.
|
|
|
| (define_insn "*branch_equality<mode>"
|
| [(set (pc)
|
| (if_then_else
|
| - (match_operator 0 "equality_operator"
|
| + (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 1 "" ""))
|
| + (label_ref (match_operand 0 "" ""))
|
| (pc)))]
|
| "!TARGET_MIPS16"
|
| {
|
| return mips_output_conditional_branch (insn, operands,
|
| - MIPS_BRANCH ("b%C0", "%2,%z3,%1"),
|
| - MIPS_BRANCH ("b%N0", "%2,%z3,%1"));
|
| + MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
|
| + MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
|
| }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| (define_insn "*branch_equality<mode>_inverted"
|
| [(set (pc)
|
| (if_then_else
|
| - (match_operator 0 "equality_operator"
|
| + (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 1 "" ""))))]
|
| + (label_ref (match_operand 0 "" ""))))]
|
| "!TARGET_MIPS16"
|
| {
|
| return mips_output_conditional_branch (insn, operands,
|
| - MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
|
| - MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
|
| + MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
|
| + MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
|
| }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| ;; MIPS16 branches
|
|
|
| @@ -5177,18 +5352,31 @@
|
| return "bt%N0z\t%3";
|
| }
|
| }
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| -(define_expand "b<code>"
|
| +(define_expand "cbranch<mode>4"
|
| [(set (pc)
|
| - (if_then_else (any_cond:CC (cc0)
|
| - (const_int 0))
|
| - (label_ref (match_operand 0 ""))
|
| + (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, <CODE>);
|
| + 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;
|
| })
|
|
|
| @@ -5205,42 +5393,40 @@
|
| [(set (pc)
|
| (if_then_else
|
| (equality_op (zero_extract:GPR
|
| - (match_operand:GPR 0 "register_operand" "d")
|
| + (match_operand:GPR 1 "register_operand" "d")
|
| (const_int 1)
|
| (match_operand 2 "const_int_operand" ""))
|
| (const_int 0))
|
| - (label_ref (match_operand 1 ""))
|
| + (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>", "%0,%2,%1"),
|
| - MIPS_BRANCH ("bbit<bbinv>", "%0,%2,%1"));
|
| + MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"),
|
| + MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"));
|
| }
|
| [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")
|
| (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 0 "register_operand" "d")
|
| + (match_operand:GPR 1 "register_operand" "d")
|
| (const_int 1)
|
| (match_operand 2 "const_int_operand" ""))
|
| (const_int 0))
|
| (pc)
|
| - (label_ref (match_operand 1 ""))))]
|
| + (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>", "%0,%2,%1"),
|
| - MIPS_BRANCH ("bbit<bbv>", "%0,%2,%1"));
|
| + MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"),
|
| + MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"));
|
| }
|
| [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")
|
| (set_attr "branch_likely" "no")])
|
|
|
| ;;
|
| @@ -5252,12 +5438,16 @@
|
|
|
| ;; Destination is always set in SI mode.
|
|
|
| -(define_expand "seq"
|
| +(define_expand "cstore<mode>4"
|
| [(set (match_operand:SI 0 "register_operand")
|
| - (eq:SI (match_dup 1)
|
| - (match_dup 2)))]
|
| + (match_operator:SI 1 "mips_cstore_operator"
|
| + [(match_operand:GPR 2 "register_operand")
|
| + (match_operand:GPR 3 "nonmemory_operand")]))]
|
| ""
|
| - { if (mips_expand_scc (EQ, operands[0])) DONE; else FAIL; })
|
| +{
|
| + mips_expand_scc (operands);
|
| + DONE;
|
| +})
|
|
|
| (define_insn "*seq_zero_<GPR:mode><GPR2:mode>"
|
| [(set (match_operand:GPR2 0 "register_operand" "=d")
|
| @@ -5290,16 +5480,6 @@
|
| [(set_attr "type" "slt")
|
| (set_attr "mode" "<GPR:MODE>")])
|
|
|
| -;; "sne" uses sltu instructions in which the first operand is $0.
|
| -;; This isn't possible in mips16 code.
|
| -
|
| -(define_expand "sne"
|
| - [(set (match_operand:SI 0 "register_operand")
|
| - (ne:SI (match_dup 1)
|
| - (match_dup 2)))]
|
| - "!TARGET_MIPS16"
|
| - { if (mips_expand_scc (NE, operands[0])) DONE; else FAIL; })
|
| -
|
| (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")
|
| @@ -5322,13 +5502,6 @@
|
| [(set_attr "type" "slt")
|
| (set_attr "mode" "<GPR:MODE>")])
|
|
|
| -(define_expand "sgt<u>"
|
| - [(set (match_operand:SI 0 "register_operand")
|
| - (any_gt:SI (match_dup 1)
|
| - (match_dup 2)))]
|
| - ""
|
| - { if (mips_expand_scc (<CODE>, operands[0])) DONE; else FAIL; })
|
| -
|
| (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")
|
| @@ -5347,13 +5520,6 @@
|
| [(set_attr "type" "slt")
|
| (set_attr "mode" "<GPR:MODE>")])
|
|
|
| -(define_expand "sge<u>"
|
| - [(set (match_operand:SI 0 "register_operand")
|
| - (any_ge:SI (match_dup 1)
|
| - (match_dup 2)))]
|
| - ""
|
| - { if (mips_expand_scc (<CODE>, operands[0])) DONE; else FAIL; })
|
| -
|
| (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")
|
| @@ -5363,13 +5529,6 @@
|
| [(set_attr "type" "slt")
|
| (set_attr "mode" "<GPR:MODE>")])
|
|
|
| -(define_expand "slt<u>"
|
| - [(set (match_operand:SI 0 "register_operand")
|
| - (any_lt:SI (match_dup 1)
|
| - (match_dup 2)))]
|
| - ""
|
| - { if (mips_expand_scc (<CODE>, operands[0])) DONE; else FAIL; })
|
| -
|
| (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")
|
| @@ -5393,13 +5552,6 @@
|
| (const_int 4)
|
| (const_int 8))])])
|
|
|
| -(define_expand "sle<u>"
|
| - [(set (match_operand:SI 0 "register_operand")
|
| - (any_le:SI (match_dup 1)
|
| - (match_dup 2)))]
|
| - ""
|
| - { if (mips_expand_scc (<CODE>, operands[0])) DONE; else FAIL; })
|
| -
|
| (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")
|
| @@ -5461,47 +5613,41 @@
|
|
|
| ;; Unconditional branches.
|
|
|
| -(define_insn "jump"
|
| +(define_expand "jump"
|
| [(set (pc)
|
| - (label_ref (match_operand 0 "" "")))]
|
| - "!TARGET_MIPS16"
|
| + (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 (flag_pic)
|
| + if (get_attr_length (insn) <= 8)
|
| + return "%*b\t%l0%/";
|
| + else
|
| {
|
| - if (get_attr_length (insn) <= 8)
|
| - return "%*b\t%l0%/";
|
| - else
|
| - {
|
| - output_asm_insn (mips_output_load_label (), operands);
|
| - return "%*jr\t%@%/%]";
|
| - }
|
| + mips_output_load_label (operands[0]);
|
| + return "%*jr\t%@%/%]";
|
| }
|
| - else
|
| - return "%*j\t%l0%/";
|
| }
|
| - [(set_attr "type" "jump")
|
| - (set_attr "mode" "none")
|
| - (set (attr "length")
|
| - ;; We can't use `j' when emitting PIC. Emit a branch if it's
|
| - ;; in range, otherwise load the address of the branch target into
|
| - ;; $at and then jump to it.
|
| - (if_then_else
|
| - (ior (eq (symbol_ref "flag_pic") (const_int 0))
|
| - (lt (abs (minus (match_dup 0)
|
| - (plus (pc) (const_int 4))))
|
| - (const_int 131072)))
|
| - (const_int 4) (const_int 16)))])
|
| + [(set_attr "type" "branch")])
|
|
|
| ;; We need a different insn for the mips16, because a mips16 branch
|
| ;; does not have a delay slot.
|
|
|
| -(define_insn ""
|
| +(define_insn "*jump_mips16"
|
| [(set (pc)
|
| (label_ref (match_operand 0 "" "")))]
|
| "TARGET_MIPS16"
|
| "b\t%l0"
|
| - [(set_attr "type" "branch")
|
| - (set_attr "mode" "none")])
|
| + [(set_attr "type" "branch")])
|
|
|
| (define_expand "indirect_jump"
|
| [(set (pc) (match_operand 0 "register_operand"))]
|
| @@ -5679,6 +5825,60 @@
|
| [(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"))]
|
| @@ -5748,14 +5948,28 @@
|
| (clobber (match_scratch:SI 0 "=&d"))]
|
| "TARGET_CALL_CLOBBERED_GP"
|
| "#"
|
| - "&& reload_completed"
|
| + "&& epilogue_completed"
|
| [(const_int 0)]
|
| {
|
| - mips_restore_gp (operands[0]);
|
| + mips_restore_gp_from_cprestore_slot (operands[0]);
|
| DONE;
|
| }
|
| - [(set_attr "type" "load")
|
| - (set_attr "length" "12")])
|
| + [(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")])
|
|
|
| ;;
|
| ;; ....................
|
| @@ -5808,12 +6022,6 @@
|
| ;; The register is therefore not a valid register_operand
|
| ;; and cannot be moved to or from other registers.
|
|
|
| -;; Convenience expander that generates the rhs of a load_call<mode> insn.
|
| -(define_expand "unspec_call<mode>"
|
| - [(unspec:P [(match_operand:P 0)
|
| - (match_operand:P 1)
|
| - (reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL)])
|
| -
|
| (define_insn "load_call<mode>"
|
| [(set (match_operand:P 0 "register_operand" "=d")
|
| (unspec:P [(match_operand:P 1 "register_operand" "d")
|
| @@ -5867,7 +6075,7 @@
|
| [(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); }
|
| + { return MIPS_CALL ("j", operands, 0, 1); }
|
| [(set_attr "type" "call")])
|
|
|
| (define_expand "sibcall_value"
|
| @@ -5887,7 +6095,7 @@
|
| (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); }
|
| + { return MIPS_CALL ("j", operands, 1, 2); }
|
| [(set_attr "type" "call")])
|
|
|
| (define_insn "sibcall_value_multiple_internal"
|
| @@ -5898,7 +6106,7 @@
|
| (call (mem:SI (match_dup 1))
|
| (match_dup 2)))]
|
| "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
| - { return MIPS_CALL ("j", operands, 1); }
|
| + { return MIPS_CALL ("j", operands, 1, 2); }
|
| [(set_attr "type" "call")])
|
|
|
| (define_expand "call"
|
| @@ -5953,9 +6161,9 @@
|
| (define_insn_and_split "call_internal"
|
| [(call (mem:SI (match_operand 0 "call_insn_operand" "c,S"))
|
| (match_operand 1 "" ""))
|
| - (clobber (reg:SI 31))]
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))]
|
| ""
|
| - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0); }
|
| + { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, 1); }
|
| "reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
| [(const_int 0)]
|
| {
|
| @@ -5967,10 +6175,10 @@
|
| (define_insn "call_split"
|
| [(call (mem:SI (match_operand 0 "call_insn_operand" "cS"))
|
| (match_operand 1 "" ""))
|
| - (clobber (reg:SI 31))
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))
|
| (clobber (reg:SI 28))]
|
| "TARGET_SPLIT_CALLS"
|
| - { return MIPS_CALL ("jal", operands, 0); }
|
| + { return MIPS_CALL ("jal", operands, 0, 1); }
|
| [(set_attr "type" "call")])
|
|
|
| ;; A pattern for calls that must be made directly. It is used for
|
| @@ -5981,9 +6189,9 @@
|
| [(call (mem:SI (match_operand 0 "const_call_insn_operand"))
|
| (match_operand 1))
|
| (const_int 1)
|
| - (clobber (reg:SI 31))]
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))]
|
| ""
|
| - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0); }
|
| + { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, -1); }
|
| "reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
| [(const_int 0)]
|
| {
|
| @@ -5997,10 +6205,10 @@
|
| [(call (mem:SI (match_operand 0 "const_call_insn_operand"))
|
| (match_operand 1))
|
| (const_int 1)
|
| - (clobber (reg:SI 31))
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))
|
| (clobber (reg:SI 28))]
|
| "TARGET_SPLIT_CALLS"
|
| - { return MIPS_CALL ("jal", operands, 0); }
|
| + { return MIPS_CALL ("jal", operands, 0, -1); }
|
| [(set_attr "type" "call")])
|
|
|
| (define_expand "call_value"
|
| @@ -6020,9 +6228,9 @@
|
| [(set (match_operand 0 "register_operand" "")
|
| (call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
|
| (match_operand 2 "" "")))
|
| - (clobber (reg:SI 31))]
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))]
|
| ""
|
| - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); }
|
| + { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
| "reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
| [(const_int 0)]
|
| {
|
| @@ -6037,10 +6245,10 @@
|
| [(set (match_operand 0 "register_operand" "")
|
| (call (mem:SI (match_operand 1 "call_insn_operand" "cS"))
|
| (match_operand 2 "" "")))
|
| - (clobber (reg:SI 31))
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))
|
| (clobber (reg:SI 28))]
|
| "TARGET_SPLIT_CALLS"
|
| - { return MIPS_CALL ("jal", operands, 1); }
|
| + { return MIPS_CALL ("jal", operands, 1, 2); }
|
| [(set_attr "type" "call")])
|
|
|
| ;; See call_internal_direct.
|
| @@ -6049,9 +6257,9 @@
|
| (call (mem:SI (match_operand 1 "const_call_insn_operand"))
|
| (match_operand 2)))
|
| (const_int 1)
|
| - (clobber (reg:SI 31))]
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))]
|
| ""
|
| - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); }
|
| + { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, -1); }
|
| "reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
| [(const_int 0)]
|
| {
|
| @@ -6067,10 +6275,10 @@
|
| (call (mem:SI (match_operand 1 "const_call_insn_operand"))
|
| (match_operand 2)))
|
| (const_int 1)
|
| - (clobber (reg:SI 31))
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))
|
| (clobber (reg:SI 28))]
|
| "TARGET_SPLIT_CALLS"
|
| - { return MIPS_CALL ("jal", operands, 1); }
|
| + { return MIPS_CALL ("jal", operands, 1, -1); }
|
| [(set_attr "type" "call")])
|
|
|
| ;; See comment for call_internal.
|
| @@ -6081,9 +6289,9 @@
|
| (set (match_operand 3 "register_operand" "")
|
| (call (mem:SI (match_dup 1))
|
| (match_dup 2)))
|
| - (clobber (reg:SI 31))]
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))]
|
| ""
|
| - { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); }
|
| + { return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
| "reload_completed && TARGET_SPLIT_CALLS && (operands[4] = insn)"
|
| [(const_int 0)]
|
| {
|
| @@ -6101,10 +6309,10 @@
|
| (set (match_operand 3 "register_operand" "")
|
| (call (mem:SI (match_dup 1))
|
| (match_dup 2)))
|
| - (clobber (reg:SI 31))
|
| + (clobber (reg:SI RETURN_ADDR_REGNUM))
|
| (clobber (reg:SI 28))]
|
| "TARGET_SPLIT_CALLS"
|
| - { return MIPS_CALL ("jal", operands, 1); }
|
| + { return MIPS_CALL ("jal", operands, 1, 2); }
|
| [(set_attr "type" "call")])
|
|
|
| ;; Call subroutine returning any type.
|
| @@ -6177,7 +6385,7 @@
|
| [(const_int 1)]
|
| ""
|
| {
|
| - if (set_noreorder)
|
| + if (mips_noreorder.nesting_level > 0)
|
| return "nop";
|
| else
|
| return "#nop";
|
|
|