auto merge of #21233 : huonw/rust/simd-size, r=Aatch
This stops the compiler ICEing on the use of SIMD types in FFI signatures. It emits correct code for LLVM intrinsics, but I am quite unsure about the ABI handling in general so I've added a new feature gate `simd_ffi` to try to ensure people don't use it without realising there's a non-trivial risk of codegen brokenness. Closes #20043.
This commit is contained in:
commit
89c4e3792d
@ -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,
|
||||
|
@ -835,26 +835,24 @@ pub fn cast_shift_rhs<F, G>(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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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<RegClass> {
|
||||
|
||||
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<RegClass> {
|
||||
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<RegClass> {
|
||||
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<RegClass> {
|
||||
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<RegClass> {
|
||||
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<RegClass> {
|
||||
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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<F>(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)
|
||||
}
|
||||
|
26
src/test/compile-fail/feature-gate-simd-ffi.rs
Normal file
26
src/test/compile-fail/feature-gate-simd-ffi.rs
Normal file
@ -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 <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.
|
||||
|
||||
#![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() {}
|
33
src/test/run-make/simd-ffi/Makefile
Normal file
33
src/test/run-make/simd-ffi/Makefile
Normal file
@ -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))))
|
81
src/test/run-make/simd-ffi/simd.rs
Executable file
81
src/test/run-make/simd-ffi/simd.rs
Executable file
@ -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 <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.
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user