| ;; iq2000.md Machine Description for Vitesse IQ2000 processors |
| ;; Copyright (C) 2003, 2004, 2005 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 2, 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 COPYING. If not, write to |
| ;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, |
| ;; Boston, MA 02110-1301, USA. |
| |
| (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")] |
| ) |