diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs index 4a69de26f6b13..0b96e649178a1 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 0000000000000..a05f6e8af5a64 --- /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 or the MIT license +// , 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 c3dc4f1e8eb2b..29fd90edce898 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 442b5d25c8ba2..b004ba9d41f34 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 fc27c11c06f24..b8e0b58f86634 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 b6e024b011e25..a49768075dcc9 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 68700d6218769..6cd10b5bd6f1b 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 0000000000000..8387b2bc723fa --- /dev/null +++ b/src/test/compile-fail/simd-type.rs @@ -0,0 +1,13 @@ +#[simd] +struct vec4(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 0000000000000..c3bcc9d0b7a02 --- /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() {}