about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/unstable.rs2
-rw-r--r--src/libcore/unstable/simd.rs43
-rw-r--r--src/librustc/middle/trans/build.rs20
-rw-r--r--src/librustc/middle/trans/common.rs6
-rw-r--r--src/librustc/middle/trans/type_of.rs43
-rw-r--r--src/librustc/middle/ty.rs44
-rw-r--r--src/librustc/middle/typeck/check/mod.rs37
-rw-r--r--src/test/compile-fail/simd-type.rs13
-rw-r--r--src/test/run-pass/simd-type.rs9
9 files changed, 193 insertions, 24 deletions
diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs
index 4a69de26f6b..0b96e649178 100644
--- a/src/libcore/unstable.rs
+++ b/src/libcore/unstable.rs
@@ -30,6 +30,8 @@ pub mod weak_task;
 pub mod exchange_alloc;
 #[path = "unstable/intrinsics.rs"]
 pub mod intrinsics;
+#[path = "unstable/simd.rs"]
+pub mod simd;
 #[path = "unstable/extfmt.rs"]
 pub mod extfmt;
 #[path = "unstable/lang.rs"]
diff --git a/src/libcore/unstable/simd.rs b/src/libcore/unstable/simd.rs
new file mode 100644
index 00000000000..a05f6e8af5a
--- /dev/null
+++ b/src/libcore/unstable/simd.rs
@@ -0,0 +1,43 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! SIMD vectors
+
+#[allow(non_camel_case_types)];
+
+#[simd]
+pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
+
+#[simd]
+pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
+
+#[simd]
+pub struct i32x4(i32, i32, i32, i32);
+
+#[simd]
+pub struct i64x2(i64, i64);
+
+#[simd]
+pub struct u8x16(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
+
+#[simd]
+pub struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16);
+
+#[simd]
+pub struct u32x4(u32, u32, u32, u32);
+
+#[simd]
+pub struct u64x2(u64, u64);
+
+#[simd]
+pub struct f32x4(f32, f32, f32, f32);
+
+#[simd]
+pub struct f64x2(f64, f64);
diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index c3dc4f1e8eb..29fd90edce8 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -963,20 +963,28 @@ pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) ->
 }
 
 pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef,
-                 Index: ValueRef) {
+                     Index: ValueRef) -> ValueRef {
     unsafe {
-        if cx.unreachable { return; }
+        if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); }
         count_insn(cx, "insertelement");
-        llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname());
+        llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname())
     }
 }
 
 pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef,
-                     Mask: ValueRef) {
+                     Mask: ValueRef) -> ValueRef {
     unsafe {
-        if cx.unreachable { return; }
+        if cx.unreachable { return llvm::LLVMGetUndef(T_nil()); }
         count_insn(cx, "shufflevector");
-        llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname());
+        llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname())
+    }
+}
+
+pub fn VectorSplat(cx: block, NumElts: uint, EltVal: ValueRef) -> ValueRef {
+    unsafe {
+        let Undef = llvm::LLVMGetUndef(T_vector(val_ty(EltVal), NumElts));
+        let VecVal = InsertElement(cx, Undef, EltVal, C_i32(0));
+        ShuffleVector(cx, VecVal, Undef, C_null(T_vector(T_i32(), NumElts)))
     }
 }
 
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 442b5d25c8b..b004ba9d41f 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -984,6 +984,12 @@ pub fn T_array(t: TypeRef, n: uint) -> TypeRef {
     }
 }
 
