aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/spu/spu-builtins.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/spu/spu-builtins.md')
-rw-r--r--gcc-4.9/gcc/config/spu/spu-builtins.md864
1 files changed, 864 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/spu/spu-builtins.md b/gcc-4.9/gcc/config/spu/spu-builtins.md
new file mode 100644
index 000000000..5df6fe039
--- /dev/null
+++ b/gcc-4.9/gcc/config/spu/spu-builtins.md
@@ -0,0 +1,864 @@
+;; Copyright (C) 2006-2014 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
+;; <http://www.gnu.org/licenses/>.
+
+
+;; 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))]
+ ""
+ "")
+
+(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_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;
+ })
+