From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/config/mep/mep.md | 2266 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2266 insertions(+) create mode 100644 gcc/config/mep/mep.md (limited to 'gcc/config/mep/mep.md') diff --git a/gcc/config/mep/mep.md b/gcc/config/mep/mep.md new file mode 100644 index 000000000..773a9a0aa --- /dev/null +++ b/gcc/config/mep/mep.md @@ -0,0 +1,2266 @@ +;; Toshiba Media Processor Machine description template +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Free +;; Software Foundation, Inc. +;; Contributed by Red Hat 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 +;; . */ + + + +;; Constraints: +;; +;; a $sp +;; b $tp +;; c control regs +;; h $hi ($23) +;; l $lo ($24) +;; d $hi/$lo pair (DImode) +;; j $rpc ($22) +;; r $0..$15 +;; t $0..$7 +;; v $gp +;; x $c0..$c31 +;; ex coprocessor registers that can be moved to other coprocessor registers +;; er coprocessor registers that can be moved to and from core registers +;; em coprocessor registers that can be moves to and from memory +;; y $ccr0..$ccr31 +;; z $0 +;; +;; I sign imm16 mov/add +;; J zero imm16 mov/add +;; K zero imm24 mov +;; L sign imm6 add +;; M zero imm5 slt,shifts +;; N zero imm4 bCC +;; O high imm16 mov +;; +;; R near symbol +;; S sign imm8 mov +;; T tp or gp relative symbol +;; U non-absolute memory +;; W %hi(sym) +;; Y (Rn) +;; Z Control Bus Symbol +;; +;; Modifiers: +;; +;; b print unique bit in mask +;; B print bits required for value (for clip) +;; h print decimal >> 16. +;; I print decimal, with hex comment if more than 8 bits +;; J print unsigned hex +;; L print set, clr or not (for bitops) +;; P print memory as a post-inc with no increment +;; U print bits required for value (for clipu) +;; x print unsigned decimal or hex, depending on where set bits are + +(define_constants [ + (REGSAVE_CONTROL_TEMP 11) + (FP_REGNO 8) + (TP_REGNO 13) + (GP_REGNO 14) + (SP_REGNO 15) + (PSW_REGNO 16) + (LP_REGNO 17) + (SAR_REGNO 18) + (RPB_REGNO 20) + (RPE_REGNO 21) + (RPC_REGNO 22) + (HI_REGNO 23) + (LO_REGNO 24) + (CBCR_REGNO 81) + ]) + +(define_constants [ + (UNS_BLOCKAGE 0) + (UNS_TPREL 2) + (UNS_GPREL 3) + (UNS_REPEAT_BEG 4) + (UNS_REPEAT_END 5) + (UNS_EH_EPILOGUE 6) + (UNS_EREPEAT_BEG 7) + (UNS_EREPEAT_END 8) + (UNS_BB_TRACE_RET 9) + (UNS_DISABLE_INT 10) + (UNS_ENABLE_INT 11) + (UNS_RETI 12) + ]) + +;; This attribute determines the VLIW packing mechanism. The IVC2 +;; coprocessor has two pipelines (P0 and P1), and a MeP+IVC2 can issue +;; up to three insns at a time. Most IVC2 insns can run on either +;; pipeline, however, scheduling some insns on P0 precludes packing a +;; core insn with it, and only 16-bit core insns can pack with any P0 +;; insn. +(define_attr "vliw" "basic,ivc2" + (const (symbol_ref "TARGET_IVC2"))) + +;; This attribute describes the kind of memory operand present in the +;; instruction. This is used to compute the length of the insn based +;; on the addressing mode used. +(define_attr "memop" "none,core0,core1,cop0,cop1" + (const_string "none")) + +(define_attr "intrinsic" "none,cmov,cmov1,cmov2,cmovc1,cmovc2,cmovh1,cmovh2" + (const_string "none")) + +;; This attribute describes how the instruction may be bundled in a +;; VLIW instruction. Type MULTI is assumed to use both slots. +(define_attr "slot" "core,cop,multi" + (cond [(eq_attr "intrinsic" "!none") + (const_string "cop")] + (const_string "core"))) + +;; This attribute describes the latency of the opcode (ready delay). +;; The 0 is used to indicate "unspecified". An instruction that +;; completes immediately with no potential stalls would have a value +;; of 1, a one cycle stall would be 2, etc. +(define_attr "latency" "" + (const_int 0)) + +(define_attr "shiftop" "none,operand2" + (const_string "none")) + +;; This attribute describes the size of the instruction in bytes. +;; This *must* be exact unless the pattern is SLOT_MULTI, as this +;; is used by the VLIW bundling code. +(define_attr "length" "" + (cond [(eq_attr "memop" "core0") + (symbol_ref "mep_core_address_length (insn, 0)") + (eq_attr "memop" "core1") + (symbol_ref "mep_core_address_length (insn, 1)") + (eq_attr "memop" "cop0") + (symbol_ref "mep_cop_address_length (insn, 0)") + (eq_attr "memop" "cop1") + (symbol_ref "mep_cop_address_length (insn, 1)") + ] + ; Catch patterns that don't define the length properly. + (symbol_ref "(abort (), 0)"))) + +;; This attribute describes a pipeline hazard seen in the insn. +(define_attr "stall" "none,int2,ssarb,load,store,ldc,stc,ldcb,stcb,ssrab,fsft,ret,advck,mul,mulr,div" + (cond [(and (eq_attr "shiftop" "operand2") + (not (match_operand:SI 2 "mep_single_shift_operand" ""))) + (const_string "int2")] + (const_string "none"))) + +(define_attr "may_trap" "no,yes" + (const_string "no")) + +;; Describe a user's asm statement. +(define_asm_attributes + [(set_attr "length" "4") + (set_attr "slot" "multi")]) + +;; Each IVC2 instruction uses one of these two pipelines. P0S insns +;; use P0; C3 insns use P1. +(define_automaton "mep_ivc2") +(define_cpu_unit "ivc2_core,ivc2_p0,ivc2_p1" "mep_ivc2") + +;; Each core or IVC2 instruction is bundled into one of these slots. +;; Supported bundlings: +;; +;; Core mode: +;; +;; C1 [-----core-----] +;; C2 [-------------core-------------] +;; C3 [--------------c3--------------] +;; +;; VLIW mode: +;; +;; V1 [-----core-----][--------p0s-------][------------p1------------] +;; V2 [-------------core-------------]xxxx[------------p1------------] +;; V3 1111[--p0--]0111[--------p0--------][------------p1------------] + +(define_attr "slots" "core,c3,p0,p0_p0s,p0_p1,p0s,p0s_p1,p1" (const_string "core")) + +(define_cpu_unit "ivc2_slot_c16,ivc2_slot_c32,ivc2_slot_c3,ivc2_slot_p0s,ivc2_slot_p0,ivc2_slot_p1" "mep_ivc2") + +(define_insn_reservation "ivc2_insn_core16" 1 + (and (eq_attr "vliw" "ivc2") + (and (eq (symbol_ref "get_attr_length(insn)") (const_int 2)) + (and (eq_attr "intrinsic" "none") + (eq_attr "slot" "!cop")))) + "ivc2_core+ivc2_slot_c16") + +(define_insn_reservation "ivc2_insn_core32" 1 + (and (eq_attr "vliw" "ivc2") + (and (eq (symbol_ref "get_attr_length(insn)") (const_int 4)) + (and (eq_attr "intrinsic" "none") + (eq_attr "slot" "!cop")))) + "ivc2_core+ivc2_slot_c32") + +;; These shouldn't happen when in VLIW mode. +(define_insn_reservation "ivc2_insn_c3" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "c3")) + "ivc2_p1+ivc2_slot_c3") + +(define_insn_reservation "ivc2_insn_p0" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "p0")) + "ivc2_p0+ivc2_slot_p0") + +(define_insn_reservation "ivc2_insn_p0_p0s" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "p0_p0s")) + "ivc2_p0+ivc2_slot_p0|ivc2_p0+ivc2_slot_p0s") + +(define_insn_reservation "ivc2_insn_p0_p1" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "p0_p1")) + "ivc2_p0+ivc2_slot_p0|ivc2_p1+ivc2_slot_p1") + +(define_insn_reservation "ivc2_insn_p0s" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "p0s")) + "ivc2_p0+ivc2_slot_p0s") + +(define_insn_reservation "ivc2_insn_p0s_p1" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "p0s_p1")) + "ivc2_p0+ivc2_slot_p0s|ivc2_p1+ivc2_slot_p1") + +(define_insn_reservation "ivc2_insn_p1" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "slots" "p1")) + "ivc2_p1+ivc2_slot_p1") + +;; these run in C3 also, but when we're doing VLIW scheduling, they +;; only run in P0. +(define_insn_reservation "ivc2_insn_cmov" 1 + (and (eq_attr "vliw" "ivc2") + (eq_attr "intrinsic" "!none")) + "ivc2_p0+ivc2_slot_p0") + + +(exclusion_set "ivc2_slot_c32" + "ivc2_slot_p0,ivc2_slot_p0s") +(exclusion_set "ivc2_slot_p0" + "ivc2_slot_p0s") +(exclusion_set "ivc2_slot_c16" + "ivc2_slot_p0") +(exclusion_set "ivc2_slot_c16" + "ivc2_slot_c32") + +;; Non-IVC2 scheduling. +(define_automaton "mep") +(define_cpu_unit "core,cop" "mep") + +;; Latencies are the time between one insn entering the second pipeline +;; stage (E2, LD, A2 or V2) and the next instruction entering the same +;; stage. When an instruction assigns to general registers, the default +;; latencies are for when the next instruction receives the register +;; through bypass 1. + +;; Arithmetic instructions that execute in a single stage. +(define_insn_reservation "h1_int1" 2 + (and (eq_attr "slot" "!cop") + (eq_attr "stall" "none")) + "core") +(define_bypass 1 "h1_int1" "h1_int1,h1_ssarb") +(define_bypass 1 "h1_int1" "h1_store" "mep_store_data_bypass_p") + +;; $sar can be read by an immediately following fsft or ldc. +(define_insn_reservation "h1_ssarb" 1 + (eq_attr "stall" "ssarb") + "core") + +;; Arithmetic instructions that execute in two stages. +(define_insn_reservation "h1_int2" 2 + (eq_attr "stall" "int2,fsft") + "core") +(define_bypass 1 "h1_int2" "h1_int1,h1_ssarb") +(define_bypass 1 "h1_int2" "h1_store" "mep_store_data_bypass_p") + +(define_insn_reservation "h1_load" 4 + (eq_attr "stall" "load") + "core") +(define_bypass 3 "h1_load" "h1_int1,h1_ssarb") +(define_bypass 3 "h1_load" "h1_store" "mep_store_data_bypass_p") + +(define_insn_reservation "h1_store" 1 + (eq_attr "stall" "store") + "core") + +(define_insn_reservation "h1_ipipe_ldc" 2 + (and (eq_attr "stall" "ldc") + (ne (symbol_ref "mep_ipipe_ldc_p(insn)") (const_int 0))) + "core") +(define_bypass 1 "h1_ipipe_ldc" "h1_int1,h1_ssarb") +(define_bypass 1 "h1_ipipe_ldc" "h1_store" "mep_store_data_bypass_p") + +(define_insn_reservation "h1_apipe_ldc" 2 + (and (eq_attr "stall" "ldc") + (eq (symbol_ref "mep_ipipe_ldc_p(insn)") (const_int 0))) + "core") + +;; 2 is correct for stc->ret and stc->fsft. The most important remaining +;; case is stc->madd, which induces no stall. +(define_insn_reservation "h1_stc" 2 + (eq_attr "stall" "stc") + "core") +(define_bypass 1 "h1_stc" "h1_mul") + +;; ??? Parameterised latency. +(define_insn_reservation "h1_ldcb" 5 + (eq_attr "stall" "ldcb") + "core") + +(define_insn_reservation "h1_stcb" 1 + (eq_attr "stall" "stcb") + "core") + +(define_insn_reservation "h1_advck" 6 + (eq_attr "stall" "advck") + "core") + +(define_insn_reservation "h1_mul" 5 + (eq_attr "stall" "mul,mulr") + "core") +(define_bypass 4 "h1_mul" "h1_int1,h1_ssarb") +(define_bypass 4 "h1_mul" "h1_store" "mep_store_data_bypass_p") +(define_bypass 1 "h1_mul" "h1_mul" "mep_mul_hilo_bypass_p") + +(define_insn_reservation "h1_div" 36 + (eq_attr "stall" "div") + "core") + +(define_insn_reservation "h1_cop" 1 + (eq_attr "slot" "cop") + "cop") + +(include "predicates.md") +(include "constraints.md") +(include "intrinsics.md") + +;; :::::::::::::::::::: +;; :: +;; :: Moves +;; :: +;; :::::::::::::::::::: + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (mep_expand_mov (operands, QImode)) + DONE; +}") + +;; The Idea here is to prefer the 16-bit tp-relative load, but to fall back +;; to the general 32-bit load rather than do silly things with spill regs. +(define_insn "*movqi_tprel_load" + [(set (match_operand:QI 0 "mep_tprel_operand" "=t,*r") + (mem:QI (plus:SI (match_operand:SI 1 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 2 + "symbolic_operand" "s,s")] + UNS_TPREL)))))] + "" + "lb\\t%0, %%tpoff(%2)(%1)" + [(set_attr "length" "2,4") + (set_attr "stall" "load")]) + +(define_insn "*movqi_tprel_store" + [(set (mem:QI (plus:SI (match_operand:SI 0 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 1 + "symbolic_operand" "s,s")] + UNS_TPREL)))) + (match_operand:QI 2 "mep_tprel_operand" "t,*r"))] + "" + "sb\\t%2, %%tpoff(%1)(%0)" + [(set_attr "length" "2,4") + (set_attr "stall" "store")]) + +(define_insn "*movqi_internal" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r, r,m,r,c,r,y,r,er,ex,em,Y") + (match_operand:QI 1 "general_operand" " r,n,rm,r,c,r,y,r,er,r,ex,Y,em"))] + "mep_mov_ok (operands, QImode)" + "@ + mov\\t%0, %1 + mov\\t%0, %1 + lb\\t%0, %1 + sb\\t%1, %0 + ldc\\t%0, %1 + stc\\t%1, %0 + cmovc\\t%0, %1 + cmovc\\t%0, %1 + cmov\\t%0, %1 + cmov\\t%0, %1 + %<\\t%0, %M1 + lbcpa\\t%0, %P1 + sbcpa\\t%1, %P0" + [(set_attr "length" "2,2,*,*,2,2,4,4,4,4,*,4,4") + (set_attr "intrinsic" "*,*,*,*,*,*,cmovc2,cmovc1,cmov2,cmov1,cmov,*,*") + (set_attr "stall" "*,*,load,store,ldc,stc,*,*,*,*,*,load,store") + (set_attr "memop" "*,*,core1,core0,*,*,*,*,*,*,*,*,*")]) + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (mep_expand_mov (operands, HImode)) + DONE; +}") + +(define_insn "*movhi_tprel_load" + [(set (match_operand:HI 0 "mep_tprel_operand" "=t,*r") + (mem:HI (plus:SI (match_operand:SI 1 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 2 + "symbolic_operand" "s,s")] + UNS_TPREL)))))] + "" + "lh\\t%0, %%tpoff(%2)(%1)" + [(set_attr "length" "2,4") + (set_attr "stall" "load")]) + +(define_insn "*movhi_tprel_store" + [(set (mem:HI (plus:SI (match_operand:SI 0 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 1 + "symbolic_operand" "s,s")] + UNS_TPREL)))) + (match_operand:HI 2 "mep_tprel_operand" "t,*r"))] + "" + "sh\\t%2, %%tpoff(%1)(%0)" + [(set_attr "length" "2,4") + (set_attr "stall" "store")]) + +(define_insn "*movhi_internal" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,m,r,c,r,y,r,er,ex,em,Y") + (match_operand:HI 1 "general_operand" " r,S,n,m,r,c,r,y,r,er,r,ex,Y,em"))] + "mep_mov_ok (operands, HImode)" + "@ + mov\\t%0, %1 + mov\\t%0, %I1 + mov\\t%0, %I1 + lh\\t%0, %1 + sh\\t%1, %0 + ldc\\t%0, %1 + stc\\t%1, %0 + cmovc\\t%0, %1 + cmovc\\t%0, %1 + cmov\\t%0, %1 + cmov\\t%0, %1 + %<\\t%0, %M1 + lhcpa\\t%0, %P1 + shcpa\\t%1, %P0" + [(set_attr "length" "2,2,4,*,*,2,2,4,4,4,4,*,4,4") + (set_attr "intrinsic" "*,*,*,*,*,*,*,cmovc2,cmovc1,cmov2,cmov1,cmov,*,*") + (set_attr "stall" "*,*,*,load,store,ldc,stc,*,*,*,*,*,load,store") + (set_attr "memop" "*,*,*,core1,core0,*,*,*,*,*,*,*,*,*")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " +{ + if (mep_expand_mov (operands, SImode)) + DONE; +}") + +(define_insn "*movsi_tprel_load" + [(set (match_operand:SI 0 "mep_tprel_operand" "=t,*r") + (mem:SI (plus:SI (match_operand:SI 1 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 2 + "symbolic_operand" "s,s")] + UNS_TPREL)))))] + "" + "lw\\t%0, %%tpoff(%2)(%1)" + [(set_attr "length" "2,4") + (set_attr "stall" "load")]) + +(define_insn "*movsi_tprel_store" + [(set (mem:SI (plus:SI (match_operand:SI 0 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 1 + "symbolic_operand" "s,s")] + UNS_TPREL)))) + (match_operand:SI 2 "mep_tprel_operand" "t,*r"))] + "" + "sw\\t%2, %%tpoff(%1)(%0)" + [(set_attr "length" "2,4") + (set_attr "stall" "store")]) + +(define_insn "movsi_topsym_s" + [(set (match_operand:SI 0 "register_operand" "=r") + (high:SI (match_operand:SI 1 "symbolic_operand" "s")))] + "" + "movh\\t%0, %%hi(%1)" + [(set_attr "length" "4")]) + +(define_insn "movsi_botsym_s" + [(set (match_operand:SI 0 "register_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "symbolic_operand" "s")))] + "" + "add3\\t%0, %1, %%lo(%2)" + [(set_attr "length" "4")]) + + + +(define_insn "cmovh_getsub" + [(set (match_operand:SI 0 "register_operand" "=r") + (subreg:SI (match_operand:DI 1 "register_operand" "er") 4))] + "0 && TARGET_64BIT_CR_REGS" + "cmovh\\t%0, %1" + [(set_attr "intrinsic" "cmovh2") + (set_attr "length" "4")]) + +(define_insn "*movsi_internal" + [(set (match_operand:SI 0 "mep_movdest_operand" + "=r,r,r,r,r, t,t,r,r,r,Z,m,r,c,r,y,r, er,ex,em,U ") + (match_operand:SI 1 "general_operand" + " r,S,I,J,OW,K,s,i,Z,m,r,r,c,r,y,r,er,r, ex,U, em"))] + "mep_mov_ok (operands, SImode)" + "@ + mov\\t%0, %1 + mov\\t%0, %I1 + mov\\t%0, %I1 + movu\\t%0, %J1 + movh\\t%0, %h1 + movu\\t%0, %x1 + movu\\t%0, %1 + # + ldcb\\t%0, %1 + lw\\t%0, %1 + stcb\\t%1, %0 + sw\\t%1, %0 + ldc\\t%0, %1 + stc\\t%1, %0 + cmovc\\t%0, %1 + cmovc\\t%0, %1 + cmov\\t%0, %1 + cmov\\t%0, %1 + %<\\t%0, %M1 + lwcp\\t%0, %1 + swcp\\t%1, %0" + [(set_attr "length" "2,2,4,4,4,4,4,*,4,*,4,*,2,2,4,4,4,4,4,*,*") + (set_attr "intrinsic" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,cmovc2,cmovc1,cmov2,cmov1,cmov,*,*") + (set_attr "stall" "*,*,*,*,*,*,*,*,ldcb,load,stcb,store,ldc,stc,*,*,*,*,*,load,store") + (set_attr "memop" "*,*,*,*,*,*,*,*,*,core1,*,core0,*,*,*,*,*,*,*,cop1,cop0") + (set_attr "slot" "*,*,*,*,*,*,*,multi,*,*,*,*,*,*,*,*,*,*,*,*,*")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "mep_split_mov (operands, 0)" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 3)))] + " +{ + HOST_WIDE_INT value; + int lo, hi; + + value = INTVAL (operands[1]); + + lo = value & 0xffff; + hi = trunc_int_for_mode (value & 0xffff0000, SImode); + + operands[2] = GEN_INT (hi); + operands[3] = GEN_INT (lo); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "immediate_operand" ""))] + "mep_split_mov (operands, 1)" + [(set (match_dup 0) (high:SI (match_dup 1))) + (set (match_dup 0) (lo_sum:SI (match_dup 0) (match_dup 1)))] + "") + +;; ??? What purpose do these two serve that high+lo_sum do not? +(define_insn "movsi_topsym_u" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "symbolic_operand" "s") + (const_int -65536)))] + "" + "movh\\t%0, %%uhi(%1)" + [(set_attr "length" "4")]) + +(define_insn "movsi_botsym_u" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "0") + (and:SI (match_operand:SI 2 "symbolic_operand" "s") + (const_int 65535))))] + "" + "or3\\t%0, %1, %%lo(%2)" + [(set_attr "length" "4")]) + +(define_expand "movdi" + [(set (match_operand:DI 0 "" "") + (match_operand:DI 1 "" ""))] + "" + " +{ + if (mep_expand_mov (operands, DImode)) + DONE; +}") + +(define_insn "*movdi_internal_32" + [(set (match_operand:DI 0 "mep_movdest_operand" "= r,m,r,c,r,er,ex,em,U") + (match_operand:DI 1 "general_operand" "rim,r,c,r,er,r,ex,U,em"))] + "TARGET_32BIT_CR_REGS && mep_mov_ok (operands, DImode)" + "#" + [(set_attr "slot" "multi")]) + +(define_insn "*movdi_internal_64" + [(set (match_operand:DI 0 "mep_movdest_operand" "=r,r,m,r,c,r,er,ex,em,U") + (match_operand:DI 1 "general_operand" "r,im,r,c,r,er,r,ex,U,em"))] + "TARGET_64BIT_CR_REGS && mep_mov_ok (operands, DImode)" + "@ + # + # + # + # + # + # + # + %<\\t%0, %M1 + lmcp\\t%0, %1 + smcp\\t%1, %0" + [(set_attr "slot" "multi,multi,multi,multi,multi,multi,multi,*,*,*") + (set_attr "intrinsic" "*,*,*,*,*,*,*,cmov,*,*") + (set_attr "memop" "*,*,*,*,*,*,*,cop0,cop1,cop0") + (set_attr "stall" "*,*,*,*,*,*,*,*,load,store")]) + +(define_insn "*movdi_cop_postinc" + [(parallel [(set (match_operand:DI 0 "register_operand" "=em") + (mem:DI (reg:SI SP_REGNO))) + (set (reg:SI SP_REGNO) + (plus:SI (reg:SI SP_REGNO) + (const_int 8))) + ] + )] + "TARGET_COP" + "lmcpi\\t%0,($sp+)" + [(set_attr "length" "2")]) + +(define_insn "*movdi_cop_postinc" + [(parallel [(set (match_operand:DI 0 "register_operand" "=em") + (mem:DI (match_operand:SI 2 "register_operand" "r"))) + (set (match_operand:SI 1 "register_operand" "=0") + (plus:SI (match_operand:SI 3 "register_operand" "0") + (const_int 8))) + ] + )] + "TARGET_COP" + "lmcpi\\t%0,(%1+)" + [(set_attr "length" "2")]) + +(define_insn "*cmovh_set" + [(set (zero_extract:SI (match_operand:DI 0 "register_operand" "+er") + (const_int 32) + (const_int 32)) + (match_operand:SI 1 "register_operand" "r"))] + "TARGET_64BIT_CR_REGS" + "cmovh\\t%0, %1" + [(set_attr "intrinsic" "cmovh1") + (set_attr "length" "4")]) + +(define_insn "cmovh_get" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:DI 1 "register_operand" "er") + (const_int 32) + (const_int 32)))] + "TARGET_64BIT_CR_REGS" + "cmovh\\t%0, %1" + [(set_attr "intrinsic" "cmovh2") + (set_attr "length" "4")]) + +(define_split + [(set (match_operand:DI 0 "mep_movdest_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "reload_completed && mep_multi_slot (insn)" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "mep_split_wide_move (operands, DImode);") + +;; Floating Point Moves + +(define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " +{ + if (mep_expand_mov (operands, SFmode)) + DONE; +}") + +(define_insn "*movsf_tprel_load" + [(set (match_operand:SF 0 "mep_tprel_operand" "=t,*r") + (mem:SF (plus:SI (match_operand:SI 1 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 2 + "symbolic_operand" "s,s")] + UNS_TPREL)))))] + "" + "lw\\t%0, %%tpoff(%2)(%1)" + [(set_attr "length" "2,4") + (set_attr "stall" "load")]) + +(define_insn "*movsf_tprel_store" + [(set (mem:SF (plus:SI (match_operand:SI 0 "mep_tp_operand" "b,*r") + (const:SI (unspec:SI [(match_operand:SI 1 + "symbolic_operand" "s,s")] + UNS_TPREL)))) + (match_operand:SF 2 "mep_tprel_operand" "t,*r"))] + "" + "sw\\t%2, %%tpoff(%1)(%0)" + [(set_attr "length" "2,4") + (set_attr "stall" "store")]) + +(define_insn "*movsf_internal" + [(set (match_operand:SF 0 "mep_movdest_operand" + "=r,r,r,r,Z,m,r,c,r,y,r,er,ex,em,U") + (match_operand:SF 1 "general_operand" + " r,F,Z,m,r,r,c,r,y,r,er,r,ex,U,em"))] + "mep_mov_ok (operands, SFmode)" + "@ + mov\\t%0, %1 + # + ldcb\\t%0, %1 + lw\\t%0, %1 + stcb\\t%1, %0 + sw\\t%1, %0 + ldc\\t%0, %1 + stc\\t%1, %0 + cmovc\\t%0, %1 + cmovc\\t%0, %1 + cmov\\t%0, %1 + cmov\\t%0, %1 + %<\\t%0, %M1 + lwcp\\t%0, %1 + swcp\\t%1, %0" + [(set_attr "length" "2,*,2,*,2,*,2,2,*,*,4,4,*,*,*") + (set_attr "intrinsic" "*,*,*,*,*,*,*,*,cmovc2,cmovc1,cmov2,cmov1,cmov,*,*") + (set_attr "stall" "*,*,ldcb,load,stcb,store,ldc,stc,*,*,*,*,*,load,store") + (set_attr "memop" "*,*,*,core1,*,core0,*,*,*,*,*,*,*,cop1,cop0")]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "const_double_operand" ""))] + "reload_completed" + [(const_int 0)] + " +{ + REAL_VALUE_TYPE rv; + HOST_WIDE_INT value; + HOST_WIDE_INT lo, hi; + rtx out; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (rv, value); + + lo = value & 0xffff; + hi = trunc_int_for_mode (value & 0xffff0000, SImode); + + out = gen_rtx_REG (SImode, REGNO (operands[0])); + emit_move_insn (out, GEN_INT (hi)); + if (lo != 0) + emit_insn (gen_iorsi3 (out, out, GEN_INT (lo))); + DONE; +}") + +(define_expand "movdf" + [(set (match_operand:DF 0 "" "") + (match_operand:DF 1 "" ""))] + "" + " +{ + if (mep_expand_mov (operands, DFmode)) + DONE; +}") + +(define_insn "*movdf_internal_32" + [(set (match_operand:DF 0 "mep_movdest_operand" "= r,m,r,c,r,er,ex,em,U") + (match_operand:DF 1 "general_operand" "rFm,r,c,r,er,r,ex,U,em"))] + "TARGET_32BIT_CR_REGS && mep_mov_ok (operands, DFmode)" + "#" + [(set_attr "slot" "multi")]) + +(define_insn "*movdf_internal_64" + [(set (match_operand:DF 0 "mep_movdest_operand" "= r,m,r,c,r,er,ex,em,U") + (match_operand:DF 1 "general_operand" "rFm,r,c,r,er,r,ex,U,em"))] + "TARGET_64BIT_CR_REGS && mep_mov_ok (operands, DFmode)" + "@ + # + # + # + # + # + # + %<\\t%0, %M1 + lmcp\\t%0, %1 + smcp\\t%1, %0" + [(set_attr "slot" "multi,multi,multi,multi,multi,multi,*,*,*") + (set_attr "intrinsic" "*,*,*,*,*,*,cmov,*,*") + (set_attr "memop" "*,*,*,*,*,*,*,cop1,cop0") + (set_attr "stall" "*,*,*,*,*,*,*,load,store")]) + +(define_split + [(set (match_operand:DF 0 "mep_movdest_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "reload_completed && mep_multi_slot (insn)" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "mep_split_wide_move (operands, DFmode);") + + +(define_insn "*lbcpa" + [(set (match_operand:SI 0 "register_operand" "=em") + (sign_extend:SI (mem:QI (match_operand:SI 2 "register_operand" "1")))) + (set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_dup 2) + (match_operand:SI 3 "cgen_h_sint_8a1_immediate" "")))] + "TARGET_COP && reload_completed" + "lbcpa\t%0, (%1+), %3" + [(set_attr "length" "4") + (set_attr "stall" "load")]) + +(define_insn "*sbcpa" + [(set (mem:QI (match_operand:SI 1 "register_operand" "0")) + (match_operand:QI 2 "register_operand" "em")) + (set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 1) + (match_operand:SI 3 "cgen_h_sint_8a1_immediate" "")))] + "TARGET_COP && reload_completed" + "sbcpa\t%2, (%0+), %3" + [(set_attr "length" "4") + (set_attr "stall" "store")]) + +(define_insn "*lhcpa" + [(set (match_operand:SI 0 "register_operand" "=em") + (sign_extend:SI (mem:HI (match_operand:SI 2 "register_operand" "1")))) + (set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_dup 2) + (match_operand:SI 3 "cgen_h_sint_7a2_immediate" "")))] + "TARGET_COP && reload_completed" + "lhcpa\t%0, (%1+), %3" + [(set_attr "length" "4") + (set_attr "stall" "load")]) + +(define_insn "*shcpa" + [(set (mem:HI (match_operand:SI 1 "register_operand" "0")) + (match_operand:HI 2 "register_operand" "em")) + (set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 1) + (match_operand:SI 3 "cgen_h_sint_7a2_immediate" "")))] + "TARGET_COP && reload_completed" + "shcpa\t%2, (%0+), %3" + [(set_attr "length" "4") + (set_attr "stall" "store")]) + +(define_insn "*lwcpi" + [(set (match_operand:SI 0 "register_operand" "=em") + (mem:SI (match_operand:SI 2 "register_operand" "1"))) + (set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_dup 2) + (const_int 4)))] + "TARGET_COP && reload_completed" + "lwcpi\t%0, (%1+)" + [(set_attr "length" "2") + (set_attr "stall" "load")]) + +(define_insn "*lwcpa" + [(set (match_operand:SI 0 "register_operand" "=em") + (mem:SI (match_operand:SI 2 "register_operand" "1"))) + (set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_dup 2) + (match_operand:SI 3 "cgen_h_sint_6a4_immediate" "")))] + "TARGET_COP && reload_completed" + "lwcpa\t%0, (%1+), %3" + [(set_attr "length" "4") + (set_attr "stall" "load")]) + +(define_insn "*swcpi" + [(set (mem:SI (match_operand:SI 1 "register_operand" "0")) + (match_operand:SI 2 "register_operand" "em")) + (set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 1) + (const_int 4)))] + "TARGET_COP && reload_completed" + "swcpi\t%2, (%0+)" + [(set_attr "length" "2") + (set_attr "stall" "store")]) + +(define_insn "*swcpa" + [(set (mem:SI (match_operand:SI 1 "register_operand" "0")) + (match_operand:SI 2 "register_operand" "em")) + (set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 1) + (match_operand:SI 3 "cgen_h_sint_6a4_immediate" "")))] + "TARGET_COP && reload_completed" + "swcpa\t%2, (%0+), %3" + [(set_attr "length" "4") + (set_attr "stall" "store")]) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "cgen_h_sint_8a1_immediate" "")))] + "TARGET_COP && mep_use_post_modify_p (insn, operands[0], operands[1])" + [(const_int 0)] +{ + emit_note (NOTE_INSN_DELETED); + DONE; +}) + +;; :::::::::::::::::::: +;; :: +;; :: Reloads +;; :: +;; :::::::::::::::::::: + +(define_expand "reload_insi" + [(set (match_operand:SI 0 "mep_reload_operand" "") + (match_operand:SI 1 "mep_reload_operand" "r")) + (clobber (match_operand:SI 2 "register_operand" "=&r"))] + "" + " +{ + mep_expand_reload (operands, SImode); + DONE; +}") + +(define_expand "reload_outsi" + [(set (match_operand:SI 0 "mep_reload_operand" "=r") + (match_operand:SI 1 "mep_reload_operand" "")) + (clobber (match_operand:SI 2 "register_operand" "=&r"))] + "" + " +{ + mep_expand_reload (operands, SImode); + DONE; +}") + + +;; :::::::::::::::::::: +;; :: +;; :: Conversions +;; :: +;; :::::::::::::::::::: + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r,em") + (sign_extend:SI + (match_operand:QI 1 "nonimmediate_operand" "0,m,Y")))] + "" + "@ + extb\\t%0 + lb\\t%0, %1 + lbcpa\\t%0, %P1" + [(set_attr "length" "2,*,*") + (set_attr "stall" "*,load,load") + (set_attr "memop" "*,core1,cop1")]) + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r,em") + (sign_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "0,m,Y")))] + "" + "@ + exth\\t%0 + lh\\t%0, %1 + lhcpa\\t%0, %P1" + [(set_attr "length" "2,*,*") + (set_attr "stall" "*,load,load") + (set_attr "memop" "*,core1,cop1")]) + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (zero_extend:SI + (match_operand:QI 1 "nonimmediate_operand" "0,r,m")))] + "" + "@ + extub\\t%0 + and3\\t%0, %1, 255 + lbu\\t%0, %1" + [(set_attr "length" "2,4,*") + (set_attr "stall" "*,*,load") + (set_attr "memop" "*,*,core1")]) + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (zero_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "0,r,m")))] + "" + "@ + extuh\\t%0 + and3\\t%0, %1, 65535 + lhu\\t%0, %1" + [(set_attr "length" "2,4,*") + (set_attr "stall" "*,*,load") + (set_attr "memop" "*,*,core1")]) + +;; :::::::::::::::::::: +;; :: +;; :: 32 bit Integer arithmetic +;; :: +;; :::::::::::::::::::: + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%r,0,r") + (match_operand:SI 2 "mep_add_operand" "r,L,IT")))] + "" + "@ + add3\\t%0, %1, %2 + add\\t%0, %2 + add3\\t%0, %1, %I2" + [(set (attr "length") + (if_then_else (eq_attr "alternative" "2") + (if_then_else (and (match_operand:SI 1 "mep_sp_operand" "") + (match_operand:SI 2 "mep_imm7a4_operand" "")) + (const_int 2) + (const_int 4)) + (const_int 2)))]) + +;; The intention here is to combine the 16-bit add with the 16-bit +;; move to create a 32-bit add. It's the same size, but takes one +;; less machine cycle. It will happen to match a 32-bit add with a +;; 16-bit move also, but gcc shouldn't be doing that ;) +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "immediate_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (match_operand:SI 4 "register_operand" ""))] + "REGNO (operands[0]) == REGNO (operands[1]) + && REGNO (operands[0]) == REGNO (operands[4]) + && GR_REGNO_P (REGNO (operands[3])) + && dead_or_set_p (peep2_next_insn (1), operands[4])" + [(set (match_dup 3) + (plus:SI (match_dup 1) + (match_dup 2)))] + "") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r")))] + "" + "sub\\t%0, %2" + [(set_attr "length" "2")]) + +(define_expand "mulsi3" + [(set (match_operand:SI 0 "register_operand" "") + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" "")))] + "TARGET_OPT_MULT || TARGET_COPRO_MULT" +{ + emit_insn (gen_mulsi3_1 (operands[0], operands[1], operands[2])); + DONE; +}) + +;; Generated by mep_reuse_lo_p when no GPR destination is needed. +(define_insn "mulsi3_lo" + [(set (match_operand:SI 0 "mep_lo_operand" "=l") + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))) + (clobber (match_scratch:SI 3 "=h"))] + "TARGET_OPT_MULT && reload_completed" + "mul\\t%1, %2" + [(set_attr "length" "2") + (set_attr "stall" "mul")]) + +;; Generated by mep_reuse_lo_p when both destinations of a mulr +;; are needed. +(define_insn "mulsi3r" + [(set (match_operand:SI 0 "mep_lo_operand" "=l") + (mult:SI (match_operand:SI 2 "register_operand" "1") + (match_operand:SI 3 "register_operand" "r"))) + (set (match_operand:SI 1 "register_operand" "=r") + (mult:SI (match_dup 2) + (match_dup 3))) + (clobber (match_scratch:SI 4 "=h"))] + "TARGET_OPT_MULT && reload_completed" + "mulr\\t%2, %3" + [(set_attr "length" "2") + (set_attr "stall" "mulr")]) + +(define_insn "mulsi3_1" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "register_operand" "r"))) + (clobber (match_scratch:SI 3 "=l")) + (clobber (match_scratch:SI 4 "=h"))] + "TARGET_OPT_MULT" + "mulr\\t%1, %2" + [(set_attr "length" "2") + (set_attr "stall" "mulr")]) + +(define_expand "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "")) + (sign_extend:DI (match_operand:SI 2 "register_operand" ""))))] + "TARGET_OPT_MULT" + " +{ + rtx hi = gen_reg_rtx (SImode); + rtx lo = gen_reg_rtx (SImode); + + emit_insn (gen_mulsidi3_i (hi, lo, operands[1], operands[2])); + emit_move_insn (gen_lowpart (SImode, operands[0]), lo); + emit_move_insn (gen_highpart (SImode, operands[0]), hi); + DONE; +}") + +(define_insn "mulsidi3_i" + [(set (match_operand:SI 0 "mep_hi_operand" "=h") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI + (match_operand:SI 2 "register_operand" "r")) + (sign_extend:DI + (match_operand:SI 3 "register_operand" "r"))) + (const_int 32)))) + (set (match_operand:SI 1 "mep_lo_operand" "=l") + (mult:SI (match_dup 2) + (match_dup 3)))] + "TARGET_OPT_MULT" + "mul\\t%2, %3" + [(set_attr "length" "2") + (set_attr "stall" "mul")]) + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "mep_hi_operand" "=h") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI + (match_operand:SI 1 "register_operand" "r")) + (sign_extend:DI + (match_operand:SI 2 "register_operand" "r"))) + (const_int 32)))) + (clobber (reg:SI LO_REGNO))] + "TARGET_OPT_MULT" + "mul\\t%1, %2" + [(set_attr "length" "2") + (set_attr "stall" "mul")]) + +(define_expand "umulsidi3" + [(set (match_operand:DI 0 "mep_hi_operand" "") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "")) + (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))] + "TARGET_OPT_MULT" + " +{ + rtx hi = gen_reg_rtx (SImode); + rtx lo = gen_reg_rtx (SImode); + + emit_insn (gen_umulsidi3_i (hi, lo, operands[1], operands[2])); + emit_move_insn (gen_lowpart (SImode, operands[0]), lo); + emit_move_insn (gen_highpart (SImode, operands[0]), hi); + DONE; +}") + +(define_insn "umulsidi3_i" + [(set (match_operand:SI 0 "mep_hi_operand" "=h") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI + (match_operand:SI 2 "register_operand" "r")) + (zero_extend:DI + (match_operand:SI 3 "register_operand" "r"))) + (const_int 32)))) + (set (match_operand:SI 1 "mep_lo_operand" "=l") + (mult:SI (match_dup 2) + (match_dup 3)))] + "TARGET_OPT_MULT" + "mulu\\t%2, %3" + [(set_attr "length" "2") + (set_attr "stall" "mul")]) + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "mep_hi_operand" "=h") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI + (match_operand:SI 1 "register_operand" "r")) + (zero_extend:DI + (match_operand:SI 2 "register_operand" "r"))) + (const_int 32)))) + (clobber (reg:SI LO_REGNO))] + "TARGET_OPT_MULT" + "mulu %1, %2" + [(set_attr "length" "2") + (set_attr "stall" "mul")]) + +;; These two don't currently match because we don't have an adddi3 pattern. +(define_insn "*smultdi_and_add" + [(set (match_operand:DI 0 "mep_hi_operand" "=d") + (plus:DI (mult:DI (zero_extend:DI + (match_operand:SI 1 "register_operand" "r")) + (zero_extend:DI + (match_operand:SI 2 "register_operand" "r"))) + (match_operand:DI 3 "mep_hi_operand" "0")))] + "TARGET_OPT_MULT && TARGET_BIG_ENDIAN" + "maddu\\t%1, %2" + [(set_attr "length" "4") + (set_attr "stall" "mul")]) + +(define_insn "*umultdi_and_add" + [(set (match_operand:DI 0 "mep_hi_operand" "=d") + (plus:DI (mult:DI (sign_extend:DI + (match_operand:SI 1 "register_operand" "r")) + (sign_extend:DI + (match_operand:SI 2 "register_operand" "r"))) + (match_operand:DI 3 "mep_hi_operand" "0")))] + "TARGET_OPT_MULT && TARGET_BIG_ENDIAN" + "madd\\t%1, %2" + [(set_attr "length" "4") + (set_attr "stall" "mul")]) + +;; A pattern for 'r1 = r2 * r3 + r4'. There are three possible +;; implementations: +;; +;; (1) 'mulr;add3'. This is usually the best choice if the instruction +;; is not part of a natural multiply-accumulate chain. It has the +;; same latency as 'stc;maddr' but doesn't tie up $lo for as long. +;; +;; (2) 'madd'. This is the best choice if the instruction is in the +;; middle of a natural multiply-accumulate chain. r4 will already +;; be in $lo and r1 will also be needed in $lo. +;; +;; (3) 'maddr'. This is the best choice if the instruction is at the +;; end of a natural multiply-accumulate chain. r4 will be in $lo +;; but r1 will be needed in a GPR. +;; +;; In theory, we could put all the alternatives into a single pattern and +;; leave the register allocator to choose between them. However, this can +;; sometimes produce poor results in practice. +;; +;; This pattern therefore describes a general GPR-to-GPR operation that +;; has a slight preference for cases in which operands 0 and 1 are tied. +;; After reload, we try to rewrite the patterns using peephole2s (if +;; enabled), falling back on define_splits if that fails. See also +;; mep_reuse_lo_p. +(define_insn "maddsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "%0,r") + (match_operand:SI 2 "register_operand" "r,r")) + (match_operand:SI 3 "register_operand" "r,r"))) + (clobber (match_scratch:SI 4 "=l,l")) + (clobber (match_scratch:SI 5 "=h,h"))] + "TARGET_OPT_MULT" + "#" + [(set_attr "length" "8") + (set_attr "stall" "mulr")]) + +;; Implement maddsi3s using maddr if operand 3 is already available in $lo. +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" "")) + (match_operand:SI 3 "register_operand" ""))) + (clobber (match_scratch:SI 4 "")) + (clobber (match_scratch:SI 5 ""))])] + "TARGET_OPT_MULT + && reload_completed + && mep_reuse_lo_p (operands[4], operands[3], insn, + !rtx_equal_p (operands[1], operands[3]) + && !rtx_equal_p (operands[2], operands[3]) + && (rtx_equal_p (operands[0], operands[3]) + || peep2_reg_dead_p (1, operands[3])))" + [(parallel + [(set (match_dup 4) + (plus:SI (mult:SI (match_dup 0) + (match_dup 2)) + (match_dup 4))) + (set (match_dup 0) + (plus:SI (mult:SI (match_dup 0) + (match_dup 2)) + (match_dup 4))) + (clobber (match_dup 5))])] + "operands[2] = mep_mulr_source (0, operands[0], operands[1], operands[2]);") + +;; This splitter implements maddsi3 as "mulr;add3". It only works if +;; operands 0 and 3 are distinct, since operand 0 is clobbered before +;; operand 3 is used. +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" "")) + (match_operand:SI 3 "register_operand" ""))) + (clobber (match_scratch:SI 4 "")) + (clobber (match_scratch:SI 5 ""))] + "TARGET_OPT_MULT + && reload_completed + && !rtx_equal_p (operands[0], operands[3])" + [(parallel [(set (match_dup 0) + (mult:SI (match_dup 0) + (match_dup 2))) + (clobber (match_dup 4)) + (clobber (match_dup 5))]) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 3)))] + "operands[2] = mep_mulr_source (0, operands[0], operands[1], operands[2]);") + +;; This is the fallback splitter for maddsi3. It moves operand 3 into +;; $lo and then uses maddr. +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" "")) + (match_operand:SI 3 "register_operand" ""))) + (clobber (match_scratch:SI 4 "")) + (clobber (match_scratch:SI 5 ""))] + "TARGET_OPT_MULT + && reload_completed" + [(parallel [(set (match_dup 4) + (plus:SI (mult:SI (match_dup 0) + (match_dup 2)) + (match_dup 4))) + (set (match_dup 0) + (plus:SI (mult:SI (match_dup 0) + (match_dup 2)) + (match_dup 4))) + (clobber (match_dup 5))])] +{ + emit_move_insn (operands[4], operands[3]); + operands[2] = mep_mulr_source (0, operands[0], operands[1], operands[2]); +}) + +;; Remove unnecessary stcs to $lo. This cleans up the moves generated +;; by earlier calls to mep_reuse_lo_p. +(define_peephole2 + [(set (match_operand:SI 0 "mep_lo_operand" "") + (match_operand:SI 1 "register_operand" ""))] + "TARGET_OPT_MULT + && mep_reuse_lo_p (operands[0], operands[1], insn, + peep2_reg_dead_p (1, operands[1]))" + [(const_int 0)] +{ + emit_note (NOTE_INSN_DELETED); + DONE; +}) + +(define_insn "maddsi3_lo" + [(set (match_operand:SI 0 "mep_lo_operand" "=l") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "mep_lo_operand" "0"))) + (clobber (match_scratch:SI 4 "=h"))] + "TARGET_OPT_MULT && reload_completed" + "madd\\t%1, %2" + [(set_attr "length" "4") + (set_attr "stall" "mul")]) + +(define_insn "maddsi3r" + [(set (match_operand:SI 0 "mep_lo_operand" "=l") + (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "1") + (match_operand:SI 3 "register_operand" "r")) + (match_operand:SI 4 "register_operand" "0"))) + (set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (mult:SI (match_dup 2) + (match_dup 3)) + (match_dup 4))) + (clobber (match_scratch:SI 5 "=h"))] + "TARGET_OPT_MULT && reload_completed" + "maddr\\t%2, %3" + [(set_attr "length" "4") + (set_attr "stall" "mulr")]) + +(define_insn "*shift_1_or_2_and_add" + [(set (match_operand:SI 0 "mep_r0_operand" "=z") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "mep_slad_operand" "n")) + (match_operand:SI 3 "register_operand" "r")))] + "" + "sl%b2ad3\\t%0, %1, %3" + [(set_attr "length" "2") + (set_attr "stall" "int2")]) + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "mep_lo_operand" "=l") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))) + (set (match_operand:SI 3 "mep_hi_operand" "=h") + (mod:SI (match_dup 1) + (match_dup 2)))] + "TARGET_OPT_DIV" + "div\\t%1, %2" + [(set_attr "length" "2") + (set_attr "stall" "div") + (set_attr "may_trap" "yes")]) + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "mep_lo_operand" "=l") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))) + (set (match_operand:SI 3 "mep_hi_operand" "=h") + (umod:SI (match_dup 1) + (match_dup 2)))] + "TARGET_OPT_DIV" + "divu\\t%1, %2" + [(set_attr "length" "2") + (set_attr "stall" "div") + (set_attr "may_trap" "yes")]) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "neg\\t%0, %1" + [(set_attr "length" "2")]) + +;; We have "absolute difference between two regs" which isn't quite +;; what gcc is expecting. +(define_expand "abssi2" + [(set (match_dup 2) (const_int 0)) + (set (match_operand:SI 0 "register_operand" "") + (abs:SI (minus:SI (match_operand:SI 1 "register_operand" "") + (match_dup 2)) + ))] + "TARGET_OPT_ABSDIFF" + "operands[2] = gen_reg_rtx (SImode);") + +(define_insn "*absdiff" + [(set (match_operand:SI 0 "register_operand" "=r") + (abs:SI (minus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r"))))] + "TARGET_OPT_ABSDIFF" + "abs\\t%0, %2" + [(set_attr "length" "4")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (abs:SI (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "immediate_operand" "")))) + (clobber (match_operand:SI 3 "register_operand" ""))] + "!reload_completed" + [(set (match_dup 3) + (match_dup 4)) + (set (match_operand:SI 0 "register_operand" "") + (abs:SI (minus:SI (match_operand:SI 1 "register_operand" "") + (match_dup 3))))] + "operands[4] = GEN_INT (-INTVAL (operands[2]));") + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (smin:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "r")))] + "TARGET_OPT_MINMAX" + "min\\t%0, %2" + [(set_attr "length" "4")]) + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (smax:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "r")))] + "TARGET_OPT_MINMAX" + "max\\t%0, %2" + [(set_attr "length" "4")]) + +(define_insn "uminsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umin:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "r")))] + "TARGET_OPT_MINMAX" + "minu\\t%0, %2" + [(set_attr "length" "4")]) + +(define_insn "umaxsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umax:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "r")))] + "TARGET_OPT_MINMAX" + "maxu\\t%0, %2" + [(set_attr "length" "4")]) + +;; Average: a = (b+c+1)>>1 +(define_insn "*averagesi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (plus:SI (plus:SI + (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "register_operand" "r")) + (const_int 1)) + (const_int 1)))] + "TARGET_OPT_AVERAGE" + "ave\\t%0, %2" + [(set_attr "length" "4")]) + +;; clip support + +(define_insn "clip_maxmin" + [(set (match_operand:SI 0 "register_operand" "=r") + (smax:SI (smin:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "n")) + (match_operand:SI 3 "immediate_operand" "n")))] + "mep_allow_clip (operands[2], operands[3], 1)" + "clip\\t%0, %B2" + [(set_attr "length" "4")]) + +(define_insn "clip_minmax" + [(set (match_operand:SI 0 "register_operand" "=r") + (smin:SI (smax:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "n")) + (match_operand:SI 3 "immediate_operand" "n")))] + "mep_allow_clip (operands[3], operands[2], 1)" + "clip\\t%0, %B3" + [(set_attr "length" "4")]) + +(define_insn "clipu_maxmin" + [(set (match_operand:SI 0 "register_operand" "=r") + (smax:SI (smin:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "n")) + (match_operand:SI 3 "immediate_operand" "n")))] + "mep_allow_clip (operands[2], operands[3], 0)" + "clipu\\t%0, %U2" + [(set_attr "length" "4")]) + +(define_insn "clipu_minmax" + [(set (match_operand:SI 0 "register_operand" "=r") + (smin:SI (smax:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "n")) + (match_operand:SI 3 "immediate_operand" "n")))] + "mep_allow_clip (operands[3], operands[2], 0)" + "clipu\\t%0, %U3" + [(set_attr "length" "4")]) + +;; :::::::::::::::::::: +;; :: +;; :: 32 bit Integer Shifts and Rotates +;; :: +;; :::::::::::::::::::: + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,z") + (ashift:SI (match_operand:SI 1 "register_operand" "0,r") + (match_operand:SI 2 "nonmemory_operand" "rM,M")))] + "" + "@ + sll\\t%0, %2 + sll3\\t%0, %1, %2" + [(set_attr "length" "2,2") + (set_attr "shiftop" "operand2")]) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "rM")))] + "" + "sra\\t%0, %2" + [(set_attr "length" "2") + (set_attr "shiftop" "operand2")]) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "rM")))] + "" + "srl\\t%0, %2" + [(set_attr "length" "2") + (set_attr "shiftop" "operand2")]) + +;; :::::::::::::::::::: +;; :: +;; :: 32 Bit Integer Logical operations +;; :: +;; :::::::::::::::::::: + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,r") + (match_operand:SI 2 "nonmemory_operand" "r,J")))] + "" + "@ + and\\t%0, %2 + and3\\t%0, %1, %J2" + [(set_attr "length" "2,4")]) + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,r") + (match_operand:SI 2 "nonmemory_operand" "r,J")))] + "" + "@ + or\\t%0, %2 + or3\\t%0, %1, %J2" + [(set_attr "length" "2,4")]) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,r") + (match_operand:SI 2 "nonmemory_operand" "r,J")))] + "" + "@ + xor\\t%0, %2 + xor3\\t%0, %1, %J2" + [(set_attr "length" "2,4")]) + +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "") + (not:SI (match_operand:SI 1 "register_operand" "")))] + "" + "operands[2] = operands[1]; + ") + +;; No separate insn for this; use NOR +(define_insn "*one_cmplsi3_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "0")))] + "" + "nor\\t%0, %0" + [(set_attr "length" "2")]) + +;; :::::::::::::::::::: +;; :: +;; :: Bit Manipulation +;; :: +;; :::::::::::::::::::: + +(define_insn "*bitop_be" + [(set (match_operand:QI 0 "mep_Y_operand" "=Y") + (subreg:QI (match_operator:SI 3 "mep_bit_operator" + [(subreg:SI (match_operand:QI 1 "mep_Y_operand" "0") 0) + (match_operand 2 "immediate_operand" "n")]) + 3) + )] + "TARGET_BIG_ENDIAN && TARGET_OPT_BITOPS + && rtx_equal_p (operands[0], operands[1])" + "b%L3m\\t%0, %b2" + [(set_attr "length" "2")]) + +(define_insn "*bitop_le" + [(set (match_operand:QI 0 "mep_Y_operand" "=Y") + (subreg:QI (match_operator:SI 3 "mep_bit_operator" + [(subreg:SI (match_operand:QI 1 "mep_Y_operand" "0") 0) + (match_operand 2 "immediate_operand" "n")]) + 0) + )] + "!TARGET_BIG_ENDIAN && TARGET_OPT_BITOPS + && rtx_equal_p (operands[0], operands[1])" + "b%L3m\\t%0, %b2" + [(set_attr "length" "2")]) + +(define_insn "btstm" + [(set (match_operand:SI 0 "mep_r0_operand" "=z") + (and:SI (subreg:SI (match_operand:QI 1 "mep_Y_operand" "Y") 0) + (match_operand 2 "immediate_operand" "n")) + )] + "TARGET_OPT_BITOPS && mep_bit_position_p (operands[2], 1)" + "btstm\\t%0, %1, %b2" + [(set_attr "length" "2")]) + +(define_insn "tas" + [(parallel [(set (match_operand:SI 0 "mep_r0_operand" "=z") + (zero_extend:SI (match_operand:QI 1 "mep_Y_operand" "+Y"))) + (set (match_dup 1) + (const_int 1)) + ] + )] + "TARGET_OPT_BITOPS" + "tas\\t%0, %1" + [(set_attr "length" "2")]) + +(define_peephole2 + [(set (match_operand:SI 0 "mep_r0_operand" "") + (zero_extend:SI (match_operand:QI 1 "mep_Y_operand" ""))) + (set (match_operand:QI 2 "register_operand" "") + (const_int 1)) + (set (match_dup 1) + (match_dup 2)) + ] + "TARGET_OPT_BITOPS" + [(parallel [(set (match_dup 0) + (zero_extend:SI (match_dup 1))) + (set (match_dup 1) + (const_int 1)) + ])] + "") + +(define_peephole2 + [(set (match_operand:SI 0 "mep_r0_operand" "") + (sign_extend:SI (match_operand:QI 1 "mep_Y_operand" ""))) + (set (match_operand:QI 2 "register_operand" "") + (const_int 1)) + (set (match_dup 1) + (match_dup 2)) + ] + "TARGET_OPT_BITOPS" + [(parallel [(set (match_dup 0) + (zero_extend:SI (match_dup 1))) + (set (match_dup 1) + (const_int 1)) + ]) + (set (match_dup 0) + (sign_extend:SI (match_dup 3)))] + "operands[3] = gen_lowpart (QImode, operands[0]);") + + +;; :::::::::::::::::::: +;; :: +;; :: Conditional branches and stores +;; :: +;; :::::::::::::::::::: + +(define_expand "cbranchsi4" + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "emit_jump_insn (gen_branch_true (operands[3], + mep_expand_cbranch (operands))); + DONE;") + +(define_expand "branch_true" + [(set (pc) + (if_then_else (match_operand 1 "" "") + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "") + +(define_expand "cstoresi4" + [(set (match_operand:SI 0 "register_operand" "") + (match_operator:SI 1 "ordered_comparison_operator" + [(match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "nonmemory_operand" "")]))] + "" + "if (mep_expand_setcc (operands)) DONE; else FAIL;") + +;; ------------------------------------------------------------ + +(define_insn "*slt" + [(set (match_operand:SI 0 "register_operand" "=z,z,r") + (lt:SI (match_operand:SI 1 "register_operand" "r,r,r") + (match_operand:SI 2 "nonmemory_operand" "r,M,I")))] + "" + "slt3\\t%0, %1, %2" + [(set_attr "length" "2,2,4")]) + +(define_insn "*sltu" + [(set (match_operand:SI 0 "register_operand" "=z,z,r") + (ltu:SI (match_operand:SI 1 "register_operand" "r,r,r") + (match_operand:SI 2 "nonmemory_operand" "r,M,J")))] + "" + "sltu3\\t%0, %1, %2" + [(set_attr "length" "2,2,4")]) + +(define_insn "*bcpeq_true" + [(set (pc) + (if_then_else (eq:SI (reg:SI CBCR_REGNO) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bcpeq\t0, %l0" + [(set_attr "length" "4")]) + +(define_insn "*bcpeq_false" + [(set (pc) + (if_then_else (eq:SI (reg:SI CBCR_REGNO) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bcpne\t0, %l0" + [(set_attr "length" "4")]) + +(define_insn "*bcpne_true" + [(set (pc) + (if_then_else (ne:SI (reg:SI CBCR_REGNO) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bcpne\t0, %l0" + [(set_attr "length" "4")]) + +(define_insn "*bcpne_false" + [(set (pc) + (if_then_else (ne:SI (reg:SI CBCR_REGNO) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bcpeq\t0, %l0" + [(set_attr "length" "4")]) + +;; ??? The lengths here aren't correct, since no attempt it made to +;; find "beqz" in the 256-byte range. However, this should not affect +;; bundling, since we never run core branches in parallel. + +(define_insn "mep_beq_true" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "mep_reg_or_imm4_operand" "rN")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "* return mep_emit_cbranch (operands, 0);" + [(set_attr "length" "4")] ) + +(define_insn "*beq_false" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "mep_reg_or_imm4_operand" "rN")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "* return mep_emit_cbranch (operands, 1);" + [(set_attr "length" "4")]) + +(define_insn "mep_bne_true" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "mep_reg_or_imm4_operand" "rN")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "* return mep_emit_cbranch (operands, 1); " + [(set_attr "length" "4")]) + +(define_insn "*bne_false" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "mep_reg_or_imm4_operand" "rN")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "* return mep_emit_cbranch (operands, 0); " + [(set_attr "length" "4")]) + +(define_insn "mep_blti" + [(set (pc) + (if_then_else (lt (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "mep_imm4_operand" "N")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "blti\\t%0, %1, %l2" + [(set_attr "length" "4")]) + +(define_insn "*bgei" + [(set (pc) + (if_then_else (ge (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "mep_imm4_operand" "N")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bgei\\t%0, %1, %l2" + [(set_attr "length" "4")]) + +;; :::::::::::::::::::: +;; :: +;; :: Call and branch instructions +;; :: +;; :::::::::::::::::::: + +(define_expand "call" + [(parallel [(call (match_operand:QI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" "")) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ])] + "" + " +{ + mep_expand_call (operands, 0); + DONE; +}") + +(define_insn "call_internal" + [(call (mem (match_operand:SI 0 "mep_call_address_operand" "R,r")) + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_operand:SI 3 "mep_tp_operand" "b,b")) + (use (match_operand:SI 4 "mep_gp_operand" "v,v")) + (clobber (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ] + "" +{ + static char const pattern[2][2][8] = + { + { "bsrv\t%0", "jsrv\t%0" }, + { "bsr\t%0", "jsr\t%0" } + }; + + return pattern[mep_vliw_mode_match (operands[2])][which_alternative]; +} + [(set_attr "length" "4,2")]) + +(define_expand "sibcall" + [(parallel [(call (match_operand:QI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" "")) + (use (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ])] + "" + "") + +(define_insn "*sibcall_internal" + [(call (mem (match_operand:SI 0 "mep_nearsym_operand" "s")) + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ] + "SIBLING_CALL_P (insn)" +{ + if (mep_vliw_jmp_match (operands[2])) + return "jmp\t%0"; + else if (mep_vliw_mode_match (operands[2])) + return + "movu $0, %0\n\ + jmp $0"; + else + return + "ldc $12, $lp\n\ + movh $11, %%hi(%0)\n\ + xor3 $12, $12, 1\n\ + add3 $11, $11, %%lo(%0+1)\n\ + stc $12, $lp\n\ + jmp $11"; +} + [(set_attr "length" "48") + (set_attr "slot" "multi")]) + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "" "") + (match_operand:SI 2 "" ""))) + (use (match_operand:SI 3 "" "")) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ])] + "" + " +{ + mep_expand_call (operands, 1); + DONE; +}") + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=rx,rx") + (call (mem:SI (match_operand:SI 1 "mep_call_address_operand" "R,r")) + (match_operand:SI 2 "" ""))) + (use (match_operand:SI 3 "const_int_operand" "")) + (use (match_operand:SI 4 "mep_tp_operand" "b,b")) + (use (match_operand:SI 5 "mep_gp_operand" "v,v")) + (clobber (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ] + "" +{ + static char const pattern[2][2][8] = + { + { "bsrv\t%1", "jsrv\t%1" }, + { "bsr\t%1", "jsr\t%1" } + }; + + return pattern[mep_vliw_mode_match (operands[3])][which_alternative]; +} + [(set_attr "length" "4,2")]) + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "" "") + (match_operand:SI 2 "" ""))) + (use (match_operand:SI 3 "" "")) + (use (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ])] + "" + "") + +(define_insn "*sibcall_value_internal" + [(set (match_operand 0 "register_operand" "=rx") + (call (mem (match_operand:SI 1 "mep_nearsym_operand" "s")) + (match_operand:SI 2 "" ""))) + (use (match_operand:SI 3 "const_int_operand" "")) + (use (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ] + "SIBLING_CALL_P (insn)" +{ + if (mep_vliw_jmp_match (operands[3])) + return "jmp\t%1"; + else if (mep_vliw_mode_match (operands[3])) + return + "movu $0, %1\n\ + jmp $0"; + else + return + "ldc $12, $lp\n\ + movh $11, %%hi(%1)\n\ + xor3 $12, $12, 1\n\ + add3 $11, $11, %%lo(%1+1)\n\ + stc $12, $lp\n\ + jmp $11"; +} + [(set_attr "length" "48") + (set_attr "slot" "multi")]) + +(define_insn "return_internal" + [(return) + (use (match_operand:SI 0 "register_operand" ""))] + "" + "* return (REGNO (operands[0]) == LP_REGNO) ? \"ret\" : \"jmp\\t%0\";" + [(set_attr "length" "2") + (set_attr "stall" "ret")]) + +(define_insn "eh_return_internal" + [(return) + (use (reg:SI 10)) + (use (reg:SI 11)) + (use (reg:SI LP_REGNO)) + (clobber (reg:SI REGSAVE_CONTROL_TEMP)) + ] + "" + "ret" + [(set_attr "length" "2") + (set_attr "stall" "ret")]) + +;; The assembler replaces short jumps with long jumps as needed. +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "bra\\t%l0" + [(set_attr "length" "4")]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp\\t%0" + [(set_attr "length" "2")]) + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp\\t%0" + [(set_attr "length" "2")]) + + +;; :::::::::::::::::::: +;; :: +;; :: Low Overhead Looping +;; :: +;; :::::::::::::::::::: + +;; This insn is volatile because we'd like it to stay in its original +;; position, just before the loop header. If it stays there, we might +;; be able to convert it into a "repeat" insn. +(define_insn "doloop_begin_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI + [(match_operand:SI 1 "register_operand" "0") + (match_operand 2 "const_int_operand" "")] UNS_REPEAT_BEG))] + "" + { gcc_unreachable (); } + [(set_attr "length" "4")]) + +(define_expand "doloop_begin" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand:QI 1 "const_int_operand" "")) + (use (match_operand:QI 2 "const_int_operand" "")) + (use (match_operand:QI 3 "const_int_operand" ""))] + "!profile_arc_flag && TARGET_OPT_REPEAT" + "if (INTVAL (operands[3]) > 1) + FAIL; + mep_emit_doloop (operands, 0); + DONE; + ") + +(define_insn "doloop_end_internal" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "nonimmediate_operand" "+r,cxy,*m") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1))) + (unspec [(match_operand 2 "const_int_operand" "")] UNS_REPEAT_END) + (clobber (match_scratch:SI 3 "=X,&r,&r"))] + "" + { gcc_unreachable (); } + ;; Worst case length: + ;; + ;; lw , 4 + ;; add ,-1 2 + ;; sw , 4 + ;; jmp 4 + ;; 1f: + [(set_attr "length" "14") + (set_attr "slot" "multi")]) + +(define_expand "doloop_end" + [(use (match_operand 0 "nonimmediate_operand" "")) + (use (match_operand:QI 1 "const_int_operand" "")) + (use (match_operand:QI 2 "const_int_operand" "")) + (use (match_operand:QI 3 "const_int_operand" "")) + (use (label_ref (match_operand 4 "" "")))] + "!profile_arc_flag && TARGET_OPT_REPEAT" + "if (INTVAL (operands[3]) > 1) + FAIL; + if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode) + FAIL; + mep_emit_doloop (operands, 1); + DONE; + ") + +(define_insn "repeat" + [(set (reg:SI RPC_REGNO) + (unspec:SI [(match_operand:SI 0 "mep_r0_15_operand" "r") + (match_operand:SI 1 "" "")] + UNS_REPEAT_BEG))] + "" + "repeat\\t%0,%l1" + [(set_attr "length" "4")]) + +(define_insn "repeat_end" + [(unspec [(const_int 0)] UNS_REPEAT_END)] + "" + "# repeat end" + [(set_attr "length" "0")]) + +(define_insn "erepeat" + [(unspec [(match_operand 0 "" "")] UNS_EREPEAT_BEG)] + "" + "erepeat\\t%l0" + [(set_attr "length" "4")]) + +(define_insn "erepeat_end" + [(unspec [(const_int 0)] UNS_EREPEAT_END)] + "" + "# erepeat end" + [(set_attr "length" "0") + (set_attr "slot" "multi")]) + + +;; :::::::::::::::::::: +;; :: +;; :: Prologue and Epilogue instructions +;; :: +;; :::::::::::::::::::: + +(define_expand "prologue" + [(const_int 1)] + "" + " +{ + mep_expand_prologue (); + DONE; +}") + +(define_expand "epilogue" + [(return)] + "" + " +{ + mep_expand_epilogue (); + DONE; +}") + +(define_expand "eh_return" + [(use (match_operand:SI 0 "register_operand" "r"))] + "" + " +{ + mep_expand_eh_return (operands); + DONE; +}") + +(define_insn_and_split "eh_epilogue" + [(unspec [(match_operand:SI 0 "register_operand" "r")] UNS_EH_EPILOGUE) + (use (reg:SI LP_REGNO))] + "" + "#" + "epilogue_completed" + [(const_int 1)] + "mep_emit_eh_epilogue (operands); DONE;" + [(set_attr "slot" "multi")]) + +(define_expand "sibcall_epilogue" + [(const_int 0)] + "" + " +{ + mep_expand_sibcall_epilogue (); + DONE; +}") + +(define_insn "mep_bb_trace_ret" + [(unspec_volatile [(const_int 0)] UNS_BB_TRACE_RET)] + "" + "* return mep_emit_bb_trace_ret ();" + [(set_attr "slot" "multi")]) + +(define_insn "mep_disable_int" + [(unspec_volatile [(const_int 0)] UNS_DISABLE_INT)] + "" + "di" + [(set_attr "length" "2")]) + +(define_insn "mep_enable_int" + [(unspec_volatile [(const_int 0)] UNS_ENABLE_INT)] + "" + "ei" + [(set_attr "length" "2")]) + +(define_insn "mep_reti" + [(return) + (unspec_volatile [(const_int 0)] UNS_RETI)] + "" + "reti" + [(set_attr "length" "2")]) + +;; :::::::::::::::::::: +;; :: +;; :: Miscellaneous instructions +;; :: +;; :::::::::::::::::::: + +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "length" "2")]) + +(define_insn "nop32" + [(const_int 1)] + "" + "or3\\t$0, $0, 0" + [(set_attr "length" "4")]) + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNS_BLOCKAGE)] + "" + "" + [(set_attr "length" "0") + (set_attr "slot" "multi")]) + + +(define_insn "djmark" + [(unspec_volatile [(const_int 0)] 999)] + "" + "# dj" + [(set_attr "length" "0") + (set_attr "slot" "multi")]) + -- cgit v1.2.3