+pub fn T_vector(t: TypeRef, n: uint) -> TypeRef {
+    unsafe {
+        return llvm::LLVMVectorType(t, n as c_uint);
+    }
+}
+
 // Interior vector.
 pub fn T_vec2(targ_cfg: @session::config, t: TypeRef) -> TypeRef {
     return T_struct(~[T_int(targ_cfg), // fill
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index fc27c11c06f..b8e0b58f866 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -155,9 +155,15 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
         }
 
         ty::ty_struct(did, _) => {
-            let repr = adt::represent_type(cx, t);
-            let packed = ty::lookup_packed(cx.tcx, did);
-            T_struct(adt::sizing_fields_of(cx, repr), packed)
+            if ty::type_is_simd(cx.tcx, t) {
+                let et = ty::simd_type(cx.tcx, t);
+                let n = ty::simd_size(cx.tcx, t);
+                T_vector(type_of(cx, et), n)
+            } else {
+                let repr = adt::represent_type(cx, t);
+                let packed = ty::lookup_packed(cx.tcx, did);
+                T_struct(adt::sizing_fields_of(cx, repr), packed)
+            }
         }
 
         ty::ty_self(_) | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => {
@@ -263,14 +269,19 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
       }
       ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx),
       ty::ty_struct(did, ref substs) => {
-        // Only create the named struct, but don't fill it in. We fill it
-        // in *after* placing it into the type cache. This prevents
-        // infinite recursion with recursive struct types.
-
-        common::T_named_struct(llvm_type_name(cx,
-                                              a_struct,
-                                              did,
-                                              /*bad*/ copy substs.tps))
+        if ty::type_is_simd(cx.tcx, t) {
+          let et = ty::simd_type(cx.tcx, t);
+          let n = ty::simd_size(cx.tcx, t);
+          T_vector(type_of(cx, et), n)
+        } else {
+          // Only create the named struct, but don't fill it in. We fill it
+          // in *after* placing it into the type cache. This prevents
+          // infinite recursion with recursive struct types.
+          T_named_struct(llvm_type_name(cx,
+                                        a_struct,
+                                        did,
+                                        /*bad*/ copy substs.tps))
+        }
       }
       ty::ty_self(*) => cx.tcx.sess.unimpl(~"type_of: ty_self"),
       ty::ty_infer(*) => cx.tcx.sess.bug(~"type_of with ty_infer"),
@@ -289,10 +300,12 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef {
       }
 
       ty::ty_struct(did, _) => {
-        let repr = adt::represent_type(cx, t);
-        let packed = ty::lookup_packed(cx.tcx, did);
-        common::set_struct_body(llty, adt::fields_of(cx, repr),
-                                packed);
+        if !ty::type_is_simd(cx.tcx, t) {
+          let repr = adt::represent_type(cx, t);
+          let packed = ty::lookup_packed(cx.tcx, did);
+          common::set_struct_body(llty, adt::fields_of(cx, repr),
+                                  packed);
+        }
       }
       _ => ()
     }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index b6e024b011e..a49768075dc 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1567,6 +1567,13 @@ pub fn type_is_sequence(ty: t) -> bool {
     }
 }
 
