]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/spu/spu-builtins.md
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / spu / spu-builtins.md
diff --git a/gcc/config/spu/spu-builtins.md b/gcc/config/spu/spu-builtins.md
new file mode 100644 (file)
index 0000000..8c1157a
--- /dev/null
@@ -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
+;; <http://www.gnu.org/licenses/>.
+
+
+;; This includes expands for all the intrinsics.
+;; spu_expand_builtin looks at the mode of match_operand.
+
+\f
+;; 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" ""))]
+  ""
+  "")
+
+\f
+;; 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))]
+  ""
+  "")
+
+
+\f
+;; 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;
+   }")
+
+\f
+;; 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;
+  })
+