X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=gcc%2Fconfig%2Fiq2000%2Fiq2000.md;fp=gcc%2Fconfig%2Fiq2000%2Fiq2000.md;h=225147cfc6d9cb54a0ae5eff1a0bef240bd17266;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=0000000000000000000000000000000000000000;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/config/iq2000/iq2000.md b/gcc/config/iq2000/iq2000.md new file mode 100644 index 00000000..225147cf --- /dev/null +++ b/gcc/config/iq2000/iq2000.md @@ -0,0 +1,2550 @@ +;; iq2000.md Machine Description for Vitesse IQ2000 processors +;; Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + +;; 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 +;; . + +(define_constants + [(UNSPEC_ADO16 0) + (UNSPEC_RAM 1) + (UNSPEC_CHKHDR 2) + (UNSPEC_PKRL 3) + (UNSPEC_CFC0 4) + (UNSPEC_CFC1 5) + (UNSPEC_CFC2 6) + (UNSPEC_CFC3 7) + (UNSPEC_CTC0 8) + (UNSPEC_CTC1 9) + (UNSPEC_CTC2 10) + (UNSPEC_CTC3 11) + (UNSPEC_MFC0 12) + (UNSPEC_MFC1 13) + (UNSPEC_MFC2 14) + (UNSPEC_MFC3 15) + (UNSPEC_MTC0 16) + (UNSPEC_MTC1 17) + (UNSPEC_MTC2 18) + (UNSPEC_MTC3 19) + (UNSPEC_LUR 20) + (UNSPEC_RB 21) + (UNSPEC_RX 22) + (UNSPEC_SRRD 23) + (UNSPEC_SRWR 24) + (UNSPEC_WB 25) + (UNSPEC_WX 26) + (UNSPEC_LUC32 49) + (UNSPEC_LUC32L 27) + (UNSPEC_LUC64 28) + (UNSPEC_LUC64L 29) + (UNSPEC_LUK 30) + (UNSPEC_LULCK 31) + (UNSPEC_LUM32 32) + (UNSPEC_LUM32L 33) + (UNSPEC_LUM64 34) + (UNSPEC_LUM64L 35) + (UNSPEC_LURL 36) + (UNSPEC_MRGB 37) + (UNSPEC_SRRDL 38) + (UNSPEC_SRULCK 39) + (UNSPEC_SRWRU 40) + (UNSPEC_TRAPQFL 41) + (UNSPEC_TRAPQNE 42) + (UNSPEC_TRAPREL 43) + (UNSPEC_WBU 44) + (UNSPEC_SYSCALL 45)] +) +;; UNSPEC values used in iq2000.md +;; Number USE +;; 0 movsi_ul +;; 1 movsi_us, get_fnaddr +;; 3 eh_set_return +;; 20 builtin_setjmp_setup +;; +;; UNSPEC_VOLATILE values +;; 0 blockage +;; 2 loadgp +;; 3 builtin_longjmp +;; 4 exception_receiver +;; 10 consttable_qi +;; 11 consttable_hi +;; 12 consttable_si +;; 13 consttable_di +;; 14 consttable_sf +;; 15 consttable_df +;; 16 align_2 +;; 17 align_4 +;; 18 align_8 + + +;; .................... +;; +;; Attributes +;; +;; .................... + +;; Classification of each insn. +;; branch conditional branch +;; jump unconditional jump +;; call unconditional call +;; load load instruction(s) +;; store store instruction(s) +;; move data movement within same register set +;; xfer transfer to/from coprocessor +;; arith integer arithmetic instruction +;; darith double precision integer arithmetic instructions +;; imul integer multiply +;; idiv integer divide +;; icmp integer compare +;; fadd floating point add/subtract +;; fmul floating point multiply +;; fmadd floating point multiply-add +;; fdiv floating point divide +;; fabs floating point absolute value +;; fneg floating point negation +;; fcmp floating point compare +;; fcvt floating point convert +;; fsqrt floating point square root +;; multi multiword sequence (or user asm statements) +;; nop no operation + +(define_attr "type" + "unknown,branch,jump,call,load,store,move,xfer,arith,darith,imul,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop" + (const_string "unknown")) + +;; Main data type used by the insn +(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF,FPSW" (const_string "unknown")) + +;; Length (in # of bytes). A conditional branch is allowed only to a +;; location within a signed 18-bit offset of the delay slot. If that +;; provides too small a range, we use the `j' instruction. This +;; instruction takes a 28-bit value, but that value is not an offset. +;; Instead, it's bitwise-ored with the high-order four bits of the +;; instruction in the delay slot, which means it cannot be used to +;; cross a 256MB boundary. We could fall back back on the jr, +;; instruction which allows full access to the entire address space, +;; but we do not do so at present. + +(define_attr "length" "" + (cond [(eq_attr "type" "branch") + (cond [(lt (abs (minus (match_dup 1) (plus (pc) (const_int 4)))) + (const_int 131072)) + (const_int 4)] + (const_int 12))] + (const_int 4))) + +(define_attr "cpu" + "default,iq2000" + (const (symbol_ref "iq2000_cpu_attr"))) + +;; Does the instruction have a mandatory delay slot? has_dslot +;; Can the instruction be in a delay slot? ok_in_dslot +;; Can the instruction not be in a delay slot? not_in_dslot +(define_attr "dslot" "has_dslot,ok_in_dslot,not_in_dslot" + (if_then_else (eq_attr "type" "branch,jump,call,xfer,fcmp") + (const_string "has_dslot") + (const_string "ok_in_dslot"))) + +;; Attribute defining whether or not we can use the branch-likely instructions + +(define_attr "branch_likely" "no,yes" + (const + (if_then_else (ne (symbol_ref "GENERATE_BRANCHLIKELY") (const_int 0)) + (const_string "yes") + (const_string "no")))) + + +;; Describe a user's asm statement. +(define_asm_attributes + [(set_attr "type" "multi")]) + + + +;; ......................... +;; +;; Delay slots, can't describe load/fcmp/xfer delay slots here +;; +;; ......................... + +(define_delay (eq_attr "type" "jump") + [(and (eq_attr "dslot" "ok_in_dslot") (eq_attr "length" "4")) + (nil) + (nil)]) + +(define_delay (eq_attr "type" "branch") + [(and (eq_attr "dslot" "ok_in_dslot") (eq_attr "length" "4")) + (nil) + (and (eq_attr "branch_likely" "yes") (and (eq_attr "dslot" "ok_in_dslot") (eq_attr "length" "4")))]) + +(define_delay (eq_attr "type" "call") + [(and (eq_attr "dslot" "ok_in_dslot") (eq_attr "length" "4")) + (nil) + (nil)]) + +(include "predicates.md") + + +;; ......................... +;; +;; Pipeline model +;; +;; ......................... + +(define_automaton "iq2000") +(define_cpu_unit "core,memory" "iq2000") + +(define_insn_reservation "nonmemory" 1 + (eq_attr "type" "!load,move,store,xfer") + "core") + +(define_insn_reservation "iq2000_load_move" 3 + (and (eq_attr "type" "load,move") + (eq_attr "cpu" "iq2000")) + "memory") + +(define_insn_reservation "other_load_move" 1 + (and (eq_attr "type" "load,move") + (eq_attr "cpu" "!iq2000")) + "memory") + +(define_insn_reservation "store" 1 + (eq_attr "type" "store") + "memory") + +(define_insn_reservation "xfer" 2 + (eq_attr "type" "xfer") + "memory") + +;; +;; .................... +;; +;; CONDITIONAL TRAPS +;; +;; .................... +;; + +(define_insn "trap" + [(trap_if (const_int 1) (const_int 0))] + "" + "* +{ + return \"break\"; +}") + +;; +;; .................... +;; +;; ADDITION +;; +;; .................... +;; + +(define_expand "addsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "") + +(define_insn "addsi3_internal" + [(set (match_operand:SI 0 "register_operand" "=d,=d") + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ,dJ") + (match_operand:SI 2 "arith_operand" "d,I")))] + "" + "@ + addu\\t%0,%z1,%2 + addiu\\t%0,%z1,%2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +;; +;; .................... +;; +;; SUBTRACTION +;; +;; .................... +;; + +(define_expand "subsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "") + +(define_insn "subsi3_internal" + [(set (match_operand:SI 0 "register_operand" "=d,=d") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ,dJ") + (match_operand:SI 2 "arith_operand" "d,I")))] + "" + "@ + subu\\t%0,%z1,%2 + addiu\\t%0,%z1,%n2" + [(set_attr "type" "arith") + (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")))] + "" + "* +{ + operands[2] = const0_rtx; + return \"subu\\t%0,%z2,%1\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (not:SI (match_operand:SI 1 "register_operand" "d")))] + "" + "* +{ + operands[2] = const0_rtx; + return \"nor\\t%0,%z2,%1\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +;; +;; .................... +;; +;; LOGICAL +;; +;; .................... +;; + +(define_expand "andsi3" + [(set (match_operand:SI 0 "register_operand" "=d,d,d") + (and:SI (match_operand:SI 1 "uns_arith_operand" "%d,d,d") + (match_operand:SI 2 "nonmemory_operand" "d,K,N")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d,d") + (and:SI (match_operand:SI 1 "uns_arith_operand" "%d,d,d") + (match_operand:SI 2 "nonmemory_operand" "d,K,N")))] + "" + "* +{ + if (which_alternative == 0) + return \"and\\t%0,%1,%2\"; + else if (which_alternative == 1) + return \"andi\\t%0,%1,%x2\"; + else if (which_alternative == 2) + { + if ((INTVAL (operands[2]) & 0xffff) == 0xffff) + { + operands[2] = GEN_INT (INTVAL (operands[2]) >> 16); + return \"andoui\\t%0,%1,%x2\"; + } + else + { + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); + return \"andoi\\t%0,%1,%x2\"; + } + } +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (ior:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") + (match_operand:SI 2 "uns_arith_operand" "d,K")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (ior:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") + (match_operand:SI 2 "uns_arith_operand" "d,K")))] + "" + "@ + or\\t%0,%1,%2 + ori\\t%0,%1,%x2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (xor:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") + (match_operand:SI 2 "uns_arith_operand" "d,K")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (xor:SI (match_operand:SI 1 "uns_arith_operand" "%d,d") + (match_operand:SI 2 "uns_arith_operand" "d,K")))] + "" + "@ + xor\\t%0,%1,%2 + xori\\t%0,%1,%x2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "*norsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (and:SI (not:SI (match_operand:SI 1 "register_operand" "d")) + (not:SI (match_operand:SI 2 "register_operand" "d"))))] + "" + "nor\\t%0,%z1,%z2" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +;; +;; .................... +;; +;; ZERO EXTENSION +;; +;; .................... + +;; Extension insns. +;; Those for integer source operand are ordered widest source type first. + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d,d") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))] + "" + "* +{ + if (which_alternative == 0) + return \"andi\\t%0,%1,0xffff\"; + else + return iq2000_move_1word (operands, insn, TRUE); +}" + [(set_attr "type" "arith,load,load") + (set_attr "mode" "SI") + (set_attr "length" "4,4,8")]) + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=d,d,d") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] + "" + "* +{ + if (which_alternative == 0) + return \"andi\\t%0,%1,0x00ff\"; + else + return iq2000_move_1word (operands, insn, TRUE); +}" + [(set_attr "type" "arith,load,load") + (set_attr "mode" "HI") + (set_attr "length" "4,4,8")]) + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d,d,d") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))] + "" + "* +{ + if (which_alternative == 0) + return \"andi\\t%0,%1,0x00ff\"; + else + return iq2000_move_1word (operands, insn, TRUE); +}" + [(set_attr "type" "arith,load,load") + (set_attr "mode" "SI") + (set_attr "length" "4,4,8")]) + +;; +;; .................... +;; +;; SIGN EXTENSION +;; +;; .................... + +;; Extension insns. +;; Those for integer source operand are ordered widest source type first. + +;; These patterns originally accepted general_operands, however, slightly +;; better code is generated by only accepting register_operands, and then +;; letting combine generate the lh and lb insns. + +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op1 = gen_lowpart (SImode, operands[1]); + rtx temp = gen_reg_rtx (SImode); + rtx shift = GEN_INT (16); + + emit_insn (gen_ashlsi3 (temp, op1, shift)); + emit_insn (gen_ashrsi3 (operands[0], temp, shift)); + DONE; + } +}") + +(define_insn "extendhisi2_internal" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,m")))] + "" + "* return iq2000_move_1word (operands, insn, FALSE);" + [(set_attr "type" "load") + (set_attr "mode" "SI") + (set_attr "length" "4,8")]) + +(define_expand "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op0 = gen_lowpart (SImode, operands[0]); + rtx op1 = gen_lowpart (SImode, operands[1]); + rtx temp = gen_reg_rtx (SImode); + rtx shift = GEN_INT (24); + + emit_insn (gen_ashlsi3 (temp, op1, shift)); + emit_insn (gen_ashrsi3 (op0, temp, shift)); + DONE; + } +}") + +(define_insn "extendqihi2_internal" + [(set (match_operand:HI 0 "register_operand" "=d,d") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "R,m")))] + "" + "* return iq2000_move_1word (operands, insn, FALSE);" + [(set_attr "type" "load") + (set_attr "mode" "SI") + (set_attr "length" "4,8")]) + + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + " +{ + if (optimize && GET_CODE (operands[1]) == MEM) + operands[1] = force_not_mem (operands[1]); + + if (GET_CODE (operands[1]) != MEM) + { + rtx op1 = gen_lowpart (SImode, operands[1]); + rtx temp = gen_reg_rtx (SImode); + rtx shift = GEN_INT (24); + + emit_insn (gen_ashlsi3 (temp, op1, shift)); + emit_insn (gen_ashrsi3 (operands[0], temp, shift)); + DONE; + } +}") + +(define_insn "extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=d,d") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "R,m")))] + "" + "* return iq2000_move_1word (operands, insn, FALSE);" + [(set_attr "type" "load") + (set_attr "mode" "SI") + (set_attr "length" "4,8")]) + +;; +;; ........................ +;; +;; BIT FIELD EXTRACTION +;; +;; ........................ + +(define_insn "extzv" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int_operand" "O") + (match_operand:SI 3 "const_int_operand" "O")))] + "" + "* +{ + int value[4]; + value[2] = INTVAL (operands[2]); + value[3] = INTVAL (operands[3]); + operands[2] = GEN_INT ((value[3])); + operands[3] = GEN_INT ((32 - value[2])); + return \"ram\\t%0,%1,%2,%3,0x0\"; +}" + [(set_attr "type" "arith")]) + +;; +;; .................... +;; +;; DATA MOVEMENT +;; +;; .................... + +/* Take care of constants that don't fit in single instruction */ +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "(reload_in_progress || reload_completed) + && large_int (operands[1], SImode)" + + [(set (match_dup 0 ) + (high:SI (match_dup 1))) + (set (match_dup 0 ) + (lo_sum:SI (match_dup 0) + (match_dup 1)))] +) + +;; ??? iq2000_move_1word has support for HIGH, so this pattern may be +;; unnecessary. + +(define_insn "high" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (match_operand:SI 1 "immediate_operand" "")))] + "" + "lui\\t%0,%%hi(%1) # high" + [(set_attr "type" "move")]) + +(define_insn "low" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "")))] + "" + "addiu\\t%0,%1,%%lo(%2) # low" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +;; 32-bit Integer moves + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "large_int" ""))] + "reload_in_progress | reload_completed" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (ior:SI (match_dup 0) + (match_dup 3)))] + " +{ + operands[2] = GEN_INT (trunc_int_for_mode (INTVAL (operands[1]) + & BITMASK_UPPER16, + SImode)); + operands[3] = GEN_INT (INTVAL (operands[1]) & BITMASK_LOWER16); +}") + +;; Unlike most other insns, the move insns can't be split with +;; different predicates, because register spilling and other parts of +;; the compiler, have memoized the insn number already. + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " +{ + if (iq2000_check_split (operands[1], SImode)) + { + enum machine_mode mode = GET_MODE (operands[0]); + rtx tem = ((reload_in_progress | reload_completed) + ? operands[0] : gen_reg_rtx (mode)); + + emit_insn (gen_rtx_SET (VOIDmode, tem, + gen_rtx_HIGH (mode, operands[1]))); + + operands[1] = gen_rtx_LO_SUM (mode, tem, operands[1]); + } + + if ((reload_in_progress | reload_completed) == 0 + && !register_operand (operands[0], SImode) + && !register_operand (operands[1], SImode) + && (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) != 0)) + { + rtx temp = force_reg (SImode, operands[1]); + emit_move_insn (operands[0], temp); + DONE; + } + + /* Take care of constants that don't fit in single instruction */ + if ((reload_in_progress || reload_completed) + && CONSTANT_P (operands[1]) + && GET_CODE (operands[1]) != HIGH + && GET_CODE (operands[1]) != LO_SUM + && ! SMALL_INT_UNSIGNED (operands[1])) + { + rtx tem = ((reload_in_progress | reload_completed) + ? operands[0] : gen_reg_rtx (SImode)); + + emit_insn (gen_rtx_SET (VOIDmode, tem, + gen_rtx_HIGH (SImode, operands[1]))); + operands[1] = gen_rtx_LO_SUM (SImode, tem, operands[1]); + } +}") + +;; The difference between these two is whether or not ints are allowed +;; in FP registers (off by default, use -mdebugh to enable). + +(define_insn "movsi_internal2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d") + (match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a"))] + "(register_operand (operands[0], SImode) + || register_operand (operands[1], SImode) + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" + "* return iq2000_move_1word (operands, insn, FALSE);" + [(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,move,move,move") + (set_attr "mode" "SI") + (set_attr "length" "4,8,4,8,4,8,4,8,4,4,4,4,4,4")]) + +;; 16-bit Integer moves + +;; Unlike most other insns, the move insns can't be split with +;; different predicates, because register spilling and other parts of +;; the compiler, have memoized the insn number already. +;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined + +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if ((reload_in_progress | reload_completed) == 0 + && !register_operand (operands[0], HImode) + && !register_operand (operands[1], HImode) + && ((GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) != 0))) + { + rtx temp = force_reg (HImode, operands[1]); + emit_move_insn (operands[0], temp); + DONE; + } +}") + +;; The difference between these two is whether or not ints are allowed +;; in FP registers (off by default, use -mdebugh to enable). + +(define_insn "movhi_internal2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d") + (match_operand:HI 1 "general_operand" "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))] + "(register_operand (operands[0], HImode) + || register_operand (operands[1], HImode) + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" + "* return iq2000_move_1word (operands, insn, TRUE);" + [(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,move") + (set_attr "mode" "HI") + (set_attr "length" "4,4,4,8,4,8,4,4,4,4")]) + +;; 8-bit Integer moves + +;; Unlike most other insns, the move insns can't be split with +;; different predicates, because register spilling and other parts of +;; the compiler, have memoized the insn number already. +;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined + +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if ((reload_in_progress | reload_completed) == 0 + && !register_operand (operands[0], QImode) + && !register_operand (operands[1], QImode) + && (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) != 0)) + { + rtx temp = force_reg (QImode, operands[1]); + emit_move_insn (operands[0], temp); + DONE; + } +}") + +;; The difference between these two is whether or not ints are allowed +;; in FP registers (off by default, use -mdebugh to enable). + +(define_insn "movqi_internal2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d") + (match_operand:QI 1 "general_operand" "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))] + "(register_operand (operands[0], QImode) + || register_operand (operands[1], QImode) + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" + "* return iq2000_move_1word (operands, insn, TRUE);" + [(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,move") + (set_attr "mode" "QI") + (set_attr "length" "4,4,4,8,4,8,4,4,4,4")]) + +;; 32-bit floating point moves + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " +{ + if (!reload_in_progress + && !reload_completed + && GET_CODE (operands[0]) == MEM + && (GET_CODE (operands[1]) == MEM + || GET_CODE (operands[1]) == CONST_DOUBLE)) + operands[1] = copy_to_mode_reg (SFmode, operands[1]); + + /* Take care of reg <- SF constant */ + if ( const_double_operand (operands[1], GET_MODE (operands[1]) ) ) + { + emit_insn (gen_movsf_high (operands[0], operands[1])); + emit_insn (gen_movsf_lo_sum (operands[0], operands[0], operands[1])); + DONE; + } +}") + +(define_insn "movsf_lo_sum" + [(set (match_operand:SF 0 "register_operand" "=r") + (lo_sum:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "const_double_operand" "")))] + "" + "* +{ + REAL_VALUE_TYPE r; + long i; + + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[2]); + REAL_VALUE_TO_TARGET_SINGLE (r, i); + operands[2] = GEN_INT (i); + return \"addiu\\t%0,%1,%%lo(%2) # low\"; +}" + [(set_attr "length" "4") + (set_attr "type" "arith")]) + +(define_insn "movsf_high" + [(set (match_operand:SF 0 "register_operand" "=r") + (high:SF (match_operand:SF 1 "const_double_operand" "")))] + "" + "* +{ + REAL_VALUE_TYPE r; + long i; + + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (r, i); + operands[1] = GEN_INT (i); + return \"lui\\t%0,%%hi(%1) # high\"; +}" + [(set_attr "length" "4") + (set_attr "type" "arith")]) + +(define_insn "*movsf_internal" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m") + (match_operand:SF 1 "nonimmediate_operand" "r,m,r"))] + "!memory_operand (operands[0], SFmode) || !memory_operand (operands[1], SFmode)" + "* +{ + iq2000_fill_delay_slot (\"\", DELAY_LOAD, operands, insn); + if (which_alternative == 0) + return \"or\\t%0,%1,%1\"; + else if (which_alternative == 1) + return \"lw\\t%0,%1\"; + else if (which_alternative == 2) + return \"sw\\t%1,%0\"; +}" + [(set_attr "length" "4,4,4") + (set_attr "type" "arith,load,store")] +) + +;; +;; .................... +;; +;; SHIFTS +;; +;; .................... + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "") + +(define_insn "ashlsi3_internal1" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); + return \"sll\\t%0,%1,%2\"; + } + else + return \"sllv\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "") + +(define_insn "ashrsi3_internal1" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); + return \"sra\\t%0,%1,%2\"; + } + else + return \"srav\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "") + +(define_insn "lshrsi3_internal1" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); + return \"srl\\t%0,%1,%2\"; + } + else + return \"srlv\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +;; Rotate Right +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "uns_arith_operand" "O")))] + "" + "ram %0,%1,%2,0x0,0x0" + [(set_attr "type" "arith")]) + + +;; +;; .................... +;; +;; COMPARISONS +;; +;; .................... + +;; Flow here is rather complex: +;; +;; 1) The cmp{si,di,sf,df} routine is called. It deposits the +;; arguments into the branch_cmp array, and the type into +;; branch_type. No RTL is generated. +;; +;; 2) The appropriate branch define_expand is called, which then +;; creates the appropriate RTL for the comparison and branch. +;; Different CC modes are used, based on what type of branch is +;; done, so that we can constrain things appropriately. There +;; are assumptions in the rest of GCC that break if we fold the +;; operands into the 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 "cmpsi" + [(set (cc0) + (compare:CC (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "arith_operand" "")))] + "" + " +{ + if (operands[0]) /* avoid unused code message */ + { + branch_cmp[0] = operands[0]; + branch_cmp[1] = operands[1]; + branch_type = CMP_SI; + DONE; + } +}") + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" ""))] + "" + " +{ + if (operands[0]) /* avoid unused code message */ + { + branch_cmp[0] = operands[0]; + branch_cmp[1] = const0_rtx; + branch_type = CMP_SI; + DONE; + } +}") + +;; +;; .................... +;; +;; CONDITIONAL BRANCHES +;; +;; .................... + +;; Conditional branches on comparisons with zero. + +(define_insn "branch_zero" + [(set (pc) + (if_then_else + (match_operator:SI 0 "cmp_op" + [(match_operand:SI 2 "register_operand" "d") + (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + return iq2000_output_conditional_branch (insn, + operands, + /*two_operands_p=*/0, + /*float_p=*/0, + /*inverted_p=*/0, + get_attr_length (insn)); +}" + [(set_attr "type" "branch") + (set_attr "mode" "none")]) + +(define_insn "branch_zero_inverted" + [(set (pc) + (if_then_else + (match_operator:SI 0 "cmp_op" + [(match_operand:SI 2 "register_operand" "d") + (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + return iq2000_output_conditional_branch (insn, + operands, + /*two_operands_p=*/0, + /*float_p=*/0, + /*inverted_p=*/1, + get_attr_length (insn)); +}" + [(set_attr "type" "branch") + (set_attr "mode" "none")]) + +;; Conditional branch on equality comparison. + +(define_insn "branch_equality" + [(set (pc) + (if_then_else + (match_operator:SI 0 "equality_op" + [(match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d")]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + return iq2000_output_conditional_branch (insn, + operands, + /*two_operands_p=*/1, + /*float_p=*/0, + /*inverted_p=*/0, + get_attr_length (insn)); +}" + [(set_attr "type" "branch") + (set_attr "mode" "none")]) + +(define_insn "branch_equality_inverted" + [(set (pc) + (if_then_else + (match_operator:SI 0 "equality_op" + [(match_operand:SI 2 "register_operand" "d") + (match_operand:SI 3 "register_operand" "d")]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + return iq2000_output_conditional_branch (insn, + operands, + /*two_operands_p=*/1, + /*float_p=*/0, + /*inverted_p=*/1, + get_attr_length (insn)); +}" + [(set_attr "type" "branch") + (set_attr "mode" "none")]) + +(define_expand "beq" + [(set (pc) + (if_then_else (eq:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, EQ); + DONE; + } +}") + +(define_expand "bne" + [(set (pc) + (if_then_else (ne:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, NE); + DONE; + } +}") + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, GT); + DONE; + } +}") + +(define_expand "bge" + [(set (pc) + (if_then_else (ge:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, GE); + DONE; + } +}") + +(define_expand "blt" + [(set (pc) + (if_then_else (lt:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, LT); + DONE; + } +}") + +(define_expand "ble" + [(set (pc) + (if_then_else (le:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, LE); + DONE; + } +}") + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, GTU); + DONE; + } +}") + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, GEU); + DONE; + } +}") + + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, LTU); + DONE; + } +}") + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (operands[0]) /* avoid unused code warning */ + { + gen_conditional_branch (operands, LEU); + DONE; + } +}") + +;; Recognize bbi and bbin instructions. These use two unusual template +;; patterns, %Ax and %Px. %Ax outputs an 'i' if operand `x' is a LABEL_REF +;; otherwise it outputs an 'in'. %Px does nothing if `x' is PC +;; and outputs the operand if `x' is a LABEL_REF. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "arith_operand" "I")) + (const_int 0)) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "bb%A2\\t%0(31-%1),%P2%P3" + [(set_attr "length" "4") + (set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "arith_operand" "I")) + (const_int 0)) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "bb%A3\\t%0(31-%1),%P2%P3" + [(set_attr "length" "4") + (set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else + (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "arith_operand" "I")) + (const_int 0)) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "bb%A2\\t%0(31-%1),%P2%P3" + [(set_attr "length" "4") + (set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else + (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "arith_operand" "I")) + (const_int 0)) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "bb%A3\\t%0(31-%1),%P2%P3" + [(set_attr "length" "4") + (set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "power_of_2_operand" "I")) + (const_int 0)) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "bb%A3\\t%0(%p1),%P2%P3" + [(set_attr "length" "4") + (set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "power_of_2_operand" "I")) + (const_int 0)) + (match_operand 2 "pc_or_label_operand" "") + (match_operand 3 "pc_or_label_operand" "")))] + "" + "bb%A2\\t%0(%p1),%P2%P3" + [(set_attr "length" "4") + (set_attr "type" "branch")]) + +;; +;; .................... +;; +;; SETTING A REGISTER FROM A COMPARISON +;; +;; .................... + +(define_expand "seq" + [(set (match_operand:SI 0 "register_operand" "=d") + (eq:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (EQ, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + + +(define_insn "seq_si_zero" + [(set (match_operand:SI 0 "register_operand" "=d") + (eq:SI (match_operand:SI 1 "register_operand" "d") + (const_int 0)))] + "" + "sltiu\\t%0,%1,1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "sne" + [(set (match_operand:SI 0 "register_operand" "=d") + (ne:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (NE, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "sne_si_zero" + [(set (match_operand:SI 0 "register_operand" "=d") + (ne:SI (match_operand:SI 1 "register_operand" "d") + (const_int 0)))] + "" + "sltu\\t%0,%.,%1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "sgt" + [(set (match_operand:SI 0 "register_operand" "=d") + (gt:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GT, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "sgt_si" + [(set (match_operand:SI 0 "register_operand" "=d,=d") + (gt:SI (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "reg_or_0_operand" "d,J")))] + "" + "@ + slt\\t%0,%z2,%1 + slt\\t%0,%z2,%1" + [(set_attr "type" "arith,arith") + (set_attr "mode" "SI,SI")]) + +(define_expand "sge" + [(set (match_operand:SI 0 "register_operand" "=d") + (ge:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GE, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_expand "slt" + [(set (match_operand:SI 0 "register_operand" "=d") + (lt:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LT, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "slt_si" + [(set (match_operand:SI 0 "register_operand" "=d,=d") + (lt:SI (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "d,I")))] + "" + "@ + slt\\t%0,%1,%2 + slti\\t%0,%1,%2" + [(set_attr "type" "arith,arith") + (set_attr "mode" "SI,SI")]) + +(define_expand "sle" + [(set (match_operand:SI 0 "register_operand" "=d") + (le:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LE, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "sle_si_const" + [(set (match_operand:SI 0 "register_operand" "=d") + (le:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "small_int" "I")))] + "INTVAL (operands[2]) < 32767" + "* +{ + operands[2] = GEN_INT (INTVAL (operands[2])+1); + return \"slti\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "sgtu" + [(set (match_operand:SI 0 "register_operand" "=d") + (gtu:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GTU, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "sgtu_si" + [(set (match_operand:SI 0 "register_operand" "=d") + (gtu:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "reg_or_0_operand" "dJ")))] + "" + "sltu\\t%0,%z2,%1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=t") + (gtu:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "d")))] + "" + "sltu\\t%2,%1" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + +(define_expand "sgeu" + [(set (match_operand:SI 0 "register_operand" "=d") + (geu:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GEU, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_expand "sltu" + [(set (match_operand:SI 0 "register_operand" "=d") + (ltu:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LTU, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "sltu_si" + [(set (match_operand:SI 0 "register_operand" "=d,=d") + (ltu:SI (match_operand:SI 1 "register_operand" "d,d") + (match_operand:SI 2 "arith_operand" "d,I")))] + "" + "@ + sltu\\t%0,%1,%2 + sltiu\\t%0,%1,%2" + [(set_attr "type" "arith,arith") + (set_attr "mode" "SI,SI")]) + +(define_expand "sleu" + [(set (match_operand:SI 0 "register_operand" "=d") + (leu:SI (match_dup 1) + (match_dup 2)))] + "" + " +{ + if (branch_type != CMP_SI && (branch_type != CMP_DI)) + FAIL; + + /* Set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LEU, operands[0], operands[1], operands[2], (int *)0); + DONE; +}") + +(define_insn "sleu_si_const" + [(set (match_operand:SI 0 "register_operand" "=d") + (leu:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "small_int" "I")))] + "INTVAL (operands[2]) < 32767" + "* +{ + operands[2] = GEN_INT (INTVAL (operands[2]) + 1); + return \"sltiu\\t%0,%1,%2\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI")]) + + +;; +;; .................... +;; +;; UNCONDITIONAL BRANCHES +;; +;; .................... + +;; Unconditional branches. + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"j\\t%0\"; + return \"j\\t%l0\"; + /* return \"b\\t%l0\";*/ +}" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_expand "indirect_jump" + [(set (pc) (match_operand 0 "register_operand" "d"))] + "" + " +{ + rtx dest; + + if (operands[0]) /* eliminate unused code warnings */ + { + dest = operands[0]; + if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode) + operands[0] = copy_to_mode_reg (Pmode, dest); + + if (!(Pmode == DImode)) + emit_jump_insn (gen_indirect_jump_internal1 (operands[0])); + else + emit_jump_insn (gen_indirect_jump_internal2 (operands[0])); + + DONE; + } +}") + +(define_insn "indirect_jump_internal1" + [(set (pc) (match_operand:SI 0 "register_operand" "d"))] + "!(Pmode == DImode)" + "j\\t%0" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_expand "tablejump" + [(set (pc) + (match_operand 0 "register_operand" "d")) + (use (label_ref (match_operand 1 "" "")))] + "" + " +{ + if (operands[0]) /* eliminate unused code warnings */ + { + gcc_assert (GET_MODE (operands[0]) == Pmode); + + if (!(Pmode == DImode)) + emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejump_internal2 (operands[0], operands[1])); + + DONE; + } +}") + +(define_insn "tablejump_internal1" + [(set (pc) + (match_operand:SI 0 "register_operand" "d")) + (use (label_ref (match_operand 1 "" "")))] + "!(Pmode == DImode)" + "j\\t%0" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_expand "tablejump_internal3" + [(parallel [(set (pc) + (plus:SI (match_operand:SI 0 "register_operand" "d") + (label_ref:SI (match_operand 1 "" "")))) + (use (label_ref:SI (match_dup 1)))])] + "" + "") + +;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise +;;; it is not valid. ??? With the USE, the condition tests may not be required +;;; any longer. + +;;; ??? The length depends on the ABI. It is two for o32, and one for n32. +;;; We just use the conservative number here. + +(define_insn "" + [(set (pc) + (plus:SI (match_operand:SI 0 "register_operand" "d") + (label_ref:SI (match_operand 1 "" "")))) + (use (label_ref:SI (match_dup 1)))] + "!(Pmode == DImode) && next_active_insn (insn) != 0 + && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC + && PREV_INSN (next_active_insn (insn)) == operands[1]" + "* +{ + return \"j\\t%0\"; +}" + [(set_attr "type" "jump") + (set_attr "mode" "none") + (set_attr "length" "8")]) + +;; +;; .................... +;; +;; Function prologue/epilogue +;; +;; .................... +;; + +(define_expand "prologue" + [(const_int 1)] + "" + " +{ + if (iq2000_isa >= 0) /* avoid unused code warnings */ + { + iq2000_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)] 0)] + "" + "" + [(set_attr "type" "unknown") + (set_attr "mode" "none") + (set_attr "length" "0")]) + +(define_expand "epilogue" + [(const_int 2)] + "" + " +{ + if (iq2000_isa >= 0) /* avoid unused code warnings */ + { + iq2000_expand_epilogue (); + DONE; + } +}") + +;; Trivial return. Make it look like a normal return insn as that +;; allows jump optimizations to work better . +(define_insn "return" + [(return)] + "iq2000_can_use_return_insn ()" + "j\\t%%31" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +;; Normal return. + +(define_insn "return_internal" + [(use (match_operand 0 "pmode_register_operand" "")) + (return)] + "" + "* +{ + return \"j\\t%0\"; +}" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_insn "eh_return_internal" + [(const_int 4) + (return) + (use (reg:SI 26)) + (use (reg:SI 31))] + "" + "j\\t%%26" + [(set_attr "type" "jump") + (set_attr "mode" "none")]) + +(define_expand "eh_return" + [(use (match_operand:SI 0 "register_operand" "r"))] + "" + " +{ + iq2000_expand_eh_return (operands[0]); + DONE; +}") + + +;; +;; .................... +;; +;; FUNCTION CALLS +;; +;; .................... + +;; calls.c now passes a third argument, make saber happy + +(define_expand "call" + [(parallel [(call (match_operand 0 "memory_operand" "m") + (match_operand 1 "" "i")) + (clobber (reg:SI 31)) + (use (match_operand 2 "" "")) ;; next_arg_reg + (use (match_operand 3 "" ""))])] ;; struct_value_size_rtx + "" + " +{ + rtx addr; + + if (operands[0]) /* eliminate unused code warnings */ + { + addr = XEXP (operands[0], 0); + if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr))) + || ! call_insn_operand (addr, VOIDmode)) + XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr); + + /* In order to pass small structures by value in registers + compatibly with the IQ2000 compiler, we need to shift the value + into the high part of the register. Function_arg has encoded + a PARALLEL rtx, holding a vector of adjustments to be made + as the next_arg_reg variable, so we split up the insns, + and emit them separately. */ + + if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL) + { + rtvec adjust = XVEC (operands[2], 0); + int num = GET_NUM_ELEM (adjust); + int i; + + for (i = 0; i < num; i++) + emit_insn (RTVEC_ELT (adjust, i)); + } + + emit_call_insn (gen_call_internal0 (operands[0], operands[1], + gen_rtx_REG (SImode, + GP_REG_FIRST + 31))); + DONE; + } +}") + +(define_expand "call_internal0" + [(parallel [(call (match_operand 0 "" "") + (match_operand 1 "" "")) + (clobber (match_operand:SI 2 "" ""))])] + "" + "") + +(define_insn "call_internal1" + [(call (mem (match_operand 0 "call_insn_operand" "ri")) + (match_operand 1 "" "i")) + (clobber (match_operand:SI 2 "register_operand" "=d"))] + "" + "* +{ + register rtx target = operands[0]; + + if (GET_CODE (target) == CONST_INT) + return \"li\\t%@,%0\\n\\tjalr\\t%2,%@\"; + else if (CONSTANT_ADDRESS_P (target)) + return \"jal\\t%0\"; + else + return \"jalr\\t%2,%0\"; +}" + [(set_attr "type" "call") + (set_attr "mode" "none")]) + +;; calls.c now passes a fourth argument, make saber happy + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "register_operand" "=df") + (call (match_operand 1 "memory_operand" "m") + (match_operand 2 "" "i"))) + (clobber (reg:SI 31)) + (use (match_operand 3 "" ""))])] ;; next_arg_reg + "" + " +{ + rtx addr; + + if (operands[0]) /* eliminate unused code warning */ + { + addr = XEXP (operands[1], 0); + if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr))) + || ! call_insn_operand (addr, VOIDmode)) + XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr); + + /* In order to pass small structures by value in registers + compatibly with the IQ2000 compiler, we need to shift the value + into the high part of the register. Function_arg has encoded + a PARALLEL rtx, holding a vector of adjustments to be made + as the next_arg_reg variable, so we split up the insns, + and emit them separately. */ + + if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL) + { + rtvec adjust = XVEC (operands[3], 0); + int num = GET_NUM_ELEM (adjust); + int i; + + for (i = 0; i < num; i++) + emit_insn (RTVEC_ELT (adjust, i)); + } + + if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1) + { + emit_call_insn (gen_call_value_multiple_internal0 + (XEXP (XVECEXP (operands[0], 0, 0), 0), + operands[1], operands[2], + XEXP (XVECEXP (operands[0], 0, 1), 0), + gen_rtx_REG (SImode, GP_REG_FIRST + 31))); + DONE; + } + + /* We have a call returning a DImode structure in an FP reg. + Strip off the now unnecessary PARALLEL. */ + if (GET_CODE (operands[0]) == PARALLEL) + operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0); + + emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], operands[2], + gen_rtx_REG (SImode, + GP_REG_FIRST + 31))); + + DONE; + } +}") + +(define_expand "call_value_internal0" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand 1 "" "") + (match_operand 2 "" ""))) + (clobber (match_operand:SI 3 "" ""))])] + "" + "") + +(define_insn "call_value_internal1" + [(set (match_operand 0 "register_operand" "=df") + (call (mem (match_operand 1 "call_insn_operand" "ri")) + (match_operand 2 "" "i"))) + (clobber (match_operand:SI 3 "register_operand" "=d"))] + "" + "* +{ + register rtx target = operands[1]; + + if (GET_CODE (target) == CONST_INT) + return \"li\\t%@,%1\\n\\tjalr\\t%3,%@\"; + else if (CONSTANT_ADDRESS_P (target)) + return \"jal\\t%1\"; + else + return \"jalr\\t%3,%1\"; +}" + [(set_attr "type" "call") + (set_attr "mode" "none")]) + +(define_expand "call_value_multiple_internal0" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand 1 "" "") + (match_operand 2 "" ""))) + (set (match_operand 3 "" "") + (call (match_dup 1) + (match_dup 2))) + (clobber (match_operand:SI 4 "" ""))])] + "" + "") + +;; ??? May eventually need all 6 versions of the call patterns with multiple +;; return values. + +(define_insn "call_value_multiple_internal1" + [(set (match_operand 0 "register_operand" "=df") + (call (mem (match_operand 1 "call_insn_operand" "ri")) + (match_operand 2 "" "i"))) + (set (match_operand 3 "register_operand" "=df") + (call (mem (match_dup 1)) + (match_dup 2))) + (clobber (match_operand:SI 4 "register_operand" "=d"))] + "" + "* +{ + register rtx target = operands[1]; + + if (GET_CODE (target) == CONST_INT) + return \"li\\t%@,%1\\n\\tjalr\\t%4,%@\"; + else if (CONSTANT_ADDRESS_P (target)) + return \"jal\\t%1\"; + else + return \"jalr\\t%4,%1\"; +}" + [(set_attr "type" "call") + (set_attr "mode" "none")]) + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + if (operands[0]) /* silence statement not reached warnings */ + { + int i; + + emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + emit_insn (gen_blockage ()); + DONE; + } +}") + +;; +;; .................... +;; +;; MISC. +;; +;; .................... +;; + +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "type" "nop") + (set_attr "mode" "none")]) + + +;; For the rare case where we need to load an address into a register +;; that cannot be recognized by the normal movsi/addsi instructions. +;; I have no idea how many insns this can actually generate. It should +;; be rare, so over-estimating as 10 instructions should not have any +;; real performance impact. +(define_insn "leasi" + [(set (match_operand:SI 0 "register_operand" "=d") + (match_operand:SI 1 "address_operand" "p"))] + "Pmode == SImode" + "* +{ + rtx xoperands [3]; + + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = XEXP (operands[1], 1); + output_asm_insn (\"addiu\\t%0,%1,%2\", xoperands); + return \"\"; +}" + [(set_attr "type" "arith") + (set_attr "mode" "SI") + (set_attr "length" "40")]) + +(define_insn "ado16" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] + UNSPEC_ADO16))] + "" + "ado16\\t%0, %1, %2" +) + +(define_insn "ram" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int_operand" "I") + (match_operand:SI 3 "const_int_operand" "I") + (match_operand:SI 4 "const_int_operand" "I")] + UNSPEC_RAM))] + "" + "ram\\t%0, %1, %2, %3, %4" +) + +(define_insn "chkhdr" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_CHKHDR)] + "" + "* return iq2000_fill_delay_slot (\"chkhdr\\t%0, %1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "pkrl" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_PKRL)] + "" + "* return iq2000_fill_delay_slot (\"pkrl\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "cfc0" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CFC0))] + "" + "* return iq2000_fill_delay_slot (\"cfc0\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "cfc1" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CFC1))] + "" + "* return iq2000_fill_delay_slot (\"cfc1\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "cfc2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CFC2))] + "" + "* return iq2000_fill_delay_slot (\"cfc2\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "cfc3" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CFC3))] + "" + "* return iq2000_fill_delay_slot (\"cfc3\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "ctc0" + [(unspec_volatile:SI [(match_operand:SI 0 "reg_or_0_operand" "rJ") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CTC0)] + "" + "* return iq2000_fill_delay_slot (\"ctc0\\t%z0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "ctc1" + [(unspec_volatile:SI [(match_operand:SI 0 "reg_or_0_operand" "rJ") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CTC1)] + "" + "* return iq2000_fill_delay_slot (\"ctc1\\t%z0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "ctc2" + [(unspec_volatile:SI [(match_operand:SI 0 "reg_or_0_operand" "rJ") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CTC2)] + "" + "* return iq2000_fill_delay_slot (\"ctc2\\t%z0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "ctc3" + [(unspec_volatile:SI [(match_operand:SI 0 "reg_or_0_operand" "rJ") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_CTC3)] + "" + "* return iq2000_fill_delay_slot (\"ctc3\\t%z0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "mfc0" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MFC0))] + "" + "* return iq2000_fill_delay_slot (\"mfc0\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "mfc1" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MFC1))] + "" + "* return iq2000_fill_delay_slot (\"mfc1\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "mfc2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MFC2))] + "" + "* return iq2000_fill_delay_slot (\"mfc2\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "mfc3" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MFC3))] + "" + "* return iq2000_fill_delay_slot (\"mfc3\\t%0, %%%1\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "mtc0" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MTC0)] + "" + "* return iq2000_fill_delay_slot (\"mtc0\\t%0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "mtc1" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MTC1)] + "" + "* return iq2000_fill_delay_slot (\"mtc1\\t%0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "mtc2" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MTC2)] + "" + "* return iq2000_fill_delay_slot (\"mtc2\\t%0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "mtc3" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "const_int_operand" "I")] + UNSPEC_MTC3)] + "" + "* return iq2000_fill_delay_slot (\"mtc3\\t%0, %%%1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "lur" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUR)] + "" + "* return iq2000_fill_delay_slot (\"lur\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "rb" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_RB)] + "" + "* return iq2000_fill_delay_slot (\"rb\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "rx" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_RX)] + "" + "* return iq2000_fill_delay_slot (\"rx\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "srrd" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_SRRD)] + "" + "* return iq2000_fill_delay_slot (\"srrd\\t%0\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "srwr" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_SRWR)] + "" + "* return iq2000_fill_delay_slot (\"srwr\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "wb" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_WB)] + "" + "* return iq2000_fill_delay_slot (\"wb\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "wx" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_WX)] + "" + "* return iq2000_fill_delay_slot (\"wx\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "luc32" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUC32)] + "" + "* return iq2000_fill_delay_slot (\"luc32\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "luc32l" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUC32L)] + "" + "* return iq2000_fill_delay_slot (\"luc32l\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "luc64" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUC64)] + "" + "* return iq2000_fill_delay_slot (\"luc64\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "luc64l" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUC64L)] + "" + "* return iq2000_fill_delay_slot (\"luc64l\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "luk" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUK)] + "" + "* return iq2000_fill_delay_slot (\"luk\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "lulck" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_LULCK)] + "" + "* return iq2000_fill_delay_slot (\"lulck\\t%0\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "lum32" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUM32)] + "" + "* return iq2000_fill_delay_slot (\"lum32\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "lum32l" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUM32L)] + "" + "* return iq2000_fill_delay_slot (\"lum32l\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "lum64" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUM64)] + "" + "* return iq2000_fill_delay_slot (\"lum64\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "lum64l" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LUM64L)] + "" + "* return iq2000_fill_delay_slot (\"lum64l\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "lurl" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_LURL)] + "" + "* return iq2000_fill_delay_slot (\"lurl\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "mrgb" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "const_int_operand" "I")] + UNSPEC_MRGB))] + "" + "* return iq2000_fill_delay_slot (\"mrgb\\t%0, %1, %2, %3\", DELAY_LOAD, operands, insn);" + [(set_attr "dslot" "ok_in_dslot")] +) + +(define_insn "srrdl" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_SRRDL)] + "" + "* return iq2000_fill_delay_slot (\"srrdl\\t%0\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "srulck" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_SRULCK)] + "" + "* return iq2000_fill_delay_slot (\"srulck\\t%0\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "srwru" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_SRWRU)] + "" + "* return iq2000_fill_delay_slot (\"srwru\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "trapqfl" + [(unspec_volatile:SI [(const_int 1)] UNSPEC_TRAPQFL)] + "" + "* return iq2000_fill_delay_slot (\"trapqfl\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "trapqne" + [(unspec_volatile:SI [(const_int 2)] UNSPEC_TRAPQNE)] + "" + "* return iq2000_fill_delay_slot (\"trapqne\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "traprel" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_TRAPREL)] + "" + "* return iq2000_fill_delay_slot (\"traprel %0\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "wbu" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_WBU)] + "" + "* return iq2000_fill_delay_slot (\"wbu\\t%0, %1\", DELAY_NONE, operands, insn);" + [(set_attr "dslot" "not_in_dslot")] +) + +(define_insn "syscall" + [(unspec_volatile:SI [(const_int 2)] UNSPEC_SYSCALL)] + "" + "syscall" + [(set_attr "dslot" "not_in_dslot")] +)