auto merge of #6214 : sanxiyn/rust/simd-2, r=graydon
At the moment this only includes type checking and there is no code generation support yet. I wanted to get the design reviewed first. From discussion with @graydon at #5841, re-implemented as `#[simd]` attribute on structs. Progressing towards #3499.
This commit is contained in:
commit
5a65f51d66
@ -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"]
|
||||
|
43
src/libcore/unstable/simd.rs
Normal file
43
src/libcore/unstable/simd.rs
Normal file
@ -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);
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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],
|
||||
|
13
src/test/compile-fail/simd-type.rs
Normal file
13
src/test/compile-fail/simd-type.rs
Normal file
@ -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
src/test/run-pass/simd-type.rs
Normal file
9
src/test/run-pass/simd-type.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#[simd]
|
||||
struct RGBA {
|
||||
r: f32,
|
||||
g: f32,
|
||||
b: f32,
|
||||
a: f32
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user