Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIMD for Rust, take 2 #6214

Merged
merged 7 commits into from
May 8, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/libcore/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
43 changes: 43 additions & 0 deletions src/libcore/unstable/simd.rs
Original file line number Diff line number Diff line change
@@ -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);
20 changes: 14 additions & 6 deletions src/librustc/middle/trans/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 28 additions & 15 deletions src/librustc/middle/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(*) => {
Expand Down Expand Up @@ -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"),
Expand All @@ -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);
}
}
_ => ()
}
Expand Down
44 changes: 42 additions & 2 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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],
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
37 changes: 36 additions & 1 deletion src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -3047,6 +3053,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],
Expand Down
13 changes: 13 additions & 0 deletions src/test/compile-fail/simd-type.rs
Original file line number Diff line number Diff line change
@@ -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() {}
9 changes: 9 additions & 0 deletions src/test/run-pass/simd-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[simd]
struct RGBA {
r: f32,
g: f32,
b: f32,
a: f32
}

fn main() {}