+pub fn type_is_simd(cx: ctxt, ty: t) -> bool {
+    match get(ty).sty {
+        ty_struct(did, _) => lookup_simd(cx, did),
+        _ => false
+    }
+}
+
 pub fn type_is_str(ty: t) -> bool {
     match get(ty).sty {
       ty_estr(_) => true,
@@ -1583,6 +1590,26 @@ pub fn sequence_element_type(cx: ctxt, ty: t) -> t {
     }
 }
 
+pub fn simd_type(cx: ctxt, ty: t) -> t {
+    match get(ty).sty {
+        ty_struct(did, ref substs) => {
+            let fields = lookup_struct_fields(cx, did);
+            lookup_field_type(cx, did, fields[0].id, substs)
+        }
+        _ => fail!(~"simd_type called on invalid type")
+    }
+}
+
+pub fn simd_size(cx: ctxt, ty: t) -> uint {
+    match get(ty).sty {
+        ty_struct(did, _) => {
+            let fields = lookup_struct_fields(cx, did);
+            fields.len()
+        }
+        _ => fail!(~"simd_size called on invalid type")
+    }
+}
+
 pub fn get_element_type(ty: t, i: uint) -> t {
     match get(ty).sty {
       ty_tup(ref ts) => return ts[i],
@@ -2381,6 +2408,14 @@ pub fn type_is_signed(ty: t) -> bool {
     }
 }
 
+pub fn type_is_machine(ty: t) -> bool {
+    match get(ty).sty {
+        ty_int(ast::ty_i) | ty_uint(ast::ty_u) | ty_float(ast::ty_f) => false,
+        ty_int(*) | ty_uint(*) | ty_float(*) => true,
+        _ => false
+    }
+}
+
 // Whether a type is Plain Old Data -- meaning it does not contain pointers
 // that the cycle collector might care about.
 pub fn type_is_pod(cx: ctxt, ty: t) -> bool {
@@ -3896,7 +3931,7 @@ pub fn has_attr(tcx: ctxt, did: def_id, attr: &str) -> bool {
                     attrs: ref attrs,
                     _
                 }, _)) => attr::attrs_contains_name(*attrs, attr),
-            _ => tcx.sess.bug(fmt!("lookup_packed: %? is not an item",
+            _ => tcx.sess.bug(fmt!("has_attr: %? is not an item",
                                    did))
         }
     } else {
@@ -3908,11 +3943,16 @@ pub fn has_attr(tcx: ctxt, did: def_id, attr: &str) -> bool {
     }
 }
 
-/// Determine whether an item is annotated with `#[packed]` or not
+/// Determine whether an item is annotated with `#[packed]`
 pub fn lookup_packed(tcx: ctxt, did: def_id) -> bool {
     has_attr(tcx, did, "packed")
 }
 
+/// Determine whether an item is annotated with `#[simd]`
+pub fn lookup_simd(tcx: ctxt, did: def_id) -> bool {
+    has_attr(tcx, did, "simd")
+}
+
 // Look up a field ID, whether or not it's local
 // Takes a list of type substs in case the struct is generic
 pub fn lookup_field_type(tcx: ctxt,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 68700d62187..6cd10b5bd6f 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -561,8 +561,14 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt,
 }
 
 pub fn check_struct(ccx: @mut CrateCtxt, id: ast::node_id, span: span) {
+    let tcx = ccx.tcx;
+
     // Check that the class is instantiable
-    check_instantiable(ccx.tcx, span, id);
+    check_instantiable(tcx, span, id);
+
+    if ty::lookup_simd(tcx, local_def(id)) {
+        check_simd(tcx, span, id);
+    }
 }
 
 pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
@@ -3034,6 +3040,35 @@ pub fn check_instantiable(tcx: ty::ctxt,
     }
 }
 
+pub fn check_simd(tcx: ty::ctxt, sp: span, id: ast::node_id) {
+    let t = ty::node_id_to_type(tcx, id);
+    if ty::type_needs_subst(t) {
+        tcx.sess.span_err(sp, "SIMD vector cannot be generic");
+        return;
+    }
+    match ty::get(t).sty {
+        ty::ty_struct(did, ref substs) => {
+            let fields = ty::lookup_struct_fields(tcx, did);
+            if fields.is_empty() {
+                tcx.sess.span_err(sp, "SIMD vector cannot be empty");
+                return;
+            }
+            let e = ty::lookup_field_type(tcx, did, fields[0].id, substs);
+            if !vec::all(fields,
+                         |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
+                tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
+                return;
+            }
+            if !ty::type_is_machine(e) {
+                tcx.sess.span_err(sp, "SIMD vector element type should be \
+                                       machine type");
+                return;
+            }
+        }
+        _ => ()
+    }
+}
+
 pub fn check_enum_variants(ccx: @mut CrateCtxt,
                            sp: span,
                            vs: &[ast::variant],
diff --git a/src/test/compile-fail/simd-type.rs b/src/test/compile-fail/simd-type.rs
new file mode 100644
index 00000000000..8387b2bc723
--- /dev/null
+++ b/src/test/compile-fail/simd-type.rs
@@ -0,0 +1,13 @@
+#[simd]
+struct vec4<T>(T, T, T, T); //~ ERROR SIMD vector cannot be generic
+
+#[simd]
+struct empty; //~ ERROR SIMD vector cannot be empty
+
+#[simd]
+struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous
+
+#[simd]
+struct int4(int, int, int, int); //~ ERROR SIMD vector element type should be machine type
+
+fn main() {}
diff --git a/src/test/run-pass/simd-type.rs b/src/test/run-pass/simd-type.rs
new file mode 100644
index 00000000000..c3bcc9d0b7a
--- /dev/null
+++ b/src/test/run-pass/simd-type.rs
@@ -0,0 +1,9 @@
+#[simd]
+struct RGBA {
+    r: f32,
+    g: f32,
+    b: f32,
+    a: f32
+}
+
+fn main() {}