| ;; Machine description for TI C6X. |
| ;; Copyright (C) 2010-2021 Free Software Foundation, Inc. |
| ;; Contributed by Andrew Jenner <andrew@codesourcery.com> |
| ;; Contributed by Bernd Schmidt <bernds@codesourcery.com> |
| ;; Contributed by CodeSourcery. |
| ;; |
| ;; This file is part of GCC. |
| ;; |
| ;; GCC is free software; you can redistribute it and/or modify |
| ;; it under the terms of the GNU General Public License as published by |
| ;; the Free Software Foundation; either version 3, or (at your option) |
| ;; any later version. |
| ;; |
| ;; GCC is distributed in the hope that it will be useful, |
| ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ;; GNU General Public License for more details. |
| ;; |
| ;; You should have received a copy of the GNU General Public License |
| ;; along with GCC; see the file COPYING3. If not see |
| ;; <http://www.gnu.org/licenses/>. |
| |
| |
| ;; Register names |
| |
| (define_constants |
| [(REG_A0 0) |
| (REG_A1 1) |
| (REG_A2 2) |
| (REG_A3 3) |
| (REG_A4 4) |
| (REG_A5 5) |
| (REG_A6 6) |
| (REG_A7 7) |
| (REG_A8 8) |
| (REG_A9 9) |
| (REG_A10 10) |
| (REG_A11 11) |
| (REG_A12 12) |
| (REG_A13 13) |
| (REG_A14 14) |
| (REG_A15 15) |
| (REG_A16 16) |
| (REG_A17 17) |
| (REG_A18 18) |
| (REG_A19 19) |
| (REG_A20 20) |
| (REG_A21 21) |
| (REG_A22 22) |
| (REG_A23 23) |
| (REG_A24 24) |
| (REG_A25 25) |
| (REG_A26 26) |
| (REG_A27 27) |
| (REG_A28 28) |
| (REG_A29 29) |
| (REG_A30 30) |
| (REG_A31 31) |
| (REG_B0 32) |
| (REG_B1 33) |
| (REG_B2 34) |
| (REG_B3 35) |
| (REG_B4 36) |
| (REG_B5 37) |
| (REG_B6 38) |
| (REG_B7 39) |
| (REG_B8 40) |
| (REG_B9 41) |
| (REG_B10 42) |
| (REG_B11 43) |
| (REG_B12 44) |
| (REG_B13 45) |
| (REG_B14 46) |
| (REG_SP 47) |
| (REG_B15 47) |
| (REG_B16 48) |
| (REG_B17 49) |
| (REG_B18 50) |
| (REG_B19 51) |
| (REG_B20 52) |
| (REG_B21 53) |
| (REG_B22 54) |
| (REG_B23 55) |
| (REG_B24 56) |
| (REG_B25 57) |
| (REG_B26 58) |
| (REG_B27 59) |
| (REG_B28 60) |
| (REG_B29 61) |
| (REG_B30 62) |
| (REG_B31 63) |
| (REG_FRAME 64) |
| (REG_ARGP 65) |
| (REG_ILC 66)]) |
| |
| (define_c_enum "unspec" [ |
| UNSPEC_NOP |
| UNSPEC_RCP |
| UNSPEC_MISALIGNED_ACCESS |
| UNSPEC_ADDKPC |
| UNSPEC_SETUP_DSBT |
| UNSPEC_LOAD_GOT |
| UNSPEC_LOAD_SDATA |
| UNSPEC_BITREV |
| UNSPEC_GOTOFF |
| UNSPEC_MVILC |
| UNSPEC_REAL_JUMP |
| UNSPEC_REAL_LOAD |
| UNSPEC_REAL_MULT |
| UNSPEC_JUMP_SHADOW |
| UNSPEC_LOAD_SHADOW |
| UNSPEC_MULT_SHADOW |
| UNSPEC_EPILOGUE_BARRIER |
| UNSPEC_ATOMIC |
| UNSPEC_CLR |
| UNSPEC_EXT |
| UNSPEC_EXTU |
| UNSPEC_SUBC |
| UNSPEC_AVG |
| ]) |
| |
| (define_c_enum "unspecv" [ |
| UNSPECV_BLOCKAGE |
| UNSPECV_SPLOOP |
| UNSPECV_SPKERNEL |
| UNSPECV_EH_RETURN |
| UNSPECV_CAS |
| ]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Instruction attributes |
| ;; ------------------------------------------------------------------------- |
| |
| (define_attr "cpu" |
| "c62x,c64x,c64xp,c67x,c67xp,c674x" |
| (const (symbol_ref "(enum attr_cpu)c6x_arch"))) |
| |
| ;; Define a type for each insn which is used in the scheduling description. |
| ;; These correspond to the types defined in chapter 4 of the C674x manual. |
| (define_attr "type" |
| "unknown,single,mpy2,store,storen,mpy4,load,loadn,branch,call,callp,dp2,fp4, |
| intdp,cmpdp,adddp,mpy,mpyi,mpyid,mpydp,mpyspdp,mpysp2dp,spkernel,sploop, |
| mvilc,blockage,shadow,load_shadow,mult_shadow,atomic" |
| (const_string "single")) |
| |
| ;; The register file used by an instruction's destination register. |
| ;; The function destreg_file computes this; instructions can override the |
| ;; attribute if they aren't a single_set. |
| (define_attr "dest_regfile" |
| "unknown,any,a,b" |
| (cond [(eq_attr "type" "single,load,mpy2,mpy4,dp2,fp4,intdp,cmpdp,adddp,mpy,mpyi,mpyid,mpydp,mpyspdp,mpysp2dp") |
| (cond [(match_operand 0 "a_register" "") (const_string "a") |
| (match_operand 0 "b_register" "") (const_string "b")] |
| (const_string "unknown")) |
| (eq_attr "type" "store") |
| (cond [(match_operand 1 "a_register" "") (const_string "a") |
| (match_operand 1 "b_register" "") (const_string "b")] |
| (const_string "unknown"))] |
| (const_string "unknown"))) |
| |
| (define_attr "addr_regfile" |
| "unknown,a,b" |
| (const_string "unknown")) |
| |
| (define_attr "cross" |
| "n,y" |
| (const_string "n")) |
| |
| ;; This describes the relationship between operands and register files. |
| ;; For example, "sxs" means that operands 0 and 2 determine the side of |
| ;; the machine, and operand 1 can optionally use the cross path. "dt" and |
| ;; "td" are used to describe loads and stores. |
| ;; Used for register renaming in loops for improving modulo scheduling. |
| (define_attr "op_pattern" |
| "unknown,dt,td,sx,sxs,ssx" |
| (cond [(eq_attr "type" "load") (const_string "td") |
| (eq_attr "type" "store") (const_string "dt")] |
| (const_string "unknown"))) |
| |
| (define_attr "has_shadow" |
| "n,y" |
| (const_string "n")) |
| |
| ;; The number of cycles the instruction takes to finish. Any cycles above |
| ;; the first are delay slots. |
| (define_attr "cycles" "" |
| (cond [(eq_attr "type" "branch,call") (const_int 6) |
| (eq_attr "type" "load,loadn") (const_int 5) |
| (eq_attr "type" "dp2") (const_int 2) |
| (eq_attr "type" "mpy2") (const_int 2) |
| (eq_attr "type" "mpy4") (const_int 4) |
| (eq_attr "type" "fp4") (const_int 4) |
| (eq_attr "type" "mvilc") (const_int 4) |
| (eq_attr "type" "cmpdp") (const_int 2) |
| (eq_attr "type" "intdp") (const_int 5) |
| (eq_attr "type" "adddp") (const_int 7) |
| (eq_attr "type" "mpydp") (const_int 10) |
| (eq_attr "type" "mpyi") (const_int 9) |
| (eq_attr "type" "mpyid") (const_int 10) |
| (eq_attr "type" "mpyspdp") (const_int 7) |
| (eq_attr "type" "mpysp2dp") (const_int 5)] |
| (const_int 1))) |
| |
| ;; The number of cycles during which the instruction reserves functional |
| ;; units. |
| (define_attr "reserve_cycles" "" |
| (cond [(eq_attr "type" "cmpdp") (const_int 2) |
| (eq_attr "type" "adddp") (const_int 2) |
| (eq_attr "type" "mpydp") (const_int 4) |
| (eq_attr "type" "mpyi") (const_int 4) |
| (eq_attr "type" "mpyid") (const_int 4) |
| (eq_attr "type" "mpyspdp") (const_int 2)] |
| (const_int 1))) |
| |
| (define_attr "predicable" "no,yes" |
| (const_string "yes")) |
| |
| (define_attr "enabled" "no,yes" |
| (const_string "yes")) |
| |
| ;; Specify which units can be used by a given instruction. Normally, |
| ;; dest_regfile is used to select between the two halves of the machine. |
| ;; D_ADDR is for load/store instructions; they use the D unit and use |
| ;; addr_regfile to choose between D1 and D2. |
| |
| (define_attr "units62" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (const_string "unknown")) |
| |
| (define_attr "units64" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (const_string "unknown")) |
| |
| (define_attr "units64p" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (attr "units64")) |
| |
| (define_attr "units67" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (attr "units62")) |
| |
| (define_attr "units67p" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (attr "units67")) |
| |
| (define_attr "units674" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (attr "units64")) |
| |
| (define_attr "units" |
| "unknown,d,d_addr,l,m,s,dl,ds,dls,ls" |
| (cond [(eq_attr "cpu" "c62x") |
| (attr "units62") |
| (eq_attr "cpu" "c67x") |
| (attr "units67") |
| (eq_attr "cpu" "c67xp") |
| (attr "units67p") |
| (eq_attr "cpu" "c64x") |
| (attr "units64") |
| (eq_attr "cpu" "c64xp") |
| (attr "units64p") |
| (eq_attr "cpu" "c674x") |
| (attr "units674") |
| ] |
| (const_string "unknown"))) |
| |
| (define_automaton "c6x_1,c6x_2,c6x_m1,c6x_m2,c6x_t1,c6x_t2,c6x_branch") |
| (automata_option "no-comb-vect") |
| (automata_option "ndfa") |
| (automata_option "collapse-ndfa") |
| |
| (define_query_cpu_unit "d1,l1,s1" "c6x_1") |
| (define_cpu_unit "x1" "c6x_1") |
| (define_cpu_unit "l1w,s1w" "c6x_1") |
| (define_query_cpu_unit "m1" "c6x_m1") |
| (define_cpu_unit "m1w" "c6x_m1") |
| (define_cpu_unit "t1" "c6x_t1") |
| (define_query_cpu_unit "d2,l2,s2" "c6x_2") |
| (define_cpu_unit "x2" "c6x_2") |
| (define_cpu_unit "l2w,s2w" "c6x_2") |
| (define_query_cpu_unit "m2" "c6x_m2") |
| (define_cpu_unit "m2w" "c6x_m2") |
| (define_cpu_unit "t2" "c6x_t2") |
| ;; A special set of units used to identify specific reservations, rather than |
| ;; just units. |
| (define_query_cpu_unit "fps1,fpl1,adddps1,adddpl1" "c6x_1") |
| (define_query_cpu_unit "fps2,fpl2,adddps2,adddpl2" "c6x_2") |
| |
| ;; There can be up to two branches in one cycle (on the .s1 and .s2 |
| ;; units), but some instructions must not be scheduled in parallel |
| ;; with a branch. We model this by reserving either br0 or br1 for a |
| ;; normal branch, and both of them for an insn such as callp. |
| ;; Another constraint is that two branches may only execute in parallel |
| ;; if one uses an offset, and the other a register. We can distinguish |
| ;; these by the dest_regfile attribute; it is "any" iff the branch uses |
| ;; an offset. br0 is reserved for these, while br1 is reserved for |
| ;; branches using a register. |
| (define_cpu_unit "br0,br1" "c6x_branch") |
| |
| (include "c6x-sched.md") |
| |
| ;; Some reservations which aren't generated from c6x-sched.md.in |
| |
| (define_insn_reservation "branch_s1any" 6 |
| (and (eq_attr "type" "branch") |
| (and (eq_attr "cross" "n") |
| (and (eq_attr "units" "s") |
| (eq_attr "dest_regfile" "any")))) |
| "s1+s1w+br0") |
| |
| ;; For calls, we also reserve the units needed in the following cycles |
| ;; to load the return address. There are two options; using addkpc or |
| ;; mvkh/mvkl. The code in c6x_reorg knows whether to use one of these |
| ;; or whether to use callp. The actual insns are emitted only after |
| ;; the final scheduling pass is complete. |
| ;; We always reserve S2 for PC-relative call insns, since that allows |
| ;; us to turn them into callp insns later on. |
| (define_insn_reservation "call_addkpc_s1any" 6 |
| (and (eq_attr "type" "call") |
| (and (ne (symbol_ref "TARGET_INSNS_64") (const_int 0)) |
| (and (eq_attr "cross" "n") |
| (and (eq_attr "units" "s") |
| (eq_attr "dest_regfile" "any"))))) |
| "s2+s2w+br0,s2+s2w+br0+br1") |
| |
| (define_insn_reservation "call_mvk_s1any" 6 |
| (and (eq_attr "type" "call") |
| (and (eq (symbol_ref "TARGET_INSNS_64") (const_int 0)) |
| (and (eq_attr "cross" "n") |
| (and (eq_attr "units" "s") |
| (eq_attr "dest_regfile" "any"))))) |
| "s2+s2w+br0,s2+s2w,s2+s2w") |
| |
| (define_reservation "all" "s1+s2+d1+d2+l1+l2+m1+m2") |
| |
| (define_insn_reservation "callp_s1" 1 |
| (and (eq_attr "type" "callp") (eq_attr "dest_regfile" "a")) |
| "s1+s1w,all*5") |
| |
| (define_insn_reservation "callp_s2" 1 |
| (and (eq_attr "type" "callp") (eq_attr "dest_regfile" "b")) |
| "s2+s2w,all*5") |
| |
| ;; Constraints |
| |
| (include "constraints.md") |
| |
| ;; Predicates |
| |
| (include "predicates.md") |
| |
| ;; General predication pattern. |
| |
| (define_cond_exec |
| [(match_operator 0 "eqne_operator" |
| [(match_operand 1 "predicate_register" "AB") |
| (const_int 0)])] |
| "" |
| "") |
| |
| ;; ------------------------------------------------------------------------- |
| ;; NOP instruction |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "nop" |
| [(const_int 0)] |
| "" |
| "nop") |
| |
| (define_insn "nop_count" |
| [(unspec [(match_operand 0 "const_int_operand" "n")] UNSPEC_NOP)] |
| "" |
| "%|%.\\tnop\\t%0") |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Move instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_mode_iterator QIHIM [QI HI]) |
| (define_mode_iterator SIDIM [SI DI]) |
| (define_mode_iterator SIDIVM [SI DI V2HI V4QI]) |
| (define_mode_iterator VEC4M [V2HI V4QI]) |
| (define_mode_iterator VEC8M [V2SI V4HI V8QI]) |
| (define_mode_iterator SISFVM [SI SF V2HI V4QI]) |
| (define_mode_iterator DIDFM [DI DF]) |
| (define_mode_iterator DIDFVM [DI DF V2SI V4HI V8QI]) |
| (define_mode_iterator SFDFM [SF DF]) |
| (define_mode_iterator M32 [QI HI SI SF V2HI V4QI]) |
| |
| ;; The C6X LO_SUM and HIGH are backwards - HIGH sets the low bits, and |
| ;; LO_SUM adds in the high bits. Fortunately these are opaque operations |
| ;; so this does not matter. |
| (define_insn "movsi_lo_sum" |
| [(set (match_operand:SI 0 "register_operand" "=ab") |
| (lo_sum:SI (match_operand:SI 1 "register_operand" "0") |
| (match_operand:SI 2 "const_int_or_symbolic_operand" "i")))] |
| "reload_completed" |
| "%|%.\\tmvkh\\t%$\\t%2, %0" |
| [(set_attr "units" "s")]) |
| |
| (define_insn "movsi_high" |
| [(set (match_operand:SI 0 "register_operand" "=ab") |
| (high:SI (match_operand:SI 1 "const_int_or_symbolic_operand" "i")))] |
| "reload_completed" |
| "%|%.\\tmvkl\\t%$\\t%1, %0" |
| [(set_attr "units" "s")]) |
| |
| (define_insn "movsi_gotoff_lo_sum" |
| [(set (match_operand:SI 0 "register_operand" "=ab") |
| (lo_sum:SI (match_operand:SI 1 "register_operand" "0") |
| (unspec:SI [(match_operand:SI 2 "symbolic_operand" "S2")] |
| UNSPEC_GOTOFF)))] |
| "flag_pic == 2" |
| "%|%.\\tmvkh\\t%$\\t$dpr_got%2, %0" |
| [(set_attr "units" "s")]) |
| |
| (define_insn "movsi_gotoff_high" |
| [(set (match_operand:SI 0 "register_operand" "=ab") |
| (high:SI (unspec:SI [(match_operand:SI 1 "symbolic_operand" "S2")] |
| UNSPEC_GOTOFF)))] |
| "flag_pic == 2" |
| "%|%.\\tmvkl\\t%$\\t$dpr_got%1, %0" |
| [(set_attr "units" "s")]) |
| |
| ;; Normally we'd represent this as a normal load insn, but we can't currently |
| ;; represent the addressing mode. |
| (define_insn "load_got_gotoff" |
| [(set (match_operand:SI 0 "register_operand" "=a,b") |
| (unspec:SI [(match_operand:SI 1 "register_operand" "Z,Z") |
| (match_operand:SI 2 "register_operand" "b,b")] |
| UNSPEC_GOTOFF))] |
| "flag_pic == 2" |
| "%|%.\\tldw\\t%$\\t*+%1[%2], %0" |
| [(set_attr "type" "load") |
| (set_attr "units" "d_addr") |
| (set_attr "op_pattern" "unknown") |
| (set_attr "dest_regfile" "a,b") |
| (set_attr "addr_regfile" "b")]) |
| |
| (define_insn "*movstricthi_high" |
| [(set (match_operand:SI 0 "register_operand" "+ab") |
| (ior:SI (and:SI (match_dup 0) (const_int 65535)) |
| (ashift:SI (match_operand:SI 1 "const_int_operand" "IuB") |
| (const_int 16))))] |
| "reload_completed" |
| "%|%.\\tmvklh\\t%$\\t%1, %0" |
| [(set_attr "units" "s")]) |
| |
| ;; Break up SImode loads of immediate operands. |
| |
| (define_split |
| [(set (match_operand:SI 0 "register_operand" "") |
| (match_operand:SI 1 "const_int_operand" ""))] |
| "reload_completed |
| && !satisfies_constraint_IsB (operands[1])" |
| [(set (match_dup 0) (match_dup 2)) |
| (set (match_dup 0) (ior:SI (and:SI (match_dup 0) (const_int 65535)) |
| (ashift:SI (match_dup 3) (const_int 16))))] |
| { |
| HOST_WIDE_INT val = INTVAL (operands[1]); |
| operands[2] = GEN_INT (trunc_int_for_mode (val, HImode)); |
| operands[3] = GEN_INT ((val >> 16) & 65535); |
| }) |
| |
| (define_split |
| [(set (match_operand:VEC4M 0 "register_operand" "") |
| (match_operand:VEC4M 1 "const_vector_operand" ""))] |
| "reload_completed" |
| [(set (match_dup 2) (match_dup 3))] |
| { |
| unsigned HOST_WIDE_INT mask, val; |
| machine_mode inner_mode = GET_MODE_INNER (<MODE>mode); |
| int i; |
| |
| val = 0; |
| mask = GET_MODE_MASK (inner_mode); |
| if (TARGET_BIG_ENDIAN) |
| { |
| for (i = 0; i < GET_MODE_NUNITS (<MODE>mode); i++) |
| { |
| val <<= GET_MODE_BITSIZE (inner_mode); |
| val |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask; |
| } |
| } |
| else |
| { |
| i = GET_MODE_NUNITS (<MODE>mode); |
| while (i-- > 0) |
| { |
| val <<= GET_MODE_BITSIZE (inner_mode); |
| val |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask; |
| } |
| } |
| operands[2] = gen_rtx_REG (SImode, REGNO (operands[0])); |
| operands[3] = GEN_INT (trunc_int_for_mode (val, SImode)); |
| }) |
| |
| (define_split |
| [(set (match_operand:VEC8M 0 "register_operand" "") |
| (match_operand:VEC8M 1 "const_vector_operand" ""))] |
| "reload_completed" |
| [(set (match_dup 2) (match_dup 3)) |
| (set (match_dup 4) (match_dup 5))] |
| { |
| unsigned HOST_WIDE_INT mask; |
| unsigned HOST_WIDE_INT val[2]; |
| rtx lo_half, hi_half; |
| machine_mode inner_mode = GET_MODE_INNER (<MODE>mode); |
| int i, j; |
| |
| split_di (operands, 1, &lo_half, &hi_half); |
| |
| val[0] = val[1] = 0; |
| mask = GET_MODE_MASK (inner_mode); |
| if (TARGET_BIG_ENDIAN) |
| { |
| for (i = 0, j = 1; i < GET_MODE_NUNITS (<MODE>mode); i++) |
| { |
| if (i * 2 == GET_MODE_NUNITS (<MODE>mode)) |
| j--; |
| val[j] <<= GET_MODE_BITSIZE (inner_mode); |
| val[j] |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask; |
| } |
| } |
| else |
| { |
| i = GET_MODE_NUNITS (<MODE>mode); |
| j = 1; |
| while (i-- > 0) |
| { |
| val[j] <<= GET_MODE_BITSIZE (inner_mode); |
| val[j] |= INTVAL (CONST_VECTOR_ELT (operands[1], i)) & mask; |
| if (i * 2 == GET_MODE_NUNITS (<MODE>mode)) |
| j--; |
| } |
| } |
| operands[2] = lo_half; |
| operands[3] = GEN_INT (trunc_int_for_mode (val[0], SImode)); |
| operands[4] = hi_half; |
| operands[5] = GEN_INT (trunc_int_for_mode (val[1], SImode)); |
| }) |
| |
| (define_split |
| [(set (match_operand:SF 0 "register_operand" "") |
| (match_operand:SF 1 "immediate_operand" ""))] |
| "reload_completed" |
| [(set (match_dup 2) (match_dup 3)) |
| (set (match_dup 2) (ior:SI (and:SI (match_dup 2) (const_int 65535)) |
| (ashift:SI (match_dup 4) (const_int 16))))] |
| { |
| long values; |
| |
| gcc_assert (GET_CODE (operands[1]) == CONST_DOUBLE); |
| |
| REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (operands[1]), values); |
| |
| operands[2] = gen_rtx_REG (SImode, true_regnum (operands[0])); |
| operands[3] = GEN_INT (trunc_int_for_mode (values, HImode)); |
| if (values >= -32768 && values < 32768) |
| { |
| emit_move_insn (operands[2], operands[3]); |
| DONE; |
| } |
| operands[4] = GEN_INT ((values >> 16) & 65535); |
| }) |
| |
| (define_split |
| [(set (match_operand:SI 0 "register_operand" "") |
| (match_operand:SI 1 "symbolic_operand" ""))] |
| "reload_completed |
| && (!TARGET_INSNS_64PLUS |
| || !sdata_symbolic_operand (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)))] |
| "") |
| |
| ;; Normally, we represent the load of an sdata address as a normal |
| ;; move of a SYMBOL_REF. In DSBT mode, B14 is not constant, so we |
| ;; should show the dependency. |
| (define_insn "load_sdata_pic" |
| [(set (match_operand:SI 0 "register_operand" "=a,b") |
| (plus:SI (match_operand:SI 1 "pic_register_operand" "Z,Z") |
| (unspec:SI [(match_operand:SI 2 "sdata_symbolic_operand" "S0,S0")] |
| UNSPEC_LOAD_SDATA)))] |
| "flag_pic" |
| "@ |
| %|%.\\tadda%D2\\t%$\\t%1, %2, %0 |
| %|%.\\tadda%D2\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "d") |
| (set_attr "cross" "y,n") |
| (set_attr "op_pattern" "unknown") |
| (set_attr "predicable" "no")]) |
| |
| ;; Move instruction patterns |
| |
| (define_mode_attr LDST_SUFFIX [(QI "b") (HI "h") |
| (SI "w") (SF "w") (V2HI "w") (V4QI "w") |
| (DI "dw") (V2SI "dw") (V4HI "dw") (V8QI "dw")]) |
| |
| (define_insn "mov<mode>_insn" |
| [(set (match_operand:QIHIM 0 "nonimmediate_operand" |
| "=a,b, a, b, ab, ab,a,?a, b,?b, Q, R, R, Q") |
| (match_operand:QIHIM 1 "general_operand" |
| "a,b,?b,?a,Is5,IsB,Q, R, R, Q, a,?a, b,?b"))] |
| "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG" |
| "@ |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmvk\\t%$\\t%1, %0 |
| %|%.\\tmvk\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tst<LDST_SUFFIX>\\t%$\\t%1, %0" |
| [(set_attr "type" "*,*,*,*,*,*,load,load,load,load,store,store,store,store") |
| (set_attr "units62" "dls,dls,ls,ls,s,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr") |
| (set_attr "units64" "dls,dls,ls,ls,dl,s,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr") |
| (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*") |
| (set_attr "addr_regfile" "*,*,*,*,*,*,a,b,b,a,a,b,b,a") |
| (set_attr "dest_regfile" "*,*,*,*,*,*,a,a,b,b,a,a,b,b") |
| (set_attr "cross" "n,n,y,y,n,n,n,y,n,y,n,y,n,y")]) |
| |
| (define_insn "mov<mode>_insn" |
| [(set (match_operand:SISFVM 0 "nonimmediate_operand" |
| "=a,b, a, b, ab, ab,a,b,ab,a,?a, b,?b, Q, R, R, Q") |
| (match_operand:SISFVM 1 "general_operand" |
| "a,b,?b,?a,Is5,IsB,S0,S0,Si,Q, R, R, Q, a,?a, b,?b"))] |
| "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) == REG |
| || (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1]))))" |
| "@ |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmv\\t%$\\t%1, %0 |
| %|%.\\tmvk\\t%$\\t%1, %0 |
| %|%.\\tmvk\\t%$\\t%1, %0 |
| %|%.\\tadda%D1\\t%$\\tB14, %1, %0 |
| %|%.\\tadda%D1\\t%$\\tB14, %1, %0 |
| # |
| %|%.\\tldw\\t%$\\t%1, %0 |
| %|%.\\tldw\\t%$\\t%1, %0 |
| %|%.\\tldw\\t%$\\t%1, %0 |
| %|%.\\tldw\\t%$\\t%1, %0 |
| %|%.\\tstw\\t%$\\t%1, %0 |
| %|%.\\tstw\\t%$\\t%1, %0 |
| %|%.\\tstw\\t%$\\t%1, %0 |
| %|%.\\tstw\\t%$\\t%1, %0" |
| [(set_attr "type" "*,*,*,*,*,*,*,*,*,load,load,load,load,store,store,store,store") |
| (set_attr "units62" "dls,dls,ls,ls,s,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr") |
| (set_attr "units64" "dls,dls,ls,ls,dl,s,d,d,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr") |
| (set_attr "op_pattern" "sx,sx,sx,sx,*,*,*,*,*,*,*,*,*,*,*,*,*") |
| (set_attr "addr_regfile" "*,*,*,*,*,*,*,*,*,a,b,b,a,a,b,b,a") |
| (set_attr "dest_regfile" "*,*,*,*,*,*,*,*,*,a,a,b,b,a,a,b,b") |
| (set_attr "cross" "n,n,y,y,n,n,y,n,*,n,y,n,y,n,y,n,y") |
| (set_attr "predicable" "yes,yes,yes,yes,yes,yes,no,no,yes,yes,yes,yes,yes,yes,yes,yes,yes")]) |
| |
| (define_insn "*mov<mode>_insn" |
| [(set (match_operand:DIDFVM 0 "nonimmediate_operand" |
| "=a,b, a, b,ab,a,?a, b,?b, Q, R, R, Q") |
| (match_operand:DIDFVM 1 "general_operand" |
| "a,b,?b,?a,iF,Q, R, R, Q, a,?a, b,?b"))] |
| "(!MEM_P (operands[0]) || REG_P (operands[1]) |
| || (GET_CODE (operands[1]) == SUBREG && REG_P (SUBREG_REG (operands[1]))))" |
| { |
| if (MEM_P (operands[1]) && TARGET_LDDW) |
| return "%|%.\\tlddw\\t%$\\t%1, %0"; |
| if (MEM_P (operands[0]) && TARGET_STDW) |
| return "%|%.\\tstdw\\t%$\\t%1, %0"; |
| if (TARGET_INSNS_64PLUS && REG_P (operands[0]) && REG_P (operands[1]) |
| && A_REGNO_P (REGNO (operands[0])) == A_REGNO_P (REGNO (operands[1]))) |
| return "%|%.\\tdmv\\t%$\\t%P1, %p1, %0"; |
| return "#"; |
| } |
| [(set_attr "units" "s,s,*,*,*,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr,d_addr") |
| (set_attr "addr_regfile" "*,*,*,*,*,a,b,b,a,a,b,b,a") |
| (set_attr "dest_regfile" "*,*,*,*,*,a,a,b,b,a,a,b,b") |
| (set_attr "type" "*,*,*,*,*,load,load,load,load,store,store,store,store") |
| (set_attr "cross" "n,n,y,y,*,n,y,n,y,n,y,n,y")]) |
| |
| (define_split |
| [(set (match_operand:DIDFVM 0 "nonimmediate_operand" "") |
| (match_operand:DIDFVM 1 "general_operand" ""))] |
| "reload_completed |
| && !((MEM_P (operands[0]) && TARGET_STDW) |
| || (MEM_P (operands[1]) && TARGET_LDDW)) |
| && !const_vector_operand (operands[1], <MODE>mode) |
| && !(TARGET_INSNS_64PLUS && REG_P (operands[0]) && REG_P (operands[1]) |
| && A_REGNO_P (REGNO (operands[0])) == A_REGNO_P (REGNO (operands[1])))" |
| [(set (match_dup 2) (match_dup 3)) |
| (set (match_dup 4) (match_dup 5))] |
| { |
| rtx lo_half[2], hi_half[2]; |
| split_di (operands, 2, lo_half, hi_half); |
| |
| /* We can't have overlap for a register-register move, but if |
| memory is involved, we have to make sure we don't clobber the |
| address. */ |
| if (reg_overlap_mentioned_p (lo_half[0], hi_half[1])) |
| { |
| operands[2] = hi_half[0]; |
| operands[3] = hi_half[1]; |
| operands[4] = lo_half[0]; |
| operands[5] = lo_half[1]; |
| } |
| else |
| { |
| operands[2] = lo_half[0]; |
| operands[3] = lo_half[1]; |
| operands[4] = hi_half[0]; |
| operands[5] = hi_half[1]; |
| } |
| }) |
| |
| (define_insn "real_load<mode>" |
| [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB") |
| (match_operand:M32 1 "memory_operand" "Q,R,R,Q")] |
| UNSPEC_REAL_LOAD)] |
| "" |
| "%|%.\\tld<LDST_SUFFIX>\\t%$\\t%1, %k0" |
| [(set_attr "type" "load") |
| (set_attr "units" "d_addr") |
| (set_attr "addr_regfile" "a,b,b,a") |
| (set_attr "dest_regfile" "a,a,b,b") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| (define_insn "real_load<mode>" |
| [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB") |
| (match_operand:DIDFVM 1 "memory_operand" "Q,R,R,Q")] |
| UNSPEC_REAL_LOAD)] |
| "TARGET_LDDW" |
| "%|%.\\tlddw\\t%$\\t%1, %K0" |
| [(set_attr "type" "load") |
| (set_attr "units" "d_addr") |
| (set_attr "addr_regfile" "a,b,b,a") |
| (set_attr "dest_regfile" "a,a,b,b") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| (define_insn "load_shadow" |
| [(set (match_operand 0 "register_operand" "=ab") |
| (unspec [(pc)] UNSPEC_LOAD_SHADOW))] |
| "" |
| ";; load to %0 occurs" |
| [(set_attr "type" "load_shadow")]) |
| |
| (define_insn "mult_shadow" |
| [(set (match_operand 0 "register_operand" "=ab") |
| (unspec [(pc)] UNSPEC_MULT_SHADOW))] |
| "" |
| ";; multiplication occurs and stores to %0" |
| [(set_attr "type" "mult_shadow")]) |
| |
| |
| (define_mode_iterator MOV [QI HI SI SF DI DF V2HI V4QI V2SI V4HI V8QI]) |
| |
| (define_expand "mov<mode>" |
| [(set (match_operand:MOV 0 "nonimmediate_operand" "") |
| (match_operand:MOV 1 "general_operand" ""))] |
| "" |
| { |
| if (expand_move (operands, <MODE>mode)) |
| DONE; |
| }) |
| |
| (define_expand "movmisalign<mode>" |
| [(set (match_operand:SIDIVM 0 "nonimmediate_operand" "") |
| (unspec:SIDIVM [(match_operand:SIDIVM 1 "nonimmediate_operand" "")] |
| UNSPEC_MISALIGNED_ACCESS))] |
| "TARGET_INSNS_64" |
| { |
| if (MEM_P (operands[0])) |
| { |
| emit_insn (gen_movmisalign<mode>_store (operands[0], operands[1])); |
| DONE; |
| } |
| }) |
| |
| (define_insn_and_split "movmisalign<mode>_store" |
| [(set (match_operand:SIDIVM 0 "memory_operand" "=W,Q,T,Q,T") |
| (unspec:SIDIVM [(match_operand:SIDIVM 1 "register_operand" "r,a,b,b,a")] |
| UNSPEC_MISALIGNED_ACCESS)) |
| (clobber (match_scratch:SI 2 "=r,X,X,X,X"))] |
| "TARGET_INSNS_64" |
| "@ |
| # |
| %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tstn<LDST_SUFFIX>\\t%$\\t%1, %0" |
| "&& reload_completed && satisfies_constraint_W (operands[0])" |
| [(parallel |
| [(set (match_dup 3) (unspec:SIDIVM [(match_dup 1)] UNSPEC_MISALIGNED_ACCESS)) |
| (clobber (match_dup 4))])] |
| { |
| rtx addr = XEXP (operands[0], 0); |
| rtx tmpreg = operands[2]; |
| |
| if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == stack_pointer_rtx |
| && GET_CODE (XEXP (addr, 1)) == CONST_INT) |
| { |
| unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1)); |
| val &= GET_MODE_SIZE (<MODE>mode) - 1; |
| if (val == 0) |
| { |
| emit_move_insn (operands[0], operands[1]); |
| DONE; |
| } |
| } |
| operands[3] = change_address (operands[0], <MODE>mode, tmpreg); |
| emit_move_insn (tmpreg, addr); |
| operands[4] = gen_rtx_SCRATCH (SImode); |
| } |
| [(set_attr "type" "storen") |
| (set_attr "units" "d_addr") |
| (set_attr "addr_regfile" "*,a,b,a,b") |
| (set_attr "dest_regfile" "*,a,b,b,a") |
| (set_attr "cross" "*,n,n,y,y")]) |
| |
| (define_insn_and_split "movmisalign<mode>_load" |
| [(set (match_operand:SIDIVM 0 "register_operand" "=ab,a,b,b,a") |
| (unspec:SIDIVM [(match_operand:SIDIVM 1 "memory_operand" "W,Q,T,Q,T")] |
| UNSPEC_MISALIGNED_ACCESS))] |
| "TARGET_INSNS_64" |
| "@ |
| # |
| %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0 |
| %|%.\\tldn<LDST_SUFFIX>\\t%$\\t%1, %0" |
| "&& reload_completed && satisfies_constraint_W (operands[1])" |
| [(set (match_dup 0) (unspec:SIDIVM [(match_dup 2)] UNSPEC_MISALIGNED_ACCESS))] |
| { |
| rtx addr = XEXP (operands[1], 0); |
| rtx tmpreg = (GET_MODE (operands[0]) == SImode ? operands[0] |
| : operand_subword_force (operands[0], 0, DImode)); |
| |
| if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == stack_pointer_rtx |
| && GET_CODE (XEXP (addr, 1)) == CONST_INT) |
| { |
| unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1)); |
| val &= GET_MODE_SIZE (<MODE>mode) - 1; |
| if (val == 0) |
| { |
| emit_move_insn (operands[0], operands[1]); |
| DONE; |
| } |
| } |
| operands[2] = change_address (operands[1], <MODE>mode, tmpreg); |
| emit_move_insn (tmpreg, addr); |
| } |
| [(set_attr "type" "loadn") |
| (set_attr "units" "d_addr") |
| (set_attr "addr_regfile" "*,a,b,a,b") |
| (set_attr "dest_regfile" "*,a,b,b,a") |
| (set_attr "cross" "*,n,n,y,y")]) |
| |
| ;; |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Extensions/extractions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_code_iterator any_extract [zero_extract sign_extract]) |
| (define_code_iterator any_ext [zero_extend sign_extend]) |
| |
| (define_code_attr ext_name [(zero_extend "zero_extend") (sign_extend "sign_extend")]) |
| |
| (define_code_attr u [(zero_extend "u") (sign_extend "")]) |
| |
| (define_code_attr z [(zero_extract "z") (sign_extract "")]) |
| (define_code_attr zu [(zero_extract "u") (sign_extract "")]) |
| |
| (define_mode_attr ext_shift [(QI "24") (HI "16")]) |
| |
| (define_insn "<ext_name><mode>si2" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,?a, b,?b") |
| (any_ext:SI (match_operand:QIHIM 1 "nonimmediate_operand" "a,b,Q, R, R, Q")))] |
| "" |
| "@ |
| %|%.\\text<u>\\t%$\\t%1, <ext_shift>, <ext_shift>, %0 |
| %|%.\\text<u>\\t%$\\t%1, <ext_shift>, <ext_shift>, %0 |
| %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0 |
| %|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %0" |
| [(set_attr "type" "*,*,load,load,load,load") |
| (set_attr "units" "s,s,d_addr,d_addr,d_addr,d_addr") |
| (set_attr "addr_regfile" "*,*,a,b,b,a") |
| (set_attr "dest_regfile" "*,*,a,a,b,b") |
| (set_attr "cross" "n,n,n,y,n,y")]) |
| |
| (define_insn "*ext<z>v_const" |
| [(set (match_operand:SI 0 "nonimmediate_operand" "=a,b") |
| (any_extract:SI (match_operand:SI 1 "register_operand" "a,b") |
| (match_operand:SI 2 "const_int_operand" "n,n") |
| (match_operand:SI 3 "const_int_operand" "n,n")))] |
| "INTVAL (operands[3]) >= 0 |
| && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32" |
| { |
| int pos = INTVAL (operands[3]); |
| int len = INTVAL (operands[2]); |
| rtx xop[4]; |
| xop[0] = operands[0]; |
| xop[1] = operands[1]; |
| xop[2] = GEN_INT (32 - pos - len); |
| xop[3] = GEN_INT (32 - len); |
| |
| output_asm_insn ("%|%.\\text<zu>\\t%$\\t%1, %2, %3, %0", xop); |
| return ""; |
| } |
| [(set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_expand "ext<z>v" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (any_extract:SI (match_operand:SI 1 "register_operand" "") |
| (match_operand:SI 2 "const_int_operand" "") |
| (match_operand:SI 3 "const_int_operand" "")))] |
| "" |
| { |
| if (INTVAL (operands[2]) < 0 |
| || INTVAL (operands[2]) + INTVAL (operands[3]) > 32) |
| FAIL; |
| }) |
| |
| (define_insn "real_<ext_name><mode>" |
| [(unspec [(match_operand 0 "const_int_operand" "JA,JA,JB,JB") |
| (any_ext:SI (match_operand:QIHIM 1 "memory_operand" "Q,R,R,Q"))] |
| UNSPEC_REAL_LOAD)] |
| "" |
| "%|%.\\tld<LDST_SUFFIX><u>\\t%$\\t%1, %k0" |
| [(set_attr "type" "load") |
| (set_attr "units" "d_addr") |
| (set_attr "addr_regfile" "a,b,b,a") |
| (set_attr "dest_regfile" "a,a,b,b") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| (define_insn "clrr" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (unspec:SI [(match_operand:SI 1 "register_operand" "0,0,0,0") |
| (match_operand:SI 2 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_const_int_operand" "ai,bi,a,b")] |
| UNSPEC_CLR))] |
| "" |
| { |
| if (CONST_INT_P (operands[2])) |
| { |
| rtx xops[4]; |
| int v1 = INTVAL (operands[2]); |
| int v2 = (v1 >> 5) & 0x1f; |
| v1 &= 0x1f; |
| xops[0] = operands[0]; |
| xops[1] = operands[1]; |
| xops[2] = GEN_INT (v1); |
| xops[3] = GEN_INT (v2); |
| output_asm_insn ("%|%.\\tclr\\t%$\\t%1, %3, %2, %0", xops); |
| return ""; |
| } |
| return "%|%.\\tclr\\t%$\\t%2, %3, %0"; |
| } |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "extr" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (unspec:SI [(match_operand:SI 1 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 2 "reg_or_const_int_operand" "ai,bi,a,b")] |
| UNSPEC_EXT))] |
| "" |
| { |
| if (CONST_INT_P (operands[2])) |
| { |
| rtx xops[4]; |
| int v1 = INTVAL (operands[2]); |
| int v2 = (v1 >> 5) & 0x1f; |
| v1 &= 0x1f; |
| xops[0] = operands[0]; |
| xops[1] = operands[1]; |
| xops[2] = GEN_INT (v1); |
| xops[3] = GEN_INT (v2); |
| output_asm_insn ("%|%.\\text\\t%$\\t%1, %3, %2, %0", xops); |
| return ""; |
| } |
| return "%|%.\\text\\t%$\\t%1, %2, %0"; |
| } |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "extru" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (unspec:SI [(match_operand:SI 1 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 2 "reg_or_const_int_operand" "ai,bi,a,b")] |
| UNSPEC_EXTU))] |
| "" |
| { |
| if (CONST_INT_P (operands[2])) |
| { |
| rtx xops[4]; |
| int v1 = INTVAL (operands[2]); |
| int v2 = (v1 >> 5) & 0x1f; |
| v1 &= 0x1f; |
| xops[0] = operands[0]; |
| xops[1] = operands[1]; |
| xops[2] = GEN_INT (v1); |
| xops[3] = GEN_INT (v2); |
| output_asm_insn ("%|%.\\textu\\t%$\\t%1, %3, %2, %0", xops); |
| return ""; |
| } |
| return "%|%.\\textu\\t%$\\t%1, %2, %0"; |
| } |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Compare instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "scmpsi_insn" |
| [(set (match_operand:SI 0 "register_operand" "=ab,a,b,a,b") |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:SI 2 "register_operand" "ab,a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_scst5_operand" "Is5,aIs5,bIs5,aIs5,bIs5")]))] |
| "" |
| "%|%.\\tcmp%C1\\t%$\\t%3, %2, %0" |
| [(set_attr "units" "l") |
| (set (attr "cross") |
| (symbol_ref "CROSS_OPERANDS (operands[0], operands[2])"))]) |
| |
| (define_insn "*ucmpsi_insn_64" |
| [(set (match_operand:SI 0 "register_operand" "=ab,a,b,a,b") |
| (match_operator:SI 1 "ltugtu_operator" |
| [(match_operand:SI 2 "register_operand" "ab,a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_ucst5_operand" "Iu5,aIu5,bIu5,aIu5,bIu5")]))] |
| "TARGET_INSNS_64" |
| "%|%.\\tcmp%C1\\t%$\\t%3, %2, %0" |
| [(set_attr "units" "l") |
| (set (attr "cross") |
| (symbol_ref "CROSS_OPERANDS (operands[0], operands[2])"))]) |
| |
| (define_insn "*ucmpsi_insn" |
| [(set (match_operand:SI 0 "register_operand" "=ab,a,b,a,b") |
| (match_operator:SI 1 "ltugtu_operator" |
| [(match_operand:SI 2 "register_operand" "ab,a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_ucst4_operand" "Iu4,aIu4,bIu4,aIu4,bIu4")]))] |
| "!TARGET_INSNS_64" |
| "%|%.\\tcmp%C1\\t%$\\t%3, %2, %0" |
| [(set_attr "units" "l") |
| (set (attr "cross") |
| (symbol_ref "CROSS_OPERANDS (operands[0], operands[2])"))]) |
| |
| (define_code_iterator andior_eqne [eq ne]) |
| (define_code_attr andior_name [(eq "and") (ne "ior")]) |
| (define_code_attr andior_condmod [(eq "") (ne "!")]) |
| |
| (define_insn "*scmpsi_<andior_name>_insn" |
| [(set (match_operand:SI 0 "register_operand" "=A,B,A,B") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:SI 2 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_scst5_operand" "aIs5,bIs5,aIs5,bIs5")])))] |
| "" |
| "%|[<andior_condmod>%4]\\tcmp%C1\\t%$\\t%3, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y") |
| (set_attr "predicable" "no")]) |
| |
| (define_insn "*ucmpsi_<andior_name>_insn_64" |
| [(set (match_operand:SI 0 "register_operand" "=A,B,A,B") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "ltugtu_operator" |
| [(match_operand:SI 2 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")])))] |
| "TARGET_INSNS_64" |
| "%|[<andior_condmod>%4]\\tcmp%C1\\t%$\\t%3, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y") |
| (set_attr "predicable" "no")]) |
| |
| (define_insn "*ucmpsi_<andior_name>_insn" |
| [(set (match_operand:SI 0 "register_operand" "=A,B,A,B") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "ltugtu_operator" |
| [(match_operand:SI 2 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 3 "reg_or_ucst4_operand" "aIu4,bIu4,aIu4,bIu4")])))] |
| "!TARGET_INSNS_64" |
| "%|[<andior_condmod>%4]\\tcmp%C1\\t%$\\t%3, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y") |
| (set_attr "predicable" "no")]) |
| |
| (define_expand "cmpsi_<andior_name>" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "c6x_comparison_operator" |
| [(match_operand:SI 2 "register_operand" "") |
| (match_operand:SI 3 "reg_or_const_int_operand" "")])))] |
| "" |
| { |
| if (c6x_force_op_for_comparison_p (GET_CODE (operands[1]), operands[3])) |
| operands[3] = force_reg (SImode, operands[3]); |
| }) |
| |
| (define_insn "*cmpsf_insn" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:SF 2 "register_operand" "a,b,a,b") |
| (match_operand:SF 3 "register_operand" "a,b,?b,?a")]))] |
| "TARGET_FP" |
| "%|%.\\tcmp%c1sp\\t%$\\t%2, %3, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "*cmpdf_insn" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:DF 2 "register_operand" "a,b,a,b") |
| (match_operand:DF 3 "register_operand" "a,b,?b,?a")]))] |
| "TARGET_FP" |
| "%|%.\\tcmp%c1dp\\t%$\\t%2, %3, %0" |
| [(set_attr "type" "cmpdp") |
| (set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_expand "cmp<mode>_<andior_name>" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:SFDFM 2 "register_operand" "") |
| (match_operand:SFDFM 3 "register_operand" "")])))] |
| "TARGET_FP") |
| |
| (define_insn "*cmpsf_<andior_name>_insn" |
| [(set (match_operand:SI 0 "register_operand" "=A,B,A,B") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:SF 2 "register_operand" "a,b,a,b") |
| (match_operand:SF 3 "register_operand" "a,b,?b,?a")])))] |
| "TARGET_FP" |
| "%|[<andior_condmod>%4]\\tcmp%c1sp\\t%$\\t%2, %3, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y") |
| (set_attr "predicable" "no")]) |
| |
| ;; reload_reg_class_lower will ensure that two-word reloads are allocated first, |
| ;; which could exhaust the predicate registers if we used just "a" and "b" |
| ;; constraints on operands 2 and 3. |
| (define_insn "*cmpdf_<andior_name>_insn" |
| [(set (match_operand:SI 0 "register_operand" "=A,B,A,B") |
| (if_then_else:SI |
| (andior_eqne:SI (match_operand:SI 4 "register_operand" "0,0,0,0") |
| (const_int 0)) |
| (match_dup 4) |
| (match_operator:SI 1 "eqltgt_operator" |
| [(match_operand:DF 2 "register_operand" "Da,Db,Da,Db") |
| (match_operand:DF 3 "register_operand" "Da,Db,?Db,?Da")])))] |
| "TARGET_FP" |
| "%|[<andior_condmod>%4]\\tcmp%c1dp\\t%$\\t%2, %3, %0" |
| [(set_attr "type" "cmpdp") |
| (set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y") |
| (set_attr "predicable" "no")]) |
| |
| (define_split |
| [(set (match_operand:SI 0 "register_operand" "") |
| (ior:SI (match_operand 1 "c6x_any_comparison_operand" "") |
| (match_operand 2 "c6x_any_comparison_operand" "")))] |
| "!reg_overlap_mentioned_p (operands[0], operands[2])" |
| [(set (match_dup 0) (match_dup 1)) |
| (set (match_dup 0) |
| (if_then_else:SI (ne:SI (match_dup 0) (const_int 0)) |
| (match_dup 0) |
| (match_dup 2)))]) |
| |
| (define_split |
| [(set (match_operand:SI 0 "register_operand" "") |
| (and:SI (match_operand 1 "c6x_any_comparison_operand" "") |
| (match_operand 2 "c6x_any_comparison_operand" "")))] |
| "!reg_overlap_mentioned_p (operands[0], operands[2])" |
| [(set (match_dup 0) (match_dup 1)) |
| (set (match_dup 0) |
| (if_then_else:SI (eq:SI (match_dup 0) (const_int 0)) |
| (match_dup 0) |
| (match_dup 2)))]) |
| |
| |
| ;; ------------------------------------------------------------------------- |
| ;; setcc instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_expand "cstoresi4" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (match_operator:SI 1 "comparison_operator" |
| [(match_operand:SI 2 "register_operand" "") |
| (match_operand:SI 3 "reg_or_ucst4_operand" "")]))] |
| "" |
| { |
| if (!c6x_comparison_operator (operands[1], SImode)) |
| { |
| rtx tmpreg = gen_reg_rtx (SImode); |
| rtx t = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])), |
| SImode, operands[2], operands[3]); |
| emit_insn (gen_rtx_SET (tmpreg, t)); |
| emit_insn (gen_scmpsi_insn (operands[0], |
| gen_rtx_fmt_ee (EQ, SImode, tmpreg, const0_rtx), |
| tmpreg, const0_rtx)); |
| DONE; |
| } |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Jump instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "indirect_jump" |
| [(set (pc) (match_operand:SI 0 "register_operand" "a,b"))] |
| "" |
| "%|%.\\tb\\t%$\\t%0" |
| [(set_attr "type" "branch") |
| (set_attr "units" "s") |
| (set_attr "cross" "y,n") |
| (set_attr "dest_regfile" "b")]) |
| |
| (define_insn "jump" |
| [(set (pc) |
| (label_ref (match_operand 0 "" "")))] |
| "" |
| "%|%.\\tb\\t%$\\t%l0" |
| [(set_attr "type" "branch") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "any")]) |
| |
| (define_expand "tablejump" |
| [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "")) |
| (use (label_ref (match_operand 1 "" "")))])] |
| "!flag_pic || !TARGET_INSNS_64" |
| { |
| }) |
| |
| (define_insn "*tablejump_internal" |
| [(set (pc) (match_operand:SI 0 "register_operand" "b")) |
| (use (label_ref (match_operand 1 "" "")))] |
| "!flag_pic || !TARGET_INSNS_64" |
| "%|\\tb\\t%$\\t%0" |
| [(set_attr "type" "branch") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "b")]) |
| |
| ;; Implement switch statements when generating PIC code. Switches are |
| ;; implemented by `tablejump' when not using -fpic. |
| |
| ;; Emit code here to do the range checking and make the index zero based. |
| ;; operand 0 is the index |
| ;; operand 1 is the lower bound |
| ;; operand 2 is the range of indices (highest - lowest + 1) |
| ;; operand 3 is the label that precedes the table itself |
| ;; operand 4 is the fall through label |
| |
| (define_expand "casesi" |
| [(use (match_operand:SI 0 "register_operand" "")) |
| (use (match_operand:SI 1 "const_int_operand" "")) |
| (use (match_operand:SI 2 "const_int_operand" "")) |
| (use (match_operand 3 "" "")) |
| (use (match_operand 4 "" ""))] |
| "flag_pic && TARGET_INSNS_64" |
| { |
| rtx indx; |
| rtx low = operands[1]; |
| rtx range = operands[2]; |
| rtx table = operands[3]; |
| rtx fail = operands[4]; |
| |
| gcc_assert (GET_CODE (operands[1]) == CONST_INT); |
| gcc_assert (GET_CODE (operands[2]) == CONST_INT); |
| |
| if (!reg_or_ucst4_operand (range, SImode)) |
| range = force_reg (SImode, range); |
| |
| /* If low bound is 0, we don't have to subtract it. */ |
| if (INTVAL (operands[1]) == 0) |
| indx = operands[0]; |
| else |
| { |
| rtx offset = GEN_INT (-INTVAL (low)); |
| indx = gen_reg_rtx (SImode); |
| if (!addsi_operand (offset, SImode)) |
| offset = force_reg (SImode, offset); |
| emit_insn (gen_addsi3 (indx, operands[0], offset)); |
| } |
| emit_cmp_and_jump_insns (indx, range, GTU, NULL_RTX, SImode, 1, fail); |
| |
| emit_jump_insn (gen_casesi_internal (indx, table)); |
| DONE; |
| }) |
| |
| ;; This is the only instance in this file where a pattern emits more than |
| ;; one instruction. The concern here is that the addkpc insn could otherwise |
| ;; be scheduled too far away from the label. A tablejump always ends an |
| ;; extended basic block, so it shouldn't happen that the scheduler places |
| ;; something in the delay slots. |
| (define_insn "casesi_internal" |
| [(set (pc) |
| (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "b") |
| (const_int 4)) |
| (label_ref (match_operand 1 "" ""))))) |
| (clobber (match_scratch:SI 2 "=&b")) |
| (clobber (match_scratch:SI 3 "=b"))] |
| "flag_pic && TARGET_INSNS_64" |
| "addkpc\t.s2\t%l1,%2, 0\n\t\tldw\t.d2t2\t*+%2[%0], %3\n\t\tnop\t\t4\n\t\tadd\t.l2\t%2, %3, %3\n\t\tb\t.s2\t%3" |
| [(set_attr "type" "branch") |
| (set_attr "predicable" "no") |
| (set_attr "dest_regfile" "b")]) |
| |
| (define_expand "cbranch<mode>4" |
| [(set (pc) |
| (if_then_else (match_operator 0 "comparison_operator" |
| [(match_operand:SIDIM 1 "register_operand" "") |
| (match_operand:SIDIM 2 "reg_or_const_int_operand" "")]) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| { |
| rtx t = c6x_expand_compare (operands[0], VOIDmode); |
| operands[0] = t; |
| operands[1] = XEXP (t, 0); |
| operands[2] = XEXP (t, 1); |
| }) |
| |
| (define_expand "cbranch<mode>4" |
| [(set (pc) |
| (if_then_else (match_operator 0 "c6x_fp_comparison_operator" |
| [(match_operand:SFDFM 1 "register_operand" "") |
| (match_operand:SFDFM 2 "register_operand" "")]) |
| (label_ref (match_operand 3 "" "")) |
| (pc)))] |
| "" |
| { |
| rtx t = c6x_expand_compare (operands[0], VOIDmode); |
| operands[0] = t; |
| operands[1] = XEXP (t, 0); |
| operands[2] = XEXP (t, 1); |
| }) |
| |
| (define_insn "br_true" |
| [(set (pc) |
| (if_then_else (match_operator 0 "predicate_operator" |
| [(match_operand:SI 1 "register_operand" "AB") |
| (const_int 0)]) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "" |
| "%|[%J0]\\tb\\t%$\\t%l2" |
| [(set_attr "type" "branch") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "any")]) |
| |
| (define_insn "br_false" |
| [(set (pc) |
| (if_then_else (match_operator 0 "predicate_operator" |
| [(match_operand:SI 1 "register_operand" "AB") |
| (const_int 0)]) |
| (pc) |
| (label_ref (match_operand 2 "" ""))))] |
| "" |
| "%|[%j0]\\tb\\t%$\\t%l2" |
| [(set_attr "type" "branch") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "any")]) |
| |
| (define_expand "return" |
| [(parallel |
| [(return) |
| (use (reg:SI REG_B3))])] |
| "reload_completed && get_frame_size () == 0 && c6x_nsaved_regs () == 0") |
| |
| ;; We can't expand this before we know where the link register is stored. |
| (define_insn_and_split "eh_return" |
| [(unspec_volatile [(match_operand:SI 0 "register_operand" "ab")] |
| UNSPECV_EH_RETURN) |
| (clobber (match_scratch:SI 1 "=&ab"))] |
| "" |
| "#" |
| "&& reload_completed" |
| [(const_int 0)] |
| " |
| { |
| c6x_set_return_address (operands[0], operands[1]); |
| DONE; |
| }" |
| ) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Doloop |
| ;; ------------------------------------------------------------------------- |
| |
| ; operand 0 is the loop count pseudo register |
| ; operand 1 is the label to jump to at the top of the loop |
| (define_expand "doloop_end" |
| [(parallel [(set (pc) (if_then_else |
| (ne (match_operand:SI 0 "" "") |
| (const_int 1)) |
| (label_ref (match_operand 1 "" "")) |
| (pc))) |
| (set (match_dup 0) |
| (plus:SI (match_dup 0) |
| (const_int -1))) |
| (clobber (match_dup 2))])] ; match_scratch |
| "TARGET_INSNS_64PLUS && optimize" |
| { |
| /* The loop optimizer doesn't check the predicates... */ |
| if (GET_MODE (operands[0]) != SImode) |
| FAIL; |
| operands[2] = gen_rtx_SCRATCH (SImode); |
| }) |
| |
| (define_insn "mvilc" |
| [(set (reg:SI REG_ILC) |
| (unspec [(match_operand:SI 0 "register_operand" "a,b")] UNSPEC_MVILC))] |
| "TARGET_INSNS_64PLUS" |
| "%|%.\\tmvc\\t%$\\t%0, ILC" |
| [(set_attr "predicable" "no") |
| (set_attr "cross" "y,n") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "b") |
| (set_attr "type" "mvilc")]) |
| |
| (define_insn "sploop" |
| [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i") |
| (reg:SI REG_ILC)] |
| UNSPECV_SPLOOP)] |
| "TARGET_INSNS_64PLUS" |
| "%|%.\\tsploop\t%0" |
| [(set_attr "predicable" "no") |
| (set_attr "type" "sploop")]) |
| |
| (define_insn "spkernel" |
| [(set (pc) |
| (if_then_else |
| (ne (unspec_volatile:SI |
| [(match_operand:SI 0 "const_int_operand" "i") |
| (match_operand:SI 1 "const_int_operand" "i")] |
| UNSPECV_SPKERNEL) |
| (const_int 1)) |
| (label_ref (match_operand 2 "" "")) |
| (pc)))] |
| "TARGET_INSNS_64PLUS" |
| "%|%.\\tspkernel\t%0, %1" |
| [(set_attr "predicable" "no") |
| (set_attr "type" "spkernel")]) |
| |
| (define_insn "loop_end" |
| [(set (pc) |
| (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "0,0,0,*r") |
| (const_int 1)) |
| (label_ref (match_operand 1 "" "")) |
| (pc))) |
| (set (match_operand:SI 0 "nonimmediate_operand" "=AB,*r,m,m") |
| (plus:SI (match_dup 3) |
| (const_int -1))) |
| (clobber (match_scratch:SI 2 "=X,&AB,&AB,&AB"))] |
| "TARGET_INSNS_64PLUS && optimize" |
| "#" |
| [(set_attr "type" "spkernel")]) |
| |
| (define_split |
| [(set (pc) |
| (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "") |
| (const_int 1)) |
| (label_ref (match_operand 1 "" "")) |
| (pc))) |
| (set (match_operand:SI 0 "memory_operand" "") |
| (plus:SI (match_dup 3) |
| (const_int -1))) |
| (clobber (match_scratch 2))] |
| "" |
| [(set (match_dup 2) (plus:SI (match_dup 3) (const_int -1))) |
| (set (match_dup 0) (match_dup 2)) |
| (set (pc) |
| (if_then_else (ne (match_dup 2) (const_int 0)) |
| (label_ref (match_dup 1)) |
| (pc)))] |
| { |
| if (!REG_P (operands[3])) |
| { |
| emit_move_insn (operands[2], operands[3]); |
| operands[3] = operands[2]; |
| } |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Delayed-branch real jumps and shadows |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "real_jump" |
| [(unspec [(match_operand 0 "c6x_jump_operand" "a,b,S3") (const_int 0)] |
| UNSPEC_REAL_JUMP)] |
| "" |
| { |
| if (GET_CODE (operands[0]) == LABEL_REF) |
| return "%|%.\\tb\\t%$\\t%l0"; |
| return "%|%.\\tb\\t%$\\t%0"; |
| } |
| [(set_attr "type" "branch") |
| (set_attr "has_shadow" "y") |
| (set_attr "units" "s") |
| (set_attr "cross" "y,n,n") |
| (set_attr "dest_regfile" "b,b,any")]) |
| |
| (define_insn "real_call" |
| [(unspec [(match_operand 0 "c6x_call_operand" "a,b,S1") (const_int 1)] |
| UNSPEC_REAL_JUMP) |
| (clobber (reg:SI REG_B3))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "has_shadow" "y") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "cross" "y,n,n") |
| (set_attr "dest_regfile" "b,b,any")]) |
| |
| (define_insn "real_ret" |
| [(unspec [(match_operand 0 "register_operand" "a,b") (const_int 2)] |
| UNSPEC_REAL_JUMP)] |
| "" |
| "%|%.\\tret\\t%$\\t%0" |
| [(set_attr "type" "branch") |
| (set_attr "has_shadow" "y") |
| (set_attr "units" "s") |
| (set_attr "cross" "y,n") |
| (set_attr "dest_regfile" "b")]) |
| |
| ;; computed_jump_p returns true if it finds a constant; so use one in the |
| ;; unspec. |
| (define_insn "indirect_jump_shadow" |
| [(set (pc) (unspec [(const_int 1)] UNSPEC_JUMP_SHADOW))] |
| "" |
| ";; indirect jump occurs" |
| [(set_attr "type" "shadow")]) |
| |
| ;; Operand 0 may be a PARALLEL which isn't handled by output_operand, so |
| ;; we don't try to print it. |
| (define_insn "indirect_call_value_shadow" |
| [(set (match_operand 0 "" "") |
| (call (unspec [(pc)] UNSPEC_JUMP_SHADOW) |
| (const_int 0)))] |
| "" |
| ";; indirect call occurs, with return value" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "indirect_sibcall_shadow" |
| [(call (unspec [(pc)] UNSPEC_JUMP_SHADOW) |
| (const_int 0))] |
| "SIBLING_CALL_P (insn)" |
| ";; indirect sibcall occurs" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "indirect_call_shadow" |
| [(call (unspec [(pc)] UNSPEC_JUMP_SHADOW) |
| (const_int 0))] |
| "" |
| ";; indirect call occurs" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "call_value_shadow" |
| [(set (match_operand 0 "" "") |
| (call (unspec [(match_operand 1 "" "")] UNSPEC_JUMP_SHADOW) |
| (const_int 0)))] |
| "" |
| ";; call to %1 occurs, with return value" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "call_shadow" |
| [(call (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW) |
| (const_int 0))] |
| "!SIBLING_CALL_P (insn)" |
| ";; call to %0 occurs" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "sibcall_shadow" |
| [(call (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW) |
| (const_int 0))] |
| "SIBLING_CALL_P (insn)" |
| ";; sibcall to %0 occurs" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "jump_shadow" |
| [(set (pc) (unspec [(match_operand 0 "" "")] UNSPEC_JUMP_SHADOW))] |
| "" |
| ";; jump to %0 occurs" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "condjump_shadow" |
| [(set (pc) |
| (if_then_else (eq (unspec [(const_int 0)] UNSPEC_JUMP_SHADOW) |
| (const_int 0)) |
| (match_operand 0 "" "") |
| (pc)))] |
| "" |
| ";; condjump to %0 occurs" |
| [(set_attr "type" "shadow")]) |
| |
| (define_insn "return_shadow" |
| [(unspec [(const_int 0)] UNSPEC_JUMP_SHADOW) |
| (return)] |
| "" |
| ";; return occurs" |
| [(set_attr "type" "shadow")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Add instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "addsi3" |
| [(set (match_operand:SI 0 "register_operand" |
| "=a ,b , a, b, a, b, a, b, ab, a, b, a, b,ab") |
| (plus:SI (match_operand:SI 1 "register_operand" |
| "%a ,b , a, b, b, a, b, a, 0, a, b, z, z,0") |
| (match_operand:SI 2 "addsi_operand" |
| "aIs5,bIs5,?b,?a,?a,?b,?aIs5,?bIs5,I5x,I5x,I5x,Iux,Iux,IsB")))] |
| "" |
| { |
| if (CONSTANT_P (operands[2])) |
| { |
| HOST_WIDE_INT val = INTVAL (operands[2]); |
| |
| if (c6x_get_unit_specifier (insn) == 'd') |
| { |
| bool issp = (TARGET_INSNS_64PLUS |
| && operands[1] == stack_pointer_rtx |
| && GET_CODE (PATTERN (insn)) != COND_EXEC); |
| |
| if (get_attr_cross (insn) == CROSS_N) |
| { |
| if (satisfies_constraint_Iu5 (operands[2])) |
| return "%|%.\\tadd\\t%$\\t%1, %2, %0"; |
| else if (satisfies_constraint_In5 (operands[2])) |
| return "%|%.\\tsub\\t%$\\t%1, %n2, %0"; |
| } |
| |
| if (issp && val > 0 && val < 32768) |
| { |
| return "%|%.\\taddab\\t%$\\t%1, %2, %0"; |
| } |
| if ((val & 1) == 0 && ((val >= -62 && val <= 62) |
| || (issp && val > 0 && val < 65536))) |
| { |
| if (val < 0) |
| return "%|%.\\tsubah\\t%$\\t%1, %r2, %0"; |
| else |
| return "%|%.\\taddah\\t%$\\t%1, %r2, %0"; |
| } |
| else if ((val & 3) == 0 && ((val >= -124 && val <= 124) |
| || (issp && val > 0 && val < 131072))) |
| { |
| if (val < 0) |
| return "%|%.\\tsubaw\\t%$\\t%1, %R2, %0"; |
| else |
| return "%|%.\\taddaw\\t%$\\t%1, %R2, %0"; |
| } |
| else if ((val & 7) == 0 && val > 0 && val <= 248) |
| { |
| rtx xop[3]; |
| xop[0] = operands[0]; |
| xop[1] = operands[1]; |
| xop[2] = GEN_INT (val >> 3); |
| output_asm_insn ("%|%.\\taddad\\t%$\\t%1, %2, %0", xop); |
| return ""; |
| } |
| } |
| else |
| { |
| if (satisfies_constraint_Is5 (operands[2])) |
| return "%|%.\\tadd\\t%$\\t%2, %1, %0"; |
| } |
| gcc_assert (rtx_equal_p (operands[0], operands[1])); |
| return "%|%.\\taddk\\t%$\\t%2, %0"; |
| } |
| if (which_alternative == 4 || which_alternative == 5) |
| return "%|%.\\tadd\\t%$\\t%2, %1, %0"; |
| else |
| return "%|%.\\tadd\\t%$\\t%1, %2, %0"; |
| } |
| [(set_attr "units62" "dls,dls,ls,ls,ls,ls,ls,ls,s,d,d,*,*,s") |
| (set_attr "units67" "dls,dls,ls,ls,ls,ls,ls,ls,ds,d,d,*,*,s") |
| (set_attr "units64" "dls,dls,dls,dls,dls,dls,ls,ls,ds,d,d,d,d,s") |
| (set_attr "cross" "n,n,y,y,y,y,y,y,n,n,n,y,n,n") |
| (set_attr "predicable" "yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,yes")]) |
| |
| (define_insn "subsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b") |
| (minus:SI (match_operand:SI 1 "reg_or_scst5_operand" "a,b,aIs5,bIs5,bIs5,aIs5") |
| (match_operand:SI 2 "register_operand" "a,b,a,b,?a,?b")))] |
| "" |
| "%|%.\\tsub\\t%$\\t%1, %2, %0" |
| [(set_attr "units62" "dls,dls,ls,ls,l,l") |
| (set_attr "units64" "dls,dls,ls,ls,ls,ls") |
| (set_attr "cross" "n,n,n,n,y,y")]) |
| |
| (define_insn "*addshiftsi" |
| [(set (match_operand:SI 0 "register_operand" "=a,b") |
| (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "a,b") |
| (match_operand:SI 3 "adda_scale_operand" "n,n")) |
| (match_operand:SI 1 "register_operand" "a,b")))] |
| "" |
| "%|%.\\tadda%d3\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "d")]) |
| |
| (define_insn "*subshiftsi" |
| [(set (match_operand:SI 0 "register_operand" "=a,b") |
| (minus:SI (match_operand:SI 1 "register_operand" "a,b") |
| (mult:SI (match_operand:SI 2 "register_operand" "a,b") |
| (match_operand:SI 3 "suba_scale_operand" "n,n"))))] |
| "" |
| "%|%.\\tsuba%d3\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "d")]) |
| |
| (define_insn "addsidi3_widen" |
| [(set (match_operand:DI 0 "register_operand" "=a,b,a,b") |
| (plus:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a,b,a,b")) |
| (zero_extend:DI (match_operand:SI 2 "register_operand" "a,b,?b,?a"))))] |
| "" |
| "%|%.\\taddu\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_expand "adddi3" |
| [(set (match_operand:DI 0 "register_operand" "") |
| (plus:DI (match_operand:DI 1 "register_operand" "") |
| (match_operand:DI 2 "register_operand" "")))] |
| "" |
| { |
| rtx tmp; |
| rtx lo_half[3], hi_half[3]; |
| split_di (operands + 1, 2, lo_half + 1, hi_half + 1); |
| if (reg_overlap_mentioned_p (operands[0], hi_half[1]) |
| || reg_overlap_mentioned_p (operands[0], hi_half[2])) |
| tmp = gen_reg_rtx (DImode); |
| else |
| tmp = operands[0]; |
| split_di (&tmp, 1, lo_half, hi_half); |
| emit_insn (gen_addsidi3_widen (tmp, lo_half[1], lo_half[2])); |
| emit_insn (gen_addsi3 (hi_half[0], copy_rtx (hi_half[0]), hi_half[1])); |
| emit_insn (gen_addsi3 (copy_rtx (hi_half[0]), |
| copy_rtx (hi_half[0]), hi_half[2])); |
| if (tmp != operands[0]) |
| emit_move_insn (operands[0], tmp); |
| DONE; |
| }) |
| |
| (define_insn "addsf3" |
| [(set (match_operand:SF 0 "register_operand" "=a,b,a,b") |
| (plus:SF (match_operand:SF 1 "register_operand" "%a,b,a,b") |
| (match_operand:SF 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\taddsp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "fp4") |
| (set_attr "units67" "l") |
| (set_attr "units67p" "ls") |
| (set_attr "units674" "ls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "adddf3" |
| [(set (match_operand:DF 0 "register_operand" "=a,b,a,b") |
| (plus:DF (match_operand:DF 1 "register_operand" "%a,b,a,b") |
| (match_operand:DF 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tadddp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "adddp") |
| (set_attr "units67" "l") |
| (set_attr "units67p" "ls") |
| (set_attr "units674" "ls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "subsf3" |
| [(set (match_operand:SF 0 "register_operand" "=a,b, a, b, a, b") |
| (minus:SF (match_operand:SF 1 "register_operand" "a,b, b, a, a, b") |
| (match_operand:SF 2 "register_operand" "a,b,?a,?b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tsubsp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "fp4") |
| (set_attr "units67" "l") |
| (set_attr "units67p" "ls") |
| (set_attr "units674" "ls") |
| (set_attr "cross" "n,n,y,y,y,y")]) |
| |
| (define_insn "subdf3" |
| [(set (match_operand:DF 0 "register_operand" "=a,b, a, b, a, b") |
| (minus:DF (match_operand:DF 1 "register_operand" "a,b, b, a, a, b") |
| (match_operand:DF 2 "register_operand" "a,b,?a,?b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tsubdp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "adddp") |
| (set_attr "units67" "l") |
| (set_attr "units67p" "ls") |
| (set_attr "units674" "ls") |
| (set_attr "cross" "n,n,y,y,y,y")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Logical instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "andsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b") |
| (and:SI (match_operand:SI 1 "register_operand" "%a,b,b,a,a,b") |
| (match_operand:SI 2 "andsi_operand" "aIs5,bIs5,?aIs5,?bIs5,aJc,bJc")))] |
| "" |
| { |
| if (which_alternative < 4) |
| return "%|%.\\tand\\t%$\\t%2, %1, %0"; |
| else |
| return "%|%.\\tclr\\t%$\\t%1, %f2, %F2, %0"; |
| } |
| [(set_attr "units62" "ls,ls,ls,ls,s,s") |
| (set_attr "units64" "dls,dls,dls,dls,s,s") |
| (set_attr "cross" "n,n,y,y,n,n")]) |
| |
| (define_insn "iorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b") |
| (ior:SI (match_operand:SI 1 "register_operand" "%a,b,b,a,a,b") |
| (match_operand:SI 2 "iorsi_operand" "aIs5,bIs5,?aIs5,?bIs5,aJs,bJs")))] |
| "" |
| { |
| if (which_alternative < 4) |
| return "%|%.\\tor\\t%$\\t%2, %1, %0"; |
| else |
| return "%|%.\\tset\\t%$\\t%1, %s2, %S2, %0"; |
| } |
| [(set_attr "units62" "ls,ls,ls,ls,s,s") |
| (set_attr "units64" "dls,dls,dls,dls,s,s") |
| (set_attr "cross" "n,n,y,y,n,n")]) |
| |
| (define_insn "xorsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (xor:SI (match_operand:SI 1 "register_operand" "%a,b,b,a") |
| (match_operand:SI 2 "reg_or_scst5_operand" "aIs5,bIs5,?aIs5,?bIs5")))] |
| "" |
| "%|%.\\txor\\t%$\\t%2, %1, %0" |
| [(set_attr "units62" "ls") |
| (set_attr "units64" "dls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Conversions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "extendsfdf2" |
| [(set (match_operand:DF 0 "register_operand" "=a,b,a,b") |
| (float_extend:DF (match_operand:SF 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tspdp\\t%$\\t%1,%0" |
| [(set_attr "type" "dp2") |
| (set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "truncdfsf2" |
| [(set (match_operand:SF 0 "register_operand" "=a,b") |
| (float_truncate:SF (match_operand:DF 1 "register_operand" "a,b")))] |
| "TARGET_FP" |
| "%|%.\\tdpsp\\t%$\\t%1,%0" |
| [(set_attr "type" "fp4") |
| (set_attr "units" "l") |
| (set_attr "cross" "n")]) |
| |
| ;;;; Convert between signed integer types and floating point. |
| (define_insn "floatsisf2" |
| [(set (match_operand:SF 0 "register_operand" "=a,b,a,b") |
| (float:SF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tintsp\\t%$\\t%1,%0" |
| [(set_attr "type" "fp4") |
| (set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "floatunssisf2" |
| [(set (match_operand:SF 0 "register_operand" "=a,b,a,b") |
| (unsigned_float:SF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tintspu\\t%$\\t%1,%0" |
| [(set_attr "type" "fp4") |
| (set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "floatsidf2" |
| [(set (match_operand:DF 0 "register_operand" "=a,b,a,b") |
| (float:DF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tintdp\\t%$\\t%1,%0" |
| [(set_attr "type" "intdp") |
| (set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "floatunssidf2" |
| [(set (match_operand:DF 0 "register_operand" "=a,b,a,b") |
| (unsigned_float:DF (match_operand:SI 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tintdpu\\t%$\\t%1,%0" |
| [(set_attr "type" "intdp") |
| (set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "fix_truncsfsi2" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (fix:SI (match_operand:SF 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP" |
| "%|%.\\tsptrunc\\t%$\\t%1,%0" |
| [(set_attr "type" "fp4") |
| (set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "fix_truncdfsi2" |
| [(set (match_operand:SI 0 "register_operand" "=a,b") |
| (fix:SI (match_operand:DF 1 "register_operand" "a,b")))] |
| "TARGET_FP" |
| "%|%.\\tdptrunc\\t%$\\t%1,%0" |
| [(set_attr "type" "fp4") |
| (set_attr "units" "l") |
| (set_attr "cross" "n")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Saturating arithmetic |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "saddsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b,a,b,a,b") |
| (ss_plus:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a,a,b,?b,?a") |
| (match_operand:SI 2 "reg_or_const_int_operand" "a,b,a,b,aIs5,bIs5,aIs5,bIs5")))] |
| "" |
| "%|%.\\tsadd\\t%$\\t%2, %1, %0" |
| [(set_attr "units" "ls,ls,ls,ls,l,l,l,l") |
| (set_attr "cross" "n,n,y,y,n,n,y,y")]) |
| |
| (define_insn "ssubsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (ss_minus:SI (match_operand:SI 1 "reg_or_scst5_operand" "aIs5,bIs5,?bIs5,?aIs5") |
| (match_operand:SI 2 "register_operand" "a,b,a,b")))] |
| "" |
| "%|%.\\tssub\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "subcsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (unspec:SI |
| [(match_operand:SI 1 "register_operand" "a,b,a,b") |
| (match_operand:SI 2 "register_operand" "a,b,?b,?a")] |
| UNSPEC_SUBC))] |
| "" |
| "%|%.\\tsubc\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Call instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_expand "call" |
| [(match_operand 0 "" "")] |
| "" |
| { |
| c6x_expand_call (NULL_RTX, operands[0], false); |
| DONE; |
| }) |
| |
| (define_expand "call_value" |
| [(match_operand 0 "" "") |
| (match_operand 1 "" "")] |
| "" |
| { |
| c6x_expand_call (operands[0], operands[1], false); |
| DONE; |
| }) |
| |
| (define_expand "sibcall" |
| [(match_operand 0 "" "")] |
| "" |
| { |
| c6x_expand_call (NULL_RTX, operands[0], true); |
| cfun->machine->contains_sibcall = true; |
| DONE; |
| }) |
| |
| (define_expand "sibcall_value" |
| [(match_operand 0 "" "") |
| (match_operand 1 "" "")] |
| "" |
| { |
| c6x_expand_call (operands[0], operands[1], true); |
| cfun->machine->contains_sibcall = true; |
| DONE; |
| }) |
| |
| (define_insn "call_internal" |
| [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1,a,b")) |
| (const_int 0))] |
| "!SIBLING_CALL_P (insn)" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "any,b,b") |
| (set_attr "cross" "n,y,n")]) |
| |
| (define_insn "call_value_internal" |
| [(set (match_operand 0 "" "") |
| (call (mem (match_operand:SI 1 "c6x_call_operand" "S1,a,b")) |
| (const_int 0)))] |
| "" |
| "%|%.\\tcall\\t%$\\t%1" |
| [(set_attr "type" "call") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "any,b,b") |
| (set_attr "cross" "n,y,n")]) |
| |
| (define_insn "sibcall_internal" |
| [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1,C")) |
| (const_int 0))] |
| "SIBLING_CALL_P (insn)" |
| "%|%.\\tb\\t%$\\t%0" |
| [(set_attr "type" "branch") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "any,b")]) |
| |
| (define_insn "callp" |
| [(call (mem (match_operand:SI 0 "c6x_call_operand" "S1")) |
| (const_int 0)) |
| (unspec [(const_int 6)] UNSPEC_NOP)] |
| "!SIBLING_CALL_P (insn)" |
| "%|%.\\tcallp\\t%$\\t%0, B3" |
| [(set_attr "type" "callp") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "b") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "callp_value" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (call (mem (match_operand:SI 1 "c6x_call_operand" "S1")) |
| (const_int 0))) |
| (unspec [(const_int 6)] UNSPEC_NOP)] |
| "!SIBLING_CALL_P (insn)" |
| "%|%.\\tcallp\\t%$\\t%1, B3" |
| [(set_attr "type" "callp") |
| (set_attr "predicable" "no") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "b") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "return_internal" |
| [(return) |
| (use (match_operand:SI 0 "register_operand" "b"))] |
| "reload_completed" |
| "%|%.\\tret\\t%$\\t%0" |
| [(set_attr "type" "branch") |
| (set_attr "units" "s") |
| (set_attr "dest_regfile" "b")]) |
| |
| (define_insn "addkpc" |
| [(set (match_operand:SI 0 "register_operand" "=b") |
| (unspec:SI [(match_operand 1 "" "")] UNSPEC_ADDKPC)) |
| (unspec [(match_operand 2 "const_int_operand" "n")] UNSPEC_NOP)] |
| "TARGET_INSNS_64" |
| "%|%.\\taddkpc\\t%$\\t%l1, %0, %2" |
| [(set_attr "units" "s") |
| (set_attr "dest_regfile" "b")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Unary operations |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "negsi2" |
| [(set (match_operand:SI 0 "register_operand" "=a, a, b, b") |
| (neg:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))] |
| "" |
| "%|%.\\tneg\\t%$\\t%1, %0" |
| [(set_attr "units" "ls") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| (define_insn "one_cmplsi2" |
| [(set (match_operand:SI 0 "register_operand" "=a, a, b, b") |
| (not:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))] |
| "" |
| "%|%.\\tnot\\t%$\\t%1, %0" |
| [(set_attr "units" "ls") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| (define_insn "clrsbsi2" |
| [(set (match_operand:SI 0 "register_operand" "=a, a, b, b") |
| (clrsb:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))] |
| "" |
| "%|%.\\tnorm\\t%$\\t%1, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| (define_insn "clzsi2" |
| [(set (match_operand:SI 0 "register_operand" "=a, a, b, b") |
| (clz:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))] |
| "" |
| "%|%.\\tlmbd\\t%$\\t1, %1, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| ;; bitrevsi2 is defined in c6x-mult.md.in. |
| |
| (define_expand "ctzsi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (ctz:SI (match_operand:SI 1 "register_operand" "")))] |
| "TARGET_INSNS_64" |
| { |
| rtx tmpreg = gen_reg_rtx (SImode); |
| emit_insn (gen_bitrevsi2 (tmpreg, operands[1])); |
| emit_insn (gen_clzsi2 (operands[0], tmpreg)); |
| DONE; |
| }) |
| |
| (define_expand "ctzdi2" |
| [(set (match_operand:DI 0 "register_operand" "") |
| (ctz:DI (match_operand:DI 1 "register_operand" "")))] |
| "TARGET_INSNS_64" |
| { |
| rtx tmpreg = gen_reg_rtx (DImode); |
| rtx out; |
| emit_insn (gen_bitrevsi2 (gen_highpart (SImode, tmpreg), |
| gen_lowpart (SImode, operands[1]))); |
| emit_insn (gen_bitrevsi2 (gen_lowpart (SImode, tmpreg), |
| gen_highpart (SImode, operands[1]))); |
| out = expand_unop (DImode, clz_optab, tmpreg, operands[0], 1); |
| if (!rtx_equal_p (out, operands[0])) |
| emit_move_insn (operands[0], out); |
| DONE; |
| }) |
| |
| (define_insn "ssabssi2" |
| [(set (match_operand:SI 0 "register_operand" "=a, a, b, b") |
| (ss_abs:SI (match_operand:SI 1 "register_operand" "a,?b, b,?a")))] |
| "" |
| "%|%.\\tabs\\t%$\\t%1, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Shift instructions |
| ;; ------------------------------------------------------------------------- |
| |
| (define_code_iterator any_shift [ss_ashift ashift ashiftrt lshiftrt]) |
| (define_code_iterator any_rshift [ashiftrt lshiftrt]) |
| (define_code_attr shift_code [(ss_ashift "ss_ashl") (ashift "ashl") |
| (ashiftrt "ashr") (lshiftrt "lshr")]) |
| (define_code_attr shift_insn [(ss_ashift "sshl") (ashift "shl") |
| (ashiftrt "shr") (lshiftrt "shru")]) |
| |
| (define_insn "<shift_code>si3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (any_shift:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))] |
| "" |
| "%|%.\\t<shift_insn>\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; See c6x-mult.md.in for the rotlsi3 pattern. |
| |
| (define_insn "rotrdi3_16" |
| [(set (match_operand:DI 0 "register_operand" "=a,b") |
| (rotatert:DI (match_operand:DI 1 "register_operand" "a,b") |
| (const_int 16)))] |
| "TARGET_INSNS_64PLUS" |
| "%|%.\\tdpackx2\\t%$\\t%P1, %p1, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "shlmbsi3" |
| [(set (match_operand:SI 0 "register_operand" "=a,b,a,b") |
| (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "a,b,?b,?a") |
| (const_int 8)) |
| (lshiftrt:SI (match_operand:SI 2 "register_operand" "a,b,a,b") |
| (const_int 24))))] |
| "TARGET_INSNS_64" |
| "%|%.\\tshlmb\\t%$\\t%2, %1, %0" |
| [(set_attr "units" "ls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_expand "ashldi3" |
| [(set (match_operand:DI 0 "register_operand" "") |
| (ashift:DI (match_operand:DI 1 "register_operand" "") |
| (match_operand:SI 2 "const_int_operand" "")))] |
| "TARGET_INSNS_64" |
| { |
| if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 8) |
| { |
| rtx lo0, lo1, hi0, hi1, tmp; |
| lo0 = gen_lowpart (SImode, operands[0]); |
| hi0 = gen_highpart (SImode, operands[0]); |
| lo1 = gen_lowpart (SImode, operands[1]); |
| hi1 = gen_highpart (SImode, operands[1]); |
| if (reg_overlap_mentioned_p (hi0, lo1)) |
| tmp = gen_reg_rtx (SImode); |
| else |
| tmp = hi0; |
| emit_insn (gen_shlmbsi3 (tmp, hi1, lo1)); |
| emit_insn (gen_ashlsi3 (lo0, lo1, operands[2])); |
| if (tmp != hi0) |
| emit_move_insn (hi0, tmp); |
| DONE; |
| } |
| FAIL; |
| }) |
| |
| (define_expand "rotrdi3" |
| [(set (match_operand:DI 0 "register_operand" "") |
| (rotatert:DI (match_operand:DI 1 "register_operand" "") |
| (match_operand:SI 2 "const_int_operand" "")))] |
| "TARGET_INSNS_64PLUS" |
| { |
| if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 16) |
| { |
| emit_insn (gen_rotrdi3_16 (operands[0], operands[1])); |
| DONE; |
| } |
| FAIL; |
| }) |
| |
| (define_insn "bswapv2hi2" |
| [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b") |
| (bswap:V2HI (match_operand:V2HI 1 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tswap4\\t%$\\t%1, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_expand "bswapsi2" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (bswap:SI (match_operand:SI 1 "register_operand" "")))] |
| "TARGET_INSNS_64" |
| { |
| rtx tmpreg = gen_reg_rtx (SImode); |
| rtx tmpv2 = gen_lowpart (V2HImode, tmpreg); |
| rtx op0v2 = gen_lowpart (V2HImode, operands[0]); |
| emit_insn (gen_rotlsi3 (tmpreg, operands[1], GEN_INT (16))); |
| emit_insn (gen_bswapv2hi2 (op0v2, tmpv2)); |
| DONE; |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Division |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "divsi3_insn" |
| [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B5)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t__c6xabi_divi" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "divsi3_insn_indcall" |
| [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (use (match_operand:SI 0 "register_operand" "b")) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B5)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "udivsi3_insn" |
| [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t__c6xabi_divu" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "udivsi3_insn_indcall" |
| [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (use (match_operand:SI 0 "register_operand" "b")) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "modsi3_insn" |
| [(set (reg:SI REG_A4) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t__c6xabi_remi" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "modsi3_insn_indcall" |
| [(set (reg:SI REG_A4) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (use (match_operand:SI 0 "register_operand" "b")) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "divmodsi4_insn" |
| [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (set (reg:SI REG_A5) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t__c6xabi_divremi" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "divmodsi4_insn_indcall" |
| [(set (reg:SI REG_A4) (div:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (set (reg:SI REG_A5) (mod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (use (match_operand:SI 0 "register_operand" "b")) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "umodsi3_insn" |
| [(set (reg:SI REG_A4) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A7)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t__c6xabi_remu" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "umodsi3_insn_indcall" |
| [(set (reg:SI REG_A4) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (use (match_operand:SI 0 "register_operand" "b")) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A7)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "udivmodsi4_insn" |
| [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (set (reg:SI REG_A5) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t__c6xabi_divremu" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "udivmodsi4_insn_indcall" |
| [(set (reg:SI REG_A4) (udiv:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (set (reg:SI REG_A5) (umod:SI (reg:SI REG_A4) (reg:SI REG_B4))) |
| (use (match_operand:SI 0 "register_operand" "b")) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "%|%.\\tcall\\t%$\\t%0" |
| [(set_attr "type" "call") |
| (set_attr "dest_regfile" "any") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn_and_split "divmodsi4" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (div:SI (match_operand:SI 1 "register_operand" "") |
| (match_operand:SI 2 "register_operand" ""))) |
| (set (match_operand:SI 3 "register_operand" "") |
| (mod:SI (match_dup 1) (match_dup 2))) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A4)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B5)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "#" |
| "" |
| [(const_int 0)] |
| { |
| rtx reg = NULL_RTX; |
| |
| if (TARGET_LONG_CALLS) |
| { |
| if (reload_completed) |
| reg = gen_rtx_REG (SImode, REG_A6); |
| else |
| reg = gen_reg_rtx (SImode); |
| } |
| emit_move_insn (gen_rtx_REG (SImode, REG_A4), operands[1]); |
| emit_move_insn (gen_rtx_REG (SImode, REG_B4), operands[2]); |
| if (find_reg_note (curr_insn, REG_UNUSED, operands[3])) |
| { |
| if (TARGET_LONG_CALLS) |
| { |
| emit_move_insn (reg, optab_libfunc (sdiv_optab, SImode)); |
| emit_insn (gen_divsi3_insn_indcall (reg)); |
| } |
| else |
| emit_insn (gen_divsi3_insn ()); |
| emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4)); |
| } |
| else if (find_reg_note (curr_insn, REG_UNUSED, operands[0])) |
| { |
| if (TARGET_LONG_CALLS) |
| { |
| emit_move_insn (reg, optab_libfunc (smod_optab, SImode)); |
| emit_insn (gen_modsi3_insn_indcall (reg)); |
| } |
| else |
| emit_insn (gen_modsi3_insn ()); |
| emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A4)); |
| } |
| else |
| { |
| if (TARGET_LONG_CALLS) |
| { |
| emit_move_insn (reg, optab_libfunc (sdivmod_optab, SImode)); |
| emit_insn (gen_divmodsi4_insn_indcall (reg)); |
| } |
| else |
| emit_insn (gen_divmodsi4_insn ()); |
| emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4)); |
| emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A5)); |
| } |
| DONE; |
| }) |
| |
| (define_insn_and_split "udivmodsi4" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (udiv:SI (match_operand:SI 1 "register_operand" "") |
| (match_operand:SI 2 "register_operand" ""))) |
| (set (match_operand:SI 3 "register_operand" "") |
| (umod:SI (match_dup 1) (match_dup 2))) |
| (clobber (reg:SI REG_A0)) |
| (clobber (reg:SI REG_A1)) |
| (clobber (reg:SI REG_A2)) |
| (clobber (reg:SI REG_A4)) |
| (clobber (reg:SI REG_A5)) |
| (clobber (reg:SI REG_A6)) |
| (clobber (reg:SI REG_A7)) |
| (clobber (reg:SI REG_B0)) |
| (clobber (reg:SI REG_B1)) |
| (clobber (reg:SI REG_B2)) |
| (clobber (reg:SI REG_B3)) |
| (clobber (reg:SI REG_B4)) |
| (clobber (reg:SI REG_B30)) |
| (clobber (reg:SI REG_B31))] |
| "" |
| "#" |
| "" |
| [(const_int 0)] |
| { |
| rtx reg = NULL_RTX; |
| |
| if (TARGET_LONG_CALLS) |
| { |
| if (reload_completed) |
| reg = gen_rtx_REG (SImode, REG_A6); |
| else |
| reg = gen_reg_rtx (SImode); |
| } |
| |
| emit_move_insn (gen_rtx_REG (SImode, REG_A4), operands[1]); |
| emit_move_insn (gen_rtx_REG (SImode, REG_B4), operands[2]); |
| if (find_reg_note (curr_insn, REG_UNUSED, operands[3])) |
| { |
| if (TARGET_LONG_CALLS) |
| { |
| emit_move_insn (reg, optab_libfunc (udiv_optab, SImode)); |
| emit_insn (gen_udivsi3_insn_indcall (reg)); |
| } |
| else |
| emit_insn (gen_udivsi3_insn ()); |
| emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4)); |
| } |
| else if (find_reg_note (curr_insn, REG_UNUSED, operands[0])) |
| { |
| if (TARGET_LONG_CALLS) |
| { |
| emit_move_insn (reg, optab_libfunc (umod_optab, SImode)); |
| emit_insn (gen_umodsi3_insn_indcall (reg)); |
| } |
| else |
| emit_insn (gen_umodsi3_insn ()); |
| emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A4)); |
| } |
| else |
| { |
| if (TARGET_LONG_CALLS) |
| { |
| emit_move_insn (reg, optab_libfunc (udivmod_optab, SImode)); |
| emit_insn (gen_udivmodsi4_insn_indcall (reg)); |
| } |
| else |
| emit_insn (gen_udivmodsi4_insn ()); |
| emit_move_insn (operands[0], gen_rtx_REG (SImode, REG_A4)); |
| emit_move_insn (operands[3], gen_rtx_REG (SImode, REG_A5)); |
| } |
| DONE; |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Multiplication |
| ;; See c6x-mult.md.in for define_insn patterns. |
| ;; ------------------------------------------------------------------------- |
| |
| (define_expand "mulhisi3" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "")) |
| (sign_extend:SI (match_operand:HI 2 "reg_or_scst5_operand" ""))))] |
| "" |
| { |
| if (CONSTANT_P (operands[2])) |
| { |
| emit_insn (gen_mulhisi3_const (operands[0], operands[1], operands[2])); |
| DONE; |
| } |
| }) |
| |
| (define_expand "usmulhisi3" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "")) |
| (sign_extend:SI (match_operand:HI 2 "reg_or_scst5_operand" ""))))] |
| "" |
| { |
| if (CONSTANT_P (operands[2])) |
| { |
| emit_insn (gen_usmulhisi3_const (operands[0], operands[1], operands[2])); |
| DONE; |
| } |
| }) |
| |
| (define_expand "mulsi3" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (mult:SI (match_operand:SI 1 "register_operand" "") |
| (match_operand:SI 2 "register_operand" "")))] |
| "" |
| { |
| if (!TARGET_MPY32) |
| { |
| rtx lo1 = gen_lowpart (HImode, operands[1]); |
| rtx lo2 = gen_lowpart (HImode, operands[2]); |
| /* (N * AH + AL) * (N * BH + BL) |
| = N*(AH * BL + BH * AL) + AL*BL */ |
| rtx tmp1 = gen_reg_rtx (SImode); |
| rtx tmp2 = gen_reg_rtx (SImode); |
| rtx tmp3 = gen_reg_rtx (SImode); |
| emit_insn (gen_umulhisi3 (tmp1, lo1, lo2)); |
| emit_insn (gen_umulhisi3_lh (tmp2, lo1, operands[2])); |
| emit_insn (gen_umulhisi3_hl (tmp3, operands[1], lo2)); |
| emit_insn (gen_addsi3 (tmp2, tmp2, tmp3)); |
| emit_insn (gen_ashlsi3 (tmp2, tmp2, GEN_INT (16))); |
| emit_insn (gen_addsi3 (operands[0], tmp1, tmp2)); |
| DONE; |
| } |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Floating point multiplication |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "mulsf3" |
| [(set (match_operand:SF 0 "register_operand" "=a,b,a,b") |
| (mult:SF (match_operand:SF 1 "register_operand" "%a,b,?a,?b") |
| (match_operand:SF 2 "register_operand" "a,b,b,a")))] |
| "TARGET_FP" |
| "%|%.\\tmpysp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "mpy4") |
| (set_attr "units" "m") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "muldf3" |
| [(set (match_operand:DF 0 "register_operand" "=a,b") |
| (mult:DF (match_operand:DF 1 "register_operand" "%a,b") |
| (match_operand:DF 2 "register_operand" "a,b")))] |
| "TARGET_FP" |
| "%|%.\\tmpydp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "mpydp") |
| (set_attr "units" "m") |
| (set_attr "cross" "n")]) |
| |
| ;; Note that mpyspdp and mpysp2dp are available on C67x, despite what the |
| ;; manual says. |
| (define_insn "*muldf_ext1" |
| [(set (match_operand:DF 0 "register_operand" "=a,b,a,b") |
| (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "a,b,a,b")) |
| (match_operand:DF 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_FP_EXT" |
| "%|%.\\tmpyspdp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "mpyspdp") |
| (set_attr "units" "m") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "*muldf_ext2" |
| [(set (match_operand:DF 0 "register_operand" "=a,b,a,b") |
| (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "%a,b,a,b")) |
| (float_extend:DF (match_operand:SF 2 "register_operand" "a,b,?b,?a"))))] |
| "TARGET_FP_EXT" |
| "%|%.\\tmpysp2dp\\t%$\\t%1, %2, %0" |
| [(set_attr "type" "mpysp2dp") |
| (set_attr "units" "m") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Floating point division |
| ;; ------------------------------------------------------------------------- |
| |
| (define_insn "rcpsf2" |
| [(set (match_operand:SF 0 "register_operand" "=a,b,a,b") |
| (unspec:SF [(match_operand:SF 1 "register_operand" "a,b,?b,?a")] |
| UNSPEC_RCP))] |
| "TARGET_FP" |
| "%|%.\\trcpsp\\t%$\\t%1, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "rcpdf2" |
| [(set (match_operand:DF 0 "register_operand" "=a,b") |
| (unspec:DF [(match_operand:DF 1 "register_operand" "a,b")] |
| UNSPEC_RCP))] |
| "TARGET_FP" |
| "%|%.\\trcpdp\\t%$\\t%1, %0" |
| [(set_attr "type" "dp2") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_expand "divsf3" |
| [(set (match_dup 4) |
| (unspec:SF [(match_operand:SF 2 "register_operand" "")] |
| UNSPEC_RCP)) |
| (set (match_dup 5) (mult:SF (match_dup 2) (match_dup 4))) |
| (set (match_dup 6) (minus:SF (match_dup 3) (match_dup 5))) |
| (set (match_dup 4) (mult:SF (match_dup 4) (match_dup 6))) |
| (set (match_dup 5) (mult:SF (match_dup 2) (match_dup 4))) |
| (set (match_dup 6) (minus:SF (match_dup 3) (match_dup 5))) |
| (set (match_dup 4) (mult:SF (match_dup 4) (match_dup 6))) |
| (set (match_operand:SF 0 "register_operand" "") |
| (mult:SF (match_operand:SF 1 "register_operand") |
| (match_dup 4)))] |
| "TARGET_FP && flag_reciprocal_math" |
| { |
| operands[3] = force_reg (SFmode, |
| const_double_from_real_value (dconst2, SFmode)); |
| operands[4] = gen_reg_rtx (SFmode); |
| operands[5] = gen_reg_rtx (SFmode); |
| operands[6] = gen_reg_rtx (SFmode); |
| }) |
| |
| (define_expand "divdf3" |
| [(set (match_dup 4) |
| (unspec:DF [(match_operand:DF 2 "register_operand" "")] |
| UNSPEC_RCP)) |
| (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4))) |
| (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5))) |
| (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6))) |
| (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4))) |
| (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5))) |
| (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6))) |
| (set (match_dup 5) (mult:DF (match_dup 2) (match_dup 4))) |
| (set (match_dup 6) (minus:DF (match_dup 3) (match_dup 5))) |
| (set (match_dup 4) (mult:DF (match_dup 4) (match_dup 6))) |
| (set (match_operand:DF 0 "register_operand" "") |
| (mult:DF (match_operand:DF 1 "register_operand") |
| (match_dup 4)))] |
| "TARGET_FP && flag_reciprocal_math" |
| { |
| operands[3] = force_reg (DFmode, |
| const_double_from_real_value (dconst2, DFmode)); |
| operands[4] = gen_reg_rtx (DFmode); |
| operands[5] = gen_reg_rtx (DFmode); |
| operands[6] = gen_reg_rtx (DFmode); |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Block moves |
| ;; ------------------------------------------------------------------------- |
| |
| (define_expand "cpymemsi" |
| [(use (match_operand:BLK 0 "memory_operand" "")) |
| (use (match_operand:BLK 1 "memory_operand" "")) |
| (use (match_operand:SI 2 "nonmemory_operand" "")) |
| (use (match_operand:SI 3 "const_int_operand" "")) |
| (use (match_operand:SI 4 "const_int_operand" "")) |
| (use (match_operand:SI 5 "const_int_operand" ""))] |
| "" |
| { |
| if (c6x_expand_cpymem (operands[0], operands[1], operands[2], operands[3], |
| operands[4], operands[5])) |
| DONE; |
| else |
| FAIL; |
| }) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Prologue and epilogue. |
| ;; ------------------------------------------------------------------------- |
| |
| ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and |
| ;; all of memory. This blocks insns from being moved across this point. |
| |
| (define_insn "blockage" |
| [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] |
| "" |
| "" |
| [(set_attr "type" "blockage")]) |
| |
| (define_insn "push_rts" |
| [(set (mem:SI (reg:SI REG_SP)) (reg:SI REG_B14)) |
| (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -8))) (reg:DI REG_A14)) |
| (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -16))) (reg:DI REG_B12)) |
| (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -24))) (reg:DI REG_A12)) |
| (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -32))) (reg:DI REG_B10)) |
| (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -40))) (reg:DI REG_A10)) |
| (set (mem:DI (plus:SI (reg:SI REG_SP) (const_int -48))) (reg:DI REG_B2)) |
| (set (reg:SI REG_SP) (plus:SI (reg:SI REG_SP) (const_int -56))) |
| (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE) |
| (clobber (reg:SI REG_A3))] |
| "TARGET_INSNS_64PLUS" |
| "%|%.\\tcallp\\t%$\\t__c6xabi_push_rts, a3" |
| [(set_attr "type" "callp") |
| (set_attr "dest_regfile" "a") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_insn "pop_rts" |
| [(set (reg:SI REG_B14) (mem:SI (plus:SI (reg:SI REG_SP) (const_int 56)))) |
| (set (reg:DI REG_A14) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 48)))) |
| (set (reg:DI REG_B12) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 40)))) |
| (set (reg:DI REG_A12) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 32)))) |
| (set (reg:DI REG_B10) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 24)))) |
| (set (reg:DI REG_A10) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 16)))) |
| (set (reg:DI REG_B2) (mem:DI (plus:SI (reg:SI REG_SP) (const_int 8)))) |
| (set (reg:SI REG_SP) (plus:SI (reg:SI REG_SP) (const_int 56))) |
| (clobber (reg:SI REG_A3)) |
| (return)] |
| "TARGET_INSNS_64PLUS" |
| "%|%.\\tretp\\t%$\\t__c6xabi_pop_rts, a3" |
| [(set_attr "type" "callp") |
| (set_attr "dest_regfile" "a") |
| (set_attr "units" "s") |
| (set_attr "cross" "n")]) |
| |
| (define_expand "prologue" |
| [(const_int 1)] |
| "" |
| "c6x_expand_prologue (); DONE;") |
| |
| (define_expand "epilogue" |
| [(const_int 1)] |
| "" |
| "c6x_expand_epilogue (false); DONE;") |
| |
| (define_expand "sibcall_epilogue" |
| [(return)] |
| "" |
| { |
| c6x_expand_epilogue (true); |
| DONE; |
| }) |
| |
| (define_insn "setup_dsbt" |
| [(set (match_operand:SI 0 "pic_register_operand" "+Z") |
| (unspec:SI [(match_dup 0) |
| (match_operand:SI 1 "symbolic_operand" "")] |
| UNSPEC_SETUP_DSBT))] |
| "TARGET_DSBT" |
| "%|%.\\tldw\\t%$\\t*+%0($DSBT_index%1), %0" |
| [(set_attr "type" "load") |
| (set_attr "units" "d_addr") |
| (set_attr "dest_regfile" "b") |
| (set_attr "addr_regfile" "b")]) |
| |
| |
| ;; A dummy use/set to prevent prologue and epiloge overlapping. |
| ;; This can be caused by sched-ebb in the presence of multiple |
| ;; exit sequences, and causes the unwinding table generation to explode. |
| (define_insn "epilogue_barrier" |
| [(set (match_operand:SI 0 "register_operand" "") |
| (unspec:SI [(match_operand:SI 1 "register_operand" "")] |
| UNSPEC_EPILOGUE_BARRIER))] |
| "" |
| "" |
| [(set_attr "type" "blockage")]) |
| |
| ;; ------------------------------------------------------------------------- |
| ;; Vector insns |
| ;; ------------------------------------------------------------------------- |
| |
| (define_code_iterator logical [and ior xor]) |
| (define_code_attr logical_insn [(and "and") (ior "ior") (xor "xor")]) |
| (define_code_attr logical_opcode [(and "and") (ior "or") (xor "xor")]) |
| (define_code_iterator plusminus [plus minus]) |
| (define_code_attr plusminus_insn [(plus "add") (minus "sub")]) |
| (define_code_iterator ss_plusminus [ss_plus ss_minus]) |
| (define_code_attr ss_plusminus_insn [(ss_plus "add") (ss_minus "sub")]) |
| |
| ;; Vector logical insns |
| |
| (define_insn "<logical_insn><mode>3" |
| [(set (match_operand:VEC4M 0 "register_operand" "=a,b,a,b") |
| (logical:VEC4M (match_operand:VEC4M 1 "register_operand" "a,b,a,b") |
| (match_operand:VEC4M 2 "register_operand" "a,b,?b,?a")))] |
| "" |
| "%|%.\\t<logical_opcode>\\t%$\\t%1, %2, %0" |
| [(set_attr "units62" "ls") |
| (set_attr "units64" "dls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; Vector add/subtract |
| |
| (define_insn "<plusminus_insn>v2hi3" |
| [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b") |
| (plusminus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b") |
| (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))] |
| "" |
| "%|%.\\t<plusminus_insn>2\\t%$\\t%1, %2, %0" |
| [(set_attr "units62" "l") |
| (set_attr "units64" "dls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "<plusminus_insn>v4qi3" |
| [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b") |
| (plusminus:V4QI (match_operand:V4QI 1 "register_operand" "a,b,a,b") |
| (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\t<plusminus_insn>4\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "ss_addv2hi3" |
| [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b") |
| (ss_plus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b") |
| (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tsadd2\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "ss_subv2hi3" |
| [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b") |
| (ss_minus:V2HI (match_operand:V2HI 1 "register_operand" "a,b,a,b") |
| (match_operand:V2HI 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tssub2\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "us_addv4qi3" |
| [(set (match_operand:V4QI 0 "register_operand" "=a,b,a,b") |
| (ss_plus:V4QI (match_operand:V4QI 1 "register_operand" "a,b,a,b") |
| (match_operand:V4QI 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tsaddu4\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; Vector/scalar min/max |
| |
| (define_mode_iterator SMINMAX [HI V2HI]) |
| (define_mode_iterator UMINMAX [QI V4QI]) |
| |
| (define_insn "smax<mode>3" |
| [(set (match_operand:SMINMAX 0 "register_operand" "=a,b,a,b") |
| (smax:SMINMAX (match_operand:SMINMAX 1 "register_operand" "a,b,a,b") |
| (match_operand:SMINMAX 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tmax2\\t%$\\t%1, %2, %0" |
| [(set_attr "units64" "l") |
| (set_attr "units64p" "ls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "smin<mode>3" |
| [(set (match_operand:SMINMAX 0 "register_operand" "=a,b,a,b") |
| (smin:SMINMAX (match_operand:SMINMAX 1 "register_operand" "a,b,a,b") |
| (match_operand:SMINMAX 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tmin2\\t%$\\t%1, %2, %0" |
| [(set_attr "units64" "l") |
| (set_attr "units64p" "ls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "umax<mode>3" |
| [(set (match_operand:UMINMAX 0 "register_operand" "=a,b,a,b") |
| (umax:UMINMAX (match_operand:UMINMAX 1 "register_operand" "a,b,a,b") |
| (match_operand:UMINMAX 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tmaxu4\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (define_insn "umin<mode>3" |
| [(set (match_operand:UMINMAX 0 "register_operand" "=a,b,a,b") |
| (umin:UMINMAX (match_operand:UMINMAX 1 "register_operand" "a,b,a,b") |
| (match_operand:UMINMAX 2 "register_operand" "a,b,?b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tminu4\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; Vector shifts |
| |
| (define_insn "<shift_code>v2hi3" |
| [(set (match_operand:V2HI 0 "register_operand" "=a,b,a,b") |
| (any_rshift:V2HI (match_operand:V2HI 1 "register_operand" "a,b,?b,?a") |
| (match_operand:SI 2 "reg_or_ucst5_operand" "aIu5,bIu5,aIu5,bIu5")))] |
| "TARGET_INSNS_64" |
| "%|%.\\t<shift_insn>2\\t%$\\t%1, %2, %0" |
| [(set_attr "units" "s") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| ;; See c6x-mult.md.in for avg2/avgu4 |
| |
| ;; Widening vector multiply and dot product. |
| ;; See c6x-mult.md.in for the define_insn patterns |
| |
| (define_expand "sdot_prodv2hi" |
| [(match_operand:SI 0 "register_operand" "") |
| (match_operand:V2HI 1 "register_operand" "") |
| (match_operand:V2HI 2 "register_operand" "") |
| (match_operand:SI 3 "register_operand" "")] |
| "TARGET_INSNS_64" |
| { |
| rtx t = gen_reg_rtx (SImode); |
| emit_insn (gen_dotv2hi (t, operands[1], operands[2])); |
| emit_insn (gen_addsi3 (operands[0], operands[3], t)); |
| DONE; |
| }) |
| |
| ;; Unary vector operations |
| |
| (define_insn "ssabsv2hi2" |
| [(set (match_operand:V2HI 0 "register_operand" "=a, a, b, b") |
| (ss_abs:V2HI (match_operand:V2HI 1 "register_operand" "a,?b, b,?a")))] |
| "TARGET_INSNS_64" |
| "%|%.\\tabs2\\t%$\\t%1, %0" |
| [(set_attr "units" "l") |
| (set_attr "cross" "n,y,n,y")]) |
| |
| ;; Pack insns |
| |
| (define_insn "*packv2hi_insv" |
| [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+a,b,a,b,ab") |
| (const_int 16) |
| (const_int 16)) |
| (match_operand:SI 1 "nonmemory_operand" "a,b,?b,?a,n"))] |
| "TARGET_INSNS_64" |
| "@ |
| %|%.\\tpack2\\t%$\\t%1, %0, %0 |
| %|%.\\tpack2\\t%$\\t%1, %0, %0 |
| %|%.\\tpack2\\t%$\\t%1, %0, %0 |
| %|%.\\tpack2\\t%$\\t%1, %0, %0 |
| %|%.\\tmvklh\\t%$\\t%1, %0" |
| [(set_attr "units" "ls") |
| (set_attr "cross" "n,n,y,y,n")]) |
| |
| (define_insn "movstricthi" |
| [(set (strict_low_part (match_operand:HI 0 "register_operand" "+a,b,a,b")) |
| (match_operand:HI 1 "register_operand" "a,b,?b,?a"))] |
| "TARGET_INSNS_64" |
| "%|%.\\tpackhl2\\t%$\\t%0, %1, %0" |
| [(set_attr "units" "ls") |
| (set_attr "cross" "n,n,y,y")]) |
| |
| (include "c6x-mult.md") |
| (include "sync.md") |