diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 3edb1ec48a0..0d1836e0144 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -304,7 +304,7 @@ pub enum RealPredicate { // The LLVM TypeKind type - must stay in sync with the def of // LLVMTypeKind in llvm/include/llvm-c/Core.h -#[derive(Copy, PartialEq)] +#[derive(Copy, PartialEq, Show)] #[repr(C)] pub enum TypeKind { Void = 0, diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 3072bcae0bf..037f20ee4c5 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -835,26 +835,24 @@ pub fn cast_shift_rhs(op: ast::BinOp, G: FnOnce(ValueRef, Type) -> ValueRef, { // Shifts may have any size int on the rhs - unsafe { - if ast_util::is_shift_binop(op) { - let mut rhs_llty = val_ty(rhs); - let mut lhs_llty = val_ty(lhs); - if rhs_llty.kind() == Vector { rhs_llty = rhs_llty.element_type() } - if lhs_llty.kind() == Vector { lhs_llty = lhs_llty.element_type() } - let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty.to_ref()); - let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty.to_ref()); - if lhs_sz < rhs_sz { - trunc(rhs, lhs_llty) - } else if lhs_sz > rhs_sz { - // FIXME (#1877: If shifting by negative - // values becomes not undefined then this is wrong. - zext(rhs, lhs_llty) - } else { - rhs - } + if ast_util::is_shift_binop(op) { + let mut rhs_llty = val_ty(rhs); + let mut lhs_llty = val_ty(lhs); + if rhs_llty.kind() == Vector { rhs_llty = rhs_llty.element_type() } + if lhs_llty.kind() == Vector { lhs_llty = lhs_llty.element_type() } + let rhs_sz = rhs_llty.int_width(); + let lhs_sz = lhs_llty.int_width(); + if lhs_sz < rhs_sz { + trunc(rhs, lhs_llty) + } else if lhs_sz > rhs_sz { + // FIXME (#1877: If shifting by negative + // values becomes not undefined then this is wrong. + zext(rhs, lhs_llty) } else { rhs } + } else { + rhs } } diff --git a/src/librustc_trans/trans/cabi_aarch64.rs b/src/librustc_trans/trans/cabi_aarch64.rs index 66308503b81..0d8ef9e2fc9 100644 --- a/src/librustc_trans/trans/cabi_aarch64.rs +++ b/src/librustc_trans/trans/cabi_aarch64.rs @@ -10,8 +10,7 @@ #![allow(non_upper_case_globals)] -use llvm; -use llvm::{Integer, Pointer, Float, Double, Struct, Array}; +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; use llvm::{StructRetAttribute, ZExtAttribute}; use trans::cabi::{FnType, ArgType}; use trans::context::CrateContext; @@ -30,11 +29,7 @@ fn align(off: uint, ty: Type) -> uint { fn ty_align(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 8, Float => 4, Double => 8, @@ -50,17 +45,18 @@ fn ty_align(ty: Type) -> uint { let elt = ty.element_type(); ty_align(elt) } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt) * len + } _ => panic!("ty_align: unhandled type") } } fn ty_size(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 8, Float => 4, Double => 8, @@ -80,6 +76,12 @@ fn ty_size(ty: Type) -> uint { let eltsz = ty_size(elt); len * eltsz } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } _ => panic!("ty_size: unhandled type") } } @@ -137,7 +139,8 @@ fn is_reg_ty(ty: Type) -> bool { Integer | Pointer | Float - | Double => true, + | Double + | Vector => true, _ => false } } diff --git a/src/librustc_trans/trans/cabi_arm.rs b/src/librustc_trans/trans/cabi_arm.rs index 830771d7397..7d1a8ab1452 100644 --- a/src/librustc_trans/trans/cabi_arm.rs +++ b/src/librustc_trans/trans/cabi_arm.rs @@ -10,8 +10,7 @@ #![allow(non_upper_case_globals)] -use llvm; -use llvm::{Integer, Pointer, Float, Double, Struct, Array}; +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; use llvm::{StructRetAttribute, ZExtAttribute}; use trans::cabi::{FnType, ArgType}; use trans::context::CrateContext; @@ -37,11 +36,7 @@ fn align(off: uint, ty: Type, align_fn: TyAlignFn) -> uint { fn general_ty_align(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -57,6 +52,11 @@ fn general_ty_align(ty: Type) -> uint { let elt = ty.element_type(); general_ty_align(elt) } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + general_ty_align(elt) * len + } _ => panic!("ty_align: unhandled type") } } @@ -70,11 +70,7 @@ fn general_ty_align(ty: Type) -> uint { // /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html fn ios_ty_align(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - cmp::min(4, ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8) - } - } + Integer => cmp::min(4, ((ty.int_width() as uint) + 7) / 8), Pointer => 4, Float => 4, Double => 4, @@ -90,17 +86,18 @@ fn ios_ty_align(ty: Type) -> uint { let elt = ty.element_type(); ios_ty_align(elt) } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ios_ty_align(elt) * len + } _ => panic!("ty_align: unhandled type") } } fn ty_size(ty: Type, align_fn: TyAlignFn) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -123,6 +120,12 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> uint { let eltsz = ty_size(elt, align_fn); len * eltsz } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt, align_fn); + len * eltsz + } _ => panic!("ty_size: unhandled type") } } @@ -166,7 +169,8 @@ fn is_reg_ty(ty: Type) -> bool { Integer | Pointer | Float - | Double => true, + | Double + | Vector => true, _ => false } } diff --git a/src/librustc_trans/trans/cabi_mips.rs b/src/librustc_trans/trans/cabi_mips.rs index 4dfe8daf339..776be8855cb 100644 --- a/src/librustc_trans/trans/cabi_mips.rs +++ b/src/librustc_trans/trans/cabi_mips.rs @@ -13,7 +13,7 @@ use libc::c_uint; use std::cmp; use llvm; -use llvm::{Integer, Pointer, Float, Double, Struct, Array}; +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; use llvm::{StructRetAttribute, ZExtAttribute}; use trans::cabi::{ArgType, FnType}; use trans::context::CrateContext; @@ -30,11 +30,7 @@ fn align(off: uint, ty: Type) -> uint { fn ty_align(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -50,17 +46,18 @@ fn ty_align(ty: Type) -> uint { let elt = ty.element_type(); ty_align(elt) } - _ => panic!("ty_size: unhandled type") + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt) * len + } + _ => panic!("ty_align: unhandled type") } } fn ty_size(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -80,6 +77,12 @@ fn ty_size(ty: Type) -> uint { let eltsz = ty_size(elt); len * eltsz } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } _ => panic!("ty_size: unhandled type") } } @@ -120,7 +123,8 @@ fn is_reg_ty(ty: Type) -> bool { Integer | Pointer | Float - | Double => true, + | Double + | Vector => true, _ => false }; } diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index 86190b1e566..980a70256e9 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -14,9 +14,8 @@ #![allow(non_upper_case_globals)] use self::RegClass::*; -use llvm; use llvm::{Integer, Pointer, Float, Double}; -use llvm::{Struct, Array, Attribute}; +use llvm::{Struct, Array, Attribute, Vector}; use llvm::{StructRetAttribute, ByValAttribute, ZExtAttribute}; use trans::cabi::{ArgType, FnType}; use trans::context::CrateContext; @@ -33,7 +32,8 @@ enum RegClass { SSEFv, SSEDs, SSEDv, - SSEInt, + SSEInt(/* bitwidth */ u64), + /// Data that can appear in the upper half of an SSE register. SSEUp, X87, X87Up, @@ -57,7 +57,7 @@ impl TypeMethods for Type { impl RegClass { fn is_sse(&self) -> bool { match *self { - SSEFs | SSEFv | SSEDs | SSEDv => true, + SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true, _ => false } } @@ -93,11 +93,7 @@ fn classify_ty(ty: Type) -> Vec { fn ty_align(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => ((ty.int_width() as uint) + 7) / 8, Pointer => 8, Float => 4, Double => 8, @@ -113,17 +109,18 @@ fn classify_ty(ty: Type) -> Vec { let elt = ty.element_type(); ty_align(elt) } - _ => panic!("ty_size: unhandled type") + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt) * len + } + _ => panic!("ty_align: unhandled type") } } fn ty_size(ty: Type) -> uint { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8 - } - } + Integer => (ty.int_width() as uint + 7) / 8, Pointer => 8, Float => 4, Double => 8, @@ -142,6 +139,13 @@ fn classify_ty(ty: Type) -> Vec { let eltsz = ty_size(elt); len * eltsz } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => panic!("ty_size: unhandled type") } } @@ -155,26 +159,34 @@ fn classify_ty(ty: Type) -> Vec { fn unify(cls: &mut [RegClass], i: uint, newv: RegClass) { - if cls[i] == newv { - return; - } else if cls[i] == NoClass { - cls[i] = newv; - } else if newv == NoClass { - return; - } else if cls[i] == Memory || newv == Memory { - cls[i] = Memory; - } else if cls[i] == Int || newv == Int { - cls[i] = Int; - } else if cls[i] == X87 || - cls[i] == X87Up || - cls[i] == ComplexX87 || - newv == X87 || - newv == X87Up || - newv == ComplexX87 { - cls[i] = Memory; - } else { - cls[i] = newv; - } + if cls[i] == newv { return } + + let to_write = match (cls[i], newv) { + (NoClass, _) => newv, + (_, NoClass) => return, + + (Memory, _) | + (_, Memory) => Memory, + + (Int, _) | + (_, Int) => Int, + + (X87, _) | + (X87Up, _) | + (ComplexX87, _) | + (_, X87) | + (_, X87Up) | + (_, ComplexX87) => Memory, + + (SSEFv, SSEUp) | + (SSEFs, SSEUp) | + (SSEDv, SSEUp) | + (SSEDs, SSEUp) | + (SSEInt(_), SSEUp) => return, + + (_, _) => newv + }; + cls[i] = to_write; } fn classify_struct(tys: &[Type], @@ -237,6 +249,27 @@ fn classify_ty(ty: Type) -> Vec { i += 1u; } } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + let mut reg = match elt.kind() { + Integer => SSEInt(elt.int_width()), + Float => SSEFv, + Double => SSEDv, + _ => panic!("classify: unhandled vector element type") + }; + + let mut i = 0u; + while i < len { + unify(cls, ix + (off + i * eltsz) / 8, reg); + + // everything after the first one is the upper + // half of a register. + reg = SSEUp; + i += 1u; + } + } _ => panic!("classify: unhandled type") } } @@ -245,7 +278,7 @@ fn classify_ty(ty: Type) -> Vec { let mut i = 0u; let ty_kind = ty.kind(); let e = cls.len(); - if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) { + if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) { if cls[i].is_sse() { i += 1u; while i < e { @@ -317,9 +350,19 @@ fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type { Int => { tys.push(Type::i64(ccx)); } - SSEFv => { + SSEFv | SSEDv | SSEInt(_) => { + let (elts_per_word, elt_ty) = match cls[i] { + SSEFv => (2, Type::f32(ccx)), + SSEDv => (1, Type::f64(ccx)), + SSEInt(bits) => { + assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64, + "llreg_ty: unsupported SSEInt width {}", bits); + (64 / bits, Type::ix(ccx, bits)) + } + _ => unreachable!(), + }; let vec_len = llvec_len(&cls[(i + 1u)..]); - let vec_ty = Type::vector(&Type::f32(ccx), (vec_len * 2u) as u64); + let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word); tys.push(vec_ty); i += vec_len; continue; @@ -334,7 +377,12 @@ fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type { } i += 1u; } - return Type::struct_(ccx, tys.as_slice(), false); + if tys.len() == 1 && tys[0].kind() == Vector { + // if the type contains only a vector, pass it as that vector. + tys[0] + } else { + Type::struct_(ccx, tys.as_slice(), false) + } } pub fn compute_abi_info(ccx: &CrateContext, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7abd59ca0cd..11d1c7e6796 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1905,18 +1905,16 @@ fn int_cast(bcx: Block, signed: bool) -> ValueRef { let _icx = push_ctxt("int_cast"); - unsafe { - let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref()); - let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref()); - return if dstsz == srcsz { - BitCast(bcx, llsrc, lldsttype) - } else if srcsz > dstsz { - TruncOrBitCast(bcx, llsrc, lldsttype) - } else if signed { - SExtOrBitCast(bcx, llsrc, lldsttype) - } else { - ZExtOrBitCast(bcx, llsrc, lldsttype) - }; + let srcsz = llsrctype.int_width(); + let dstsz = lldsttype.int_width(); + return if dstsz == srcsz { + BitCast(bcx, llsrc, lldsttype) + } else if srcsz > dstsz { + TruncOrBitCast(bcx, llsrc, lldsttype) + } else if signed { + SExtOrBitCast(bcx, llsrc, lldsttype) + } else { + ZExtOrBitCast(bcx, llsrc, lldsttype) } } diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index fb61bab6ade..abb961d87de 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -36,6 +36,7 @@ use syntax::parse::token::{InternedString, special_idents}; use syntax::parse::token; use syntax::{ast}; use syntax::{attr, ast_map}; +use syntax::print::pprust; use util::ppaux::Repr; /////////////////////////////////////////////////////////////////////////// @@ -426,16 +427,47 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return bcx; } +// feature gate SIMD types in FFI, since I (huonw) am not sure the +// ABIs are handled at all correctly. +fn gate_simd_ffi(tcx: &ty::ctxt, decl: &ast::FnDecl, ty: &ty::BareFnTy) { + if !tcx.sess.features.borrow().simd_ffi { + let check = |&: ast_ty: &ast::Ty, ty: ty::Ty| { + if ty::type_is_simd(tcx, ty) { + tcx.sess.span_err(ast_ty.span, + &format!("use of SIMD type `{}` in FFI is highly experimental and \ + may result in invalid code", + pprust::ty_to_string(ast_ty))[]); + tcx.sess.span_help(ast_ty.span, + "add #![feature(simd_ffi)] to the crate attributes to enable"); + } + }; + let sig = &ty.sig.0; + for (input, ty) in decl.inputs.iter().zip(sig.inputs.iter()) { + check(&*input.ty, *ty) + } + match decl.output { + ast::NoReturn(_) => {} + ast::Return(ref ty) => check(&**ty, sig.output.unwrap()) + } + } +} + pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { let _icx = push_ctxt("foreign::trans_foreign_mod"); for foreign_item in foreign_mod.items.iter() { let lname = link_name(&**foreign_item); - if let ast::ForeignItemFn(..) = foreign_item.node { + if let ast::ForeignItemFn(ref decl, _) = foreign_item.node { match foreign_mod.abi { Rust | RustIntrinsic => {} abi => { let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id); + match ty.sty { + ty::ty_bare_fn(_, bft) => gate_simd_ffi(ccx.tcx(), &**decl, bft), + _ => ccx.tcx().sess.span_bug(foreign_item.span, + "foreign fn's sty isn't a bare_fn_ty?") + } + register_foreign_item_fn(ccx, abi, ty, &lname.get()[]); // Unlike for other items, we shouldn't call diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 9cae142c03a..0124ab72f6b 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -284,6 +284,13 @@ impl Type { } } + /// Return the number of elements in `self` if it is a LLVM vector type. + pub fn vector_length(&self) -> uint { + unsafe { + llvm::LLVMGetVectorSize(self.to_ref()) as uint + } + } + pub fn array_length(&self) -> uint { unsafe { llvm::LLVMGetArrayLength(self.to_ref()) as uint @@ -326,6 +333,13 @@ impl Type { _ => panic!("llvm_float_width called on a non-float type") } } + + /// Retrieve the bit width of the integer type `self`. + pub fn int_width(&self) -> u64 { + unsafe { + llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64 + } + } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8929bbe0232..9231d4ad659 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -72,6 +72,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("slicing_syntax", Active), ("box_syntax", Active), ("on_unimplemented", Active), + ("simd_ffi", Active), ("if_let", Accepted), ("while_let", Accepted), @@ -128,6 +129,7 @@ pub struct Features { pub visible_private_types: bool, pub quote: bool, pub old_orphan_check: bool, + pub simd_ffi: bool, } impl Features { @@ -139,6 +141,7 @@ impl Features { visible_private_types: false, quote: false, old_orphan_check: false, + simd_ffi: false, } } } @@ -524,6 +527,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C visible_private_types: cx.has_feature("visible_private_types"), quote: cx.has_feature("quote"), old_orphan_check: cx.has_feature("old_orphan_check"), + simd_ffi: cx.has_feature("simd_ffi"), }, unknown_features) } diff --git a/src/test/compile-fail/feature-gate-simd-ffi.rs b/src/test/compile-fail/feature-gate-simd-ffi.rs new file mode 100644 index 00000000000..409c85b7198 --- /dev/null +++ b/src/test/compile-fail/feature-gate-simd-ffi.rs @@ -0,0 +1,26 @@ +// Copyright 2015 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. + +#![feature(simd)] +#![allow(dead_code)] + +use std::simd::f32x4; + +#[simd] #[derive(Copy)] #[repr(C)] struct LocalSimd(u8, u8); + +extern { + fn foo() -> f32x4; //~ ERROR use of SIMD type + fn bar(x: f32x4); //~ ERROR use of SIMD type + + fn baz() -> LocalSimd; //~ ERROR use of SIMD type + fn qux(x: LocalSimd); //~ ERROR use of SIMD type +} + +fn main() {} diff --git a/src/test/run-make/simd-ffi/Makefile b/src/test/run-make/simd-ffi/Makefile new file mode 100644 index 00000000000..68a6a5fbfe8 --- /dev/null +++ b/src/test/run-make/simd-ffi/Makefile @@ -0,0 +1,33 @@ +-include ../tools.mk + +# construct a fairly exhaustive list of platforms that we +# support. These ones don't follow a pattern +TARGETS=arm-linux-androideabi arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabi + +# these ones do, each OS lists the architectures it supports +LINUX=aarch64 i686 x86_64 mips mipsel +WINDOWS=i686 x86_64 +# fails with: failed to get iphonesimulator SDK path: no such file or directory +#IOS=i386 aarch64 armv7 +DARWIN=i686 x86_64 + +$(foreach arch,$(LINUX),$(eval TARGETS += $(arch)-unknown-linux-gnu)) +$(foreach arch,$(WINDOWS),$(eval TARGETS += $(arch)-pc-windows-gnu)) +#$(foreach arch,$(IOS),$(eval TARGETS += $(arch)-apple-ios)) +$(foreach arch,$(DARWIN),$(eval TARGETS += $(arch)-apple-darwin)) + +all: $(TARGETS) + +define MK_TARGETS +# compile the rust file to the given target, but only to asm and IR +# form, to avoid having to have an appropriate linker. +# +# we need some features because the integer SIMD instructions are not +# enabled by-default for i686 and ARM; these features will be invalid +# on some platforms, but LLVM just prints a warning so that's fine for +# now. +$(1): simd.rs + $$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs -C target-feature='+neon,+sse2' +endef + +$(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx)))) diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs new file mode 100755 index 00000000000..76079ddb8bd --- /dev/null +++ b/src/test/run-make/simd-ffi/simd.rs @@ -0,0 +1,81 @@ +// Copyright 2015 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. + +// ensures that public symbols are not removed completely +#![crate_type = "lib"] +// we can compile to a variety of platforms, because we don't need +// cross-compiled standard libraries. +#![no_std] + +#![feature(simd, simd_ffi, link_llvm_intrinsics, lang_items)] + + +#[repr(C)] +#[derive(Copy)] +#[simd] +pub struct f32x4(f32, f32, f32, f32); + + +extern { + #[link_name = "llvm.sqrt.v4f32"] + fn vsqrt(x: f32x4) -> f32x4; +} + +pub fn foo(x: f32x4) -> f32x4 { + unsafe {vsqrt(x)} +} + +#[repr(C)] +#[derive(Copy)] +#[simd] +pub struct i32x4(i32, i32, i32, i32); + + +extern { + // _mm_sll_epi32 + #[cfg(any(target_arch = "x86", + target_arch = "x86-64"))] + #[link_name = "llvm.x86.sse2.psll.d"] + fn integer(a: i32x4, b: i32x4) -> i32x4; + + // vmaxq_s32 + #[cfg(any(target_arch = "arm"))] + #[link_name = "llvm.arm.neon.vmaxs.v4i32"] + fn integer(a: i32x4, b: i32x4) -> i32x4; + // vmaxq_s32 + #[cfg(any(target_arch = "aarch64"))] + #[link_name = "llvm.aarch64.neon.maxs.v4i32"] + fn integer(a: i32x4, b: i32x4) -> i32x4; + + // just some substitute foreign symbol, not an LLVM intrinsic; so + // we still get type checking, but not as detailed as (ab)using + // LLVM. + #[cfg(not(any(target_arch = "x86", + target_arch = "x86-64", + target_arch = "arm", + target_arch = "aarch64")))] + fn integer(a: i32x4, b: i32x4) -> i32x4; +} + +pub fn bar(a: i32x4, b: i32x4) -> i32x4 { + unsafe {integer(a, b)} +} + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +mod std { + pub mod marker { + pub use Copy; + } +}