X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=gcc%2Fconfig%2Fspu%2Fspu-builtins.md;fp=gcc%2Fconfig%2Fspu%2Fspu-builtins.md;h=8c1157a3b65d0d84670eed48d4546220e350f48a;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=0000000000000000000000000000000000000000;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/config/spu/spu-builtins.md b/gcc/config/spu/spu-builtins.md new file mode 100644 index 00000000..8c1157a3 --- /dev/null +++ b/gcc/config/spu/spu-builtins.md @@ -0,0 +1,929 @@ +;; Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +;; This file 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 of the License, or (at your option) +;; any later version. + +;; This file 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 +;; . + + +;; This includes expands for all the intrinsics. +;; spu_expand_builtin looks at the mode of match_operand. + + +;; load/store + +(define_expand "spu_lqd" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (mem:TI (and:SI (plus:SI (match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_nonmem_operand" "")) + (const_int -16))))] + "" + { + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 15) != 0) + operands[2] = GEN_INT (INTVAL (operands[2]) & -16); + if (GET_CODE (operands[2]) != CONST_INT) + { + rtx op2 = operands[2]; + operands[2] = force_reg (Pmode, operands[2]); + if (!ALIGNED_SYMBOL_REF_P (op2)) + emit_insn (gen_andsi3 (operands[2], operands[2], GEN_INT (-16))); + } + }) + +(define_expand "spu_lqx" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (mem:TI (and:SI (plus:SI (match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_reg_operand" "")) + (const_int -16))))] + "" + "") + +(define_expand "spu_lqa" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (mem:TI (and:SI (match_operand:SI 1 "immediate_operand" "") + (const_int -16))))] + "" + { + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 15) != 0) + operands[1] = GEN_INT (INTVAL (operands[1]) & -16); + }) + +(define_expand "spu_lqr" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (mem:TI (and:SI (match_operand:SI 1 "address_operand" "") + (const_int -16))))] + "" + "") + +(define_expand "spu_stqd" + [(set (mem:TI (and:SI (plus:SI (match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_nonmem_operand" "")) + (const_int -16))) + (match_operand:TI 0 "spu_reg_operand" "r,r"))] + "" + { + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 15) != 0) + operands[2] = GEN_INT (INTVAL (operands[2]) & -16); + if (GET_CODE (operands[2]) != CONST_INT) + { + rtx op2 = operands[2]; + operands[2] = force_reg (Pmode, operands[2]); + if (!ALIGNED_SYMBOL_REF_P (op2)) + emit_insn (gen_andsi3 (operands[2], operands[2], GEN_INT (-16))); + } + }) + +(define_expand "spu_stqx" + [(set (mem:TI (and:SI (plus:SI (match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_reg_operand" "")) + (const_int -16))) + (match_operand:TI 0 "spu_reg_operand" "r"))] + "" + "") + +(define_expand "spu_stqa" + [(set (mem:TI (and:SI (match_operand:SI 1 "immediate_operand" "") + (const_int -16))) + (match_operand:TI 0 "spu_reg_operand" "r"))] + "" + { + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 15) != 0) + operands[1] = GEN_INT (INTVAL (operands[1]) & -16); + }) + +(define_expand "spu_stqr" + [(set (mem:TI (and:SI (match_operand:SI 1 "address_operand" "") + (const_int -16))) + (match_operand:TI 0 "spu_reg_operand" ""))] + "" + "") + + +;; generate control word + +(define_expand "spu_cbx" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_nonmem_operand" "") + (const_int 1)] UNSPEC_CPAT))] + "" + "") + +(define_expand "spu_chx" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_nonmem_operand" "") + (const_int 2)] UNSPEC_CPAT))] + "" + "") + +(define_expand "spu_cwx" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_nonmem_operand" "") + (const_int 4)] UNSPEC_CPAT))] + "" + "") + +(define_expand "spu_cdx" + [(set (match_operand:TI 0 "spu_reg_operand" "") + (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "") + (match_operand:SI 2 "spu_nonmem_operand" "") + (const_int 8)] UNSPEC_CPAT))] + "" + "") + + + +;; Constant formation + +(define_expand "spu_ilhu" + [(set (match_operand:V4SI 0 "spu_reg_operand" "") + (const_vector:V4SI [(match_operand:SI 1 "immediate_operand" "")]))] + "" + "{ emit_insn(gen_movv4si(operands[0], spu_const(V4SImode, (INTVAL(operands[1]) << 16)))); + DONE; + }") + + +;; integer subtract +(define_expand "spu_sfh" + [(set (match_operand:V8HI 0 "spu_reg_operand" "") + (minus:V8HI (match_operand:V8HI 2 "spu_nonmem_operand" "") + (match_operand:V8HI 1 "spu_reg_operand" "")))] + "" + "") + +(define_expand "spu_sf" + [(set (match_operand:V4SI 0 "spu_reg_operand" "") + (minus:V4SI (match_operand:V4SI 2 "spu_nonmem_operand" "") + (match_operand:V4SI 1 "spu_reg_operand" "")))] + "" + "") + +(define_expand "spu_sfx" + [(set (match_operand:V4SI 0 "spu_reg_operand" "") + (unspec:V4SI [(match_operand:V4SI 2 "spu_reg_operand" "") + (match_operand:V4SI 1 "spu_reg_operand" "") + (match_operand:V4SI 3 "spu_reg_operand" "")] UNSPEC_SFX))] + "" + "") + +(define_expand "spu_bg" + [(set (match_operand:V4SI 0 "spu_reg_operand" "") + (unspec:V4SI [(match_operand:V4SI 2 "spu_reg_operand" "") + (match_operand:V4SI 1 "spu_reg_operand" "")] UNSPEC_BG))] + "" + "") + +(define_expand "spu_bgx" + [(set (match_operand:V4SI 0 "spu_reg_operand" "") + (unspec:V4SI [(match_operand:V4SI 2 "spu_reg_operand" "") + (match_operand:V4SI 1 "spu_reg_operand" "") + (match_operand:V4SI 3 "spu_reg_operand" "")] UNSPEC_BGX))] + "" + "") + +;; integer multiply +(define_insn "spu_mpy" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r,r") + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r,r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_arith_operand" "r,B") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)])))))] + "" + "@ + mpy\t%0,%1,%2 + mpyi\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpyu" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r,r") + (mult:V4SI + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r,r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)]))) + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_arith_operand" "r,B") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)])))))] + "" + "@ + mpyu\t%0,%1,%2 + mpyui\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpya" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)])))) + (match_operand:V4SI 3 "spu_reg_operand" "r")))] + "" + "mpya\t%0,%1,%2,%3" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpyh" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (ashift:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)])))) + (const_vector:V4SI [(const_int 16)(const_int 16)(const_int 16)(const_int 16)])))] + "" + "mpyh\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpys" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (ashiftrt:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)])))) + (const_vector:V4SI [(const_int 16)(const_int 16)(const_int 16)(const_int 16)])))] + "" + "mpys\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpyhhu" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (mult:V4SI + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)]))) + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)])))))] + "" + "mpyhhu\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpyhh" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)])))))] + "" + "mpyhh\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpyhhau" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (plus:V4SI + (mult:V4SI + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)]))) + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)])))) + (match_operand:V4SI 3 "spu_reg_operand" "0")))] + "" + "mpyhhau\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +(define_insn "spu_mpyhha" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)(const_int 4)(const_int 6)])))) + (match_operand:V4SI 3 "spu_reg_operand" "0")))] + "" + "mpyhha\t%0,%1,%2" + [(set_attr "type" "fp7")]) + +;; form select mask +(define_insn "spu_fsmb" + [(set (match_operand:V16QI 0 "spu_reg_operand" "=r,r") + (unspec:V16QI [(match_operand:SI 1 "spu_nonmem_operand" "r,MN")] UNSPEC_FSMB))] + "" + "@ + fsmb\t%0,%1 + fsmbi\t%0,%1" + [(set_attr "type" "shuf")]) + +(define_insn "spu_fsmh" + [(set (match_operand:V8HI 0 "spu_reg_operand" "=r") + (unspec:V8HI [(match_operand:SI 1 "spu_reg_operand" "r")] UNSPEC_FSMH))] + "" + "fsmh\t%0,%1" + [(set_attr "type" "shuf")]) + +(define_insn "spu_fsm" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec:V4SI [(match_operand:SI 1 "spu_reg_operand" "r")] UNSPEC_FSM))] + "" + "fsm\t%0,%1" + [(set_attr "type" "shuf")]) + + +;; gather bits +(define_insn "spu_gbb" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec:V4SI [(match_operand:V16QI 1 "spu_reg_operand" "r")] UNSPEC_GBB))] + "" + "gbb\t%0,%1" + [(set_attr "type" "shuf")]) + +(define_insn "spu_gbh" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec:V4SI [(match_operand:V8HI 1 "spu_reg_operand" "r")] UNSPEC_GBH))] + "" + "gbh\t%0,%1" + [(set_attr "type" "shuf")]) + +(define_insn "spu_gb" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec:V4SI [(match_operand:V4SI 1 "spu_reg_operand" "r")] UNSPEC_GB))] + "" + "gb\t%0,%1" + [(set_attr "type" "shuf")]) + +;; misc byte operations +(define_insn "spu_avgb" + [(set (match_operand:V16QI 0 "spu_reg_operand" "=r") + (unspec:V16QI [(match_operand:V16QI 1 "spu_reg_operand" "r") + (match_operand:V16QI 2 "spu_reg_operand" "r")] UNSPEC_AVGB))] + "" + "avgb\t%0,%1,%2" + [(set_attr "type" "fxb")]) + +(define_insn "spu_absdb" + [(set (match_operand:V16QI 0 "spu_reg_operand" "=r") + (unspec:V16QI [(match_operand:V16QI 1 "spu_reg_operand" "r") + (match_operand:V16QI 2 "spu_reg_operand" "r")] UNSPEC_ABSDB))] + "" + "absdb\t%0,%1,%2" + [(set_attr "type" "fxb")]) + +(define_insn "spu_sumb" + [(set (match_operand:V8HI 0 "spu_reg_operand" "=r") + (unspec:V8HI [(match_operand:V16QI 1 "spu_reg_operand" "r") + (match_operand:V16QI 2 "spu_reg_operand" "r")] UNSPEC_SUMB))] + "" + "sumb\t%0,%1,%2" + [(set_attr "type" "fxb")]) + +;; sign extend +(define_insn "spu_xsbh" + [(set (match_operand:V8HI 0 "spu_reg_operand" "=r") + (sign_extend:V8HI + (vec_select:V8QI + (match_operand:V16QI 1 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7) + (const_int 9)(const_int 11)(const_int 13)(const_int 15)]))))] + "" + "xsbh\t%0,%1") + +(define_insn "spu_xshw" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)(const_int 5)(const_int 7)]))))] + "" + "xshw\t%0,%1") + +(define_insn "spu_xswd" + [(set (match_operand:V2DI 0 "spu_reg_operand" "=r") + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "spu_reg_operand" "r") + (parallel [(const_int 1)(const_int 3)]))))] + "" + "xswd\t%0,%1") + +;; or across + +(define_insn "spu_orx" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec:V4SI [(match_operand:V4SI 1 "spu_reg_operand" "r")] UNSPEC_ORX))] + "" + "orx\t%0,%1") + + +;; compare & halt +(define_insn "spu_heq" + [(unspec_volatile [(match_operand:SI 0 "spu_reg_operand" "r,r") + (match_operand:SI 1 "spu_nonmem_operand" "r,K")] UNSPEC_HEQ)] + "" + "@ + heq\t%0,%1 + heqi\t%0,%1") + +(define_insn "spu_hgt" + [(unspec_volatile [(match_operand:SI 0 "spu_reg_operand" "r,r") + (match_operand:SI 1 "spu_nonmem_operand" "r,K")] UNSPEC_HGT)] + "" + "@ + hgt\t%0,%1 + hgti\t%0,%1") + +(define_insn "spu_hlgt" + [(unspec_volatile [(match_operand:SI 0 "spu_reg_operand" "r,r") + (match_operand:SI 1 "spu_nonmem_operand" "r,K")] UNSPEC_HLGT)] + "" + "@ + hlgt\t%0,%1 + hlgti\t%0,%1") + +;; branches + +;; The description below hides the fact that bisled conditionally +;; executes the call depending on the value in channel 0. This was +;; done so that the description would conform to the format of a call +;; insn. Otherwise (if this were not part of call insn), the link +;; register, $lr, would not be saved/restored in the prologue/epilogue. + +(define_insn "spu_bisled" + [(parallel + [(call (mem:QI (match_operand:SI 0 "spu_reg_operand" "r")) + (const_int 0)) + (clobber (reg:SI 0)) + (clobber (reg:SI 130)) + (use (match_operand:SI 1 "address_operand" "")) + (use (const_int 0))])] + "" + "bisled\t$lr,%0" + [(set_attr "type" "br")]) + +(define_insn "spu_bisledd" + [(parallel + [(call (mem:QI (match_operand:SI 0 "spu_reg_operand" "r")) + (const_int 0)) + (clobber (reg:SI 0)) + (clobber (reg:SI 130)) + (use (match_operand:SI 1 "address_operand" "")) + (use (const_int 1))])] + "" + "bisledd\t$lr,%0" + [(set_attr "type" "br")]) + +(define_insn "spu_bislede" + [(parallel + [(call (mem:QI (match_operand:SI 0 "spu_reg_operand" "r")) + (const_int 0)) + (clobber (reg:SI 0)) + (clobber (reg:SI 130)) + (use (match_operand:SI 1 "address_operand" "")) + (use (const_int 2))])] + "" + "bislede\t$lr,%0" + [(set_attr "type" "br")]) + +;; float convert +(define_expand "spu_csflt" + [(set (match_operand:V4SF 0 "spu_reg_operand") + (unspec:V4SF [(match_operand:V4SI 1 "spu_reg_operand") + (match_operand:SI 2 "spu_nonmem_operand")] 0 ))] + "" +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 127)) + { + error ("spu_convtf expects an integer literal in the range [0, 127]."); + operands[2] = force_reg (SImode, operands[2]); + } + if (GET_CODE (operands[2]) != CONST_INT) + { + rtx exp2; + rtx cnv = gen_reg_rtx (V4SFmode); + rtx scale = gen_reg_rtx (SImode); + rtx op2 = force_reg (SImode, operands[2]); + rtx m1 = spu_gen_exp2 (V4SFmode, GEN_INT (-1)); + emit_insn (gen_subsi3 (scale, const1_rtx, op2)); + exp2 = spu_gen_exp2 (V4SFmode, scale); + emit_insn (gen_floatv4siv4sf2_mul (cnv, operands[1], m1)); + emit_insn (gen_mulv4sf3 (operands[0], cnv, exp2)); + } + else + { + rtx exp2 = spu_gen_exp2 (V4SFmode, operands[2]); + emit_insn (gen_floatv4siv4sf2_div (operands[0], operands[1], exp2)); + } + DONE; +}) + +(define_expand "spu_cflts" + [(set (match_operand:V4SI 0 "spu_reg_operand") + (unspec:V4SI [(match_operand:V4SF 1 "spu_reg_operand") + (match_operand:SI 2 "spu_nonmem_operand")] 0 ))] + "" +{ + rtx exp2; + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 127)) + { + error ("spu_convts expects an integer literal in the range [0, 127]."); + operands[2] = force_reg (SImode, operands[2]); + } + exp2 = spu_gen_exp2 (V4SFmode, operands[2]); + if (GET_CODE (operands[2]) != CONST_INT) + { + rtx mul = gen_reg_rtx (V4SFmode); + emit_insn (gen_mulv4sf3 (mul, operands[1], exp2)); + emit_insn (gen_fix_truncv4sfv4si2 (operands[0], mul)); + } + else + emit_insn (gen_fix_truncv4sfv4si2_mul (operands[0], operands[1], exp2)); + DONE; +}) + +(define_expand "spu_cuflt" + [(set (match_operand:V4SF 0 "spu_reg_operand" "=r") + (unspec:V4SF [(match_operand:V4SI 1 "spu_reg_operand") + (match_operand:SI 2 "spu_nonmem_operand")] 0 ))] + "" +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 127)) + { + error ("spu_convtf expects an integer literal in the range [0, 127]."); + operands[2] = force_reg (SImode, operands[2]); + } + if (GET_CODE (operands[2]) != CONST_INT) + { + rtx exp2; + rtx cnv = gen_reg_rtx (V4SFmode); + rtx scale = gen_reg_rtx (SImode); + rtx op2 = force_reg (SImode, operands[2]); + rtx m1 = spu_gen_exp2 (V4SFmode, GEN_INT (-1)); + emit_insn (gen_subsi3 (scale, const1_rtx, op2)); + exp2 = spu_gen_exp2 (V4SFmode, scale); + emit_insn (gen_floatunsv4siv4sf2_mul (cnv, operands[1], m1)); + emit_insn (gen_mulv4sf3 (operands[0], cnv, exp2)); + } + else + { + rtx exp2 = spu_gen_exp2 (V4SFmode, operands[2]); + emit_insn (gen_floatunsv4siv4sf2_div (operands[0], operands[1], exp2)); + } + DONE; +}) + +(define_expand "spu_cfltu" + [(set (match_operand:V4SI 0 "spu_reg_operand") + (unspec:V4SI [(match_operand:V4SF 1 "spu_reg_operand") + (match_operand:SI 2 "spu_nonmem_operand")] 0 ))] + "" +{ + rtx exp2; + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 127)) + { + error ("spu_convtu expects an integer literal in the range [0, 127]."); + operands[2] = force_reg (SImode, operands[2]); + } + exp2 = spu_gen_exp2 (V4SFmode, operands[2]); + if (GET_CODE (operands[2]) != CONST_INT) + { + rtx mul = gen_reg_rtx (V4SFmode); + emit_insn (gen_mulv4sf3 (mul, operands[1], exp2)); + emit_insn (gen_fixuns_truncv4sfv4si2 (operands[0], mul)); + } + else + emit_insn (gen_fixuns_truncv4sfv4si2_mul (operands[0], operands[1], exp2)); + DONE; +}) + +(define_expand "spu_frds" + [(set (match_operand:V4SF 0 "spu_reg_operand" "") + (vec_select:V4SF + (vec_concat:V4SF + (float_truncate:V2SF (match_operand:V2DF 1 "spu_reg_operand" "")) + (match_dup:V2SF 2)) + (parallel [(const_int 0)(const_int 2)(const_int 1)(const_int 3)])))] + "" + "operands[2] = spu_const(V2SFmode, 0);") + +(define_insn "_frds" + [(set (match_operand:V4SF 0 "spu_reg_operand" "=r") + (vec_select:V4SF + (vec_concat:V4SF + (float_truncate:V2SF (match_operand:V2DF 1 "spu_reg_operand" "r")) + (match_operand:V2SF 2 "vec_imm_operand" "i")) + (parallel [(const_int 0)(const_int 2)(const_int 1)(const_int 3)])))] + "" + "frds\t%0,%1" + [(set_attr "type" "fpd")]) + +(define_insn "spu_fesd" + [(set (match_operand:V2DF 0 "spu_reg_operand" "=r") + (float_extend:V2DF + (vec_select:V2SF + (match_operand:V4SF 1 "spu_reg_operand" "r") + (parallel [(const_int 0)(const_int 2)]))))] + "" + "fesd\t%0,%1" + [(set_attr "type" "fpd")]) + +;; control +(define_insn "spu_stop" + [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "M")] UNSPEC_STOP)] + "" + "stop\t%0" + [(set_attr "type" "br")]) + +(define_insn "spu_stopd" + [(unspec_volatile [(match_operand:SI 0 "spu_reg_operand" "r") + (match_operand:SI 1 "spu_reg_operand" "r") + (match_operand:SI 2 "spu_reg_operand" "r")] UNSPEC_STOPD)] + "" + "stopd\t%0,%1,%2" + [(set_attr "type" "br")]) + +;; interrupt disable/enable +(define_expand "spu_idisable" + [(parallel + [(unspec_volatile [(const_int 0)] UNSPEC_SET_INTR) + (clobber (match_dup:SI 0)) + (clobber (mem:BLK (scratch)))])] + "" + "operands[0] = gen_reg_rtx (SImode);") + +(define_expand "spu_ienable" + [(parallel + [(unspec_volatile [(const_int 1)] UNSPEC_SET_INTR) + (clobber (match_dup:SI 0)) + (clobber (mem:BLK (scratch)))])] + "" + "operands[0] = gen_reg_rtx (SImode);") + +(define_insn "set_intr" + [(unspec_volatile [(match_operand 1 "const_int_operand" "i")] UNSPEC_SET_INTR) + (clobber (match_operand:SI 0 "spu_reg_operand" "=&r")) + (clobber (mem:BLK (scratch)))] + "! flag_pic" + "ila\t%0,.+8\;bi%I1\t%0" + [(set_attr "length" "8") + (set_attr "type" "multi0")]) + +(define_insn "set_intr_pic" + [(unspec_volatile [(match_operand 1 "const_int_operand" "i")] UNSPEC_SET_INTR) + (clobber (match_operand:SI 0 "spu_reg_operand" "=&r")) + (clobber (mem:BLK (scratch)))] + "flag_pic" + "brsl\t%0,.+4\;ai\t%0,%0,8\;bi%I1\t%0" + [(set_attr "length" "12") + (set_attr "type" "multi1")]) + +(define_insn "set_intr_cc" + [(cond_exec (match_operator 1 "branch_comparison_operator" + [(match_operand 2 "spu_reg_operand" "r") + (const_int 0)]) + (parallel [(unspec_volatile [(match_operand:SI 3 "const_int_operand" "i")] UNSPEC_SET_INTR) + (clobber (match_operand:SI 0 "spu_reg_operand" "=&r")) + (clobber (mem:BLK (scratch)))]))] + "! flag_pic" + "ila\t%0,.+8\;bi%b2%b1z%I3\t%2,%0" + [(set_attr "length" "8") + (set_attr "type" "multi0")]) + +(define_insn "set_intr_cc_pic" + [(cond_exec (match_operator 1 "branch_comparison_operator" + [(match_operand 2 "spu_reg_operand" "r") + (const_int 0)]) + (parallel [(unspec_volatile [(match_operand:SI 3 "const_int_operand" "i")] UNSPEC_SET_INTR) + (clobber (match_operand:SI 0 "spu_reg_operand" "=&r")) + (clobber (mem:BLK (scratch)))]))] + "flag_pic" + "brsl\t%0,.+4\;ai\t%0,%0,8\;bi%b2%b1z%I3\t%2,%0" + [(set_attr "length" "12") + (set_attr "type" "multi1")]) + +(define_insn "set_intr_return" + [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "i")] UNSPEC_SET_INTR) + (return)] + "" + "bi%I0\t$lr" + [(set_attr "type" "br")]) + +(define_peephole2 + [(parallel + [(unspec_volatile [(match_operand:SI 0 "const_int_operand")] UNSPEC_SET_INTR) + (clobber (match_operand:SI 1 "spu_reg_operand")) + (clobber (mem:BLK (scratch)))]) + (use (reg:SI 0)) + (return)] + "" + [(use (reg:SI 0)) + (parallel + [(unspec_volatile [(match_dup:SI 0)] UNSPEC_SET_INTR) + (return)])] + "") + +;; special purpose registers +(define_insn "spu_fscrrd" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec_volatile:V4SI [(const_int 6)] UNSPEC_FSCRRD))] + "" + "fscrrd\t%0" + [(set_attr "type" "spr")]) + +(define_insn "spu_fscrwr" + [(unspec_volatile [(match_operand:V4SI 0 "spu_reg_operand" "r")] UNSPEC_FSCRWR)] + "" + "fscrwr\t$0,%0" + [(set_attr "type" "spr")]) + +(define_insn "spu_mfspr" + [(set (match_operand:SI 0 "spu_reg_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "J")] UNSPEC_MFSPR))] + "" + "mfspr\t%0,$sp%1" + [(set_attr "type" "spr")]) + +(define_insn "spu_mtspr" + [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "J") + (match_operand:SI 1 "spu_reg_operand" "r")] UNSPEC_MTSPR)] + "" + "mtspr\t$sp%0,%1" + [(set_attr "type" "spr")]) + +;; channels +(define_expand "spu_rdch" + [(set (match_operand:V4SI 0 "spu_reg_operand" "") + (unspec_volatile:V4SI [(match_operand:SI 1 "immediate_operand" "")] UNSPEC_RDCH))] + "" + "{ + if (spu_safe_dma (INTVAL (operands[1]))) + { + emit_insn (gen_spu_rdch_clobber (operands[0], operands[1])); + DONE; + } + }") + +(define_expand "spu_rchcnt" + [(set (match_operand:SI 0 "spu_reg_operand" "") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "")] UNSPEC_RCHCNT))] + "" + "{ + if (spu_safe_dma (INTVAL (operands[1]))) + { + emit_insn (gen_spu_rchcnt_clobber (operands[0], operands[1])); + DONE; + } + }") + +(define_expand "spu_wrch" + [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "") + (match_operand:V4SI 1 "spu_reg_operand" "")] UNSPEC_WRCH)] + "" + "{ + if (spu_safe_dma (INTVAL (operands[0]))) + { + emit_insn (gen_spu_wrch_clobber (operands[0], operands[1])); + DONE; + } + }") + +(define_insn "spu_rdch_noclobber" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec_volatile:V4SI [(match_operand:SI 1 "immediate_operand" "J")] UNSPEC_RDCH))] + "" + "rdch\t%0,$ch%1" + [(set_attr "type" "spr")]) + +(define_insn "spu_rchcnt_noclobber" + [(set (match_operand:SI 0 "spu_reg_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "J")] UNSPEC_RCHCNT))] + "" + "rchcnt\t%0,$ch%1" + [(set_attr "type" "spr")]) + +(define_insn "spu_wrch_noclobber" + [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "J") + (match_operand:V4SI 1 "spu_reg_operand" "r")] UNSPEC_WRCH)] + "" + "wrch\t$ch%0,%1" + [(set_attr "type" "spr")]) + +(define_insn "spu_rdch_clobber" + [(set (match_operand:V4SI 0 "spu_reg_operand" "=r") + (unspec_volatile:V4SI [(match_operand:SI 1 "immediate_operand" "J")] UNSPEC_RDCH)) + (clobber (mem:BLK (scratch)))] + "" + "rdch\t%0,$ch%1" + [(set_attr "type" "spr")]) + +(define_insn "spu_rchcnt_clobber" + [(set (match_operand:SI 0 "spu_reg_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "J")] UNSPEC_RCHCNT)) + (clobber (mem:BLK (scratch)))] + "" + "rchcnt\t%0,$ch%1" + [(set_attr "type" "spr")]) + +(define_insn "spu_wrch_clobber" + [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "J") + (match_operand:V4SI 1 "spu_reg_operand" "r")] UNSPEC_WRCH) + (clobber (mem:BLK (scratch)))] + "" + "wrch\t$ch%0,%1" + [(set_attr "type" "spr")]) + +(define_expand "spu_splats" + [(set (match_operand 0 "spu_reg_operand" "") + (vec_duplicate (match_operand 1 "spu_nonmem_operand" "")))] + "" + { + spu_builtin_splats(operands); + DONE; + }) + +(define_expand "spu_extract" + [(set (match_operand 0 "spu_reg_operand" "") + (unspec [(match_operand 1 "spu_reg_operand" "") + (match_operand 2 "spu_nonmem_operand" "")] 0))] + "" + { + spu_builtin_extract (operands); + DONE; + }) + +(define_expand "spu_insert" + [(set (match_operand 0 "spu_reg_operand" "") + (unspec [(match_operand 1 "spu_reg_operand" "") + (match_operand 2 "spu_reg_operand" "") + (match_operand:SI 3 "spu_nonmem_operand" "")] 0))] + "" + { + spu_builtin_insert(operands); + DONE; + }) + +(define_expand "spu_promote" + [(set (match_operand 0 "spu_reg_operand" "") + (unspec [(match_operand 1 "spu_reg_operand" "") + (match_operand:SI 2 "immediate_operand" "")] 0))] + "" + { + spu_builtin_promote(operands); + DONE; + }) + +;; Currently doing nothing with this but expanding its args. +(define_expand "spu_align_hint" + [(unspec [(match_operand:SI 0 "address_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "immediate_operand" "")] 0)] + "" + { + DONE; + }